@[TOC](vue2 插值语法中使用可选链运算符(.?)compile异常排查思路)
前言
最近接到组内前端求助,在使用v-for进行动态渲染的时候项目突然不能正常编译了,报错提示SyntaxError: Unexpected token ...
十分奇怪
代码可参考如下:
<h3>动态渲染内容</h3>
<el-row v-for="(item, index) in form.subObjList" :key="index" :gutter="12" :style="{ background: '#edfced' }">
<el-col> {{item?.projectNameLabel}}:{{item?.projectName}}</el-col>
<el-col> {{item?.technicalPointLabel}}:{{item?.technicalPoint}}</el-col>
<el-col> {{item?.mainFunctionLabel}}:主要功能:{{item?.mainFunction}}</el-col>
<el-col> {{item?.difficultyLabel}}:{{item?.difficulty}}</el-col>
<el-col><hr></el-col>
</el-row>
待渲染的数据
this.form.subObjList = [
{ projectNameLabel: '项目名称',
projectName: 'xx项目前端',
technicalPointLabel: '技术点',
technicalPoint: 'vue vuex vue-router js',
mainFunctionLabel: '主要功能',
mainFunction: '前端交互ux整改,完善用户体验',
difficultyLabel: '难点',
difficulty: '大批量数据渲染'
},
{ projectNameLabel: '项目名称',
projectName: 'xx项目后端',
technicalPointLabel: '技术点',
technicalPoint: 'springboot mybatis redis pgsql',
mainFunctionLabel: '主要功能',
mainFunction: '支持用户的特定业务流程',
difficultyLabel: '难点',
difficulty: '大批量数据校验'
}
]
排查思路
把新增的代码区域el-row
以及内部el-col
注释掉,重新加载检查编译情况,这时能成功编译
接着在放开el-row
新增自定义el-col
,重新加载检查编译情况,能够成功编译和渲染
<h3>动态渲染内容</h3>
<el-row v-for="(item, index) in form.subObjList" :key="index" :gutter="12" :style="{ background: '#edfced' }">
<el-col>heheda</el-col>
<!-- <el-col> {{item?.projectNameLabel}}:{{item?.projectName}}</el-col>-->
<!-- <el-col> {{item?.technicalPointLabel}}:{{item?.technicalPoint}}</el-col>-->
<!-- <el-col> {{item?.mainFunctionLabel}}:主要功能:{{item?.mainFunction}}</el-col>-->
<!-- <el-col> {{item?.difficultyLabel}}:{{item?.difficulty}}</el-col>-->
<!-- <el-col><hr></el-col>-->
</el-row>
观察到插值语法中的可选链运算符(.?
)比较怪,于是选取一个el-col
去掉.?
并放开注释,可以正常渲染
再次加上.?
,重现了编译失败
由此可以确认是在插值语法中使用可选链运算符(.?
)引起的
临时解决措施
去掉可选链运算符(.?
),与前端确认,此处动态渲染的数据需请求接口得到,item的属性没有在data()
中申明,所以使用(.?
)来避免一些潜在的问题
后续
处理完这个问题后,计划在个人PC上复现,但是并没有复现成功(环境为vue 3.4.28
& node 18.20.4
),经过搜查发现该问题会在vue2低版本上出现,此时相应的node.js版本不支持在插值语法中使用可选链运算符,于是搭建了(vue 2.6.10
& node 14.16
),确实成功复现了这个问题。求助的项目vue版本为2.5.x
,考虑到不久后该项目就会升级vue 3
,所以没有深究如何在vue 2
中实现插值语法可以使用可选链运算符号。
此处分享在vue3中该案例的完整代码:
<template>
<div>
<h3>Welcome</h3>
<el-form :model="form" label-width="100px">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="姓名">
<el-input v-model="form.name"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="年龄">
<el-input v-model="form.age"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="地址">
<el-input v-model="form.address"></el-input>
</el-form-item>
</el-col>
</el-row>
<h3>动态渲染内容</h3>
<el-row v-for="(item, index) in form.subObjList" :key="index" :gutter="12" :style="{ background: '#edfced' }">
<el-col> {{item?.projectNameLabel}}:{{item?.projectName}}</el-col>
<el-col> {{item?.technicalPointLabel}}:{{item?.technicalPoint}}</el-col>
<el-col> {{item?.mainFunctionLabel}}:主要功能:{{item?.mainFunction}}</el-col>
<el-col> {{item?.difficultyLabel}}:{{item?.difficulty}}</el-col>
<el-col><hr></el-col>
</el-row>
</el-form>
<button @click="setRenderInfo">动态渲染赋值</button>
<button @click="clearRenderInfo">动态渲染清空</button>
</div>
</template>
<!--vue3写法-->
<!--<script setup lang="ts" name="About">
import { reactive, ref } from 'vue'
import type { ComponentSize, FormProps } from 'element-plus'
let form = {
name: '松树戈',
age: '66',
address: '这里',
secondLabel: '我就是第二个标题',
subObjList: []
}
// 模拟远程请求后对subObjList进行赋值
form.subObjList = [
{ projectNameLabel: '项目名称',
projectName: 'xx项目前端',
technicalPointLabel: '技术点',
technicalPoint: 'vue vuex vue-router js',
mainFunctionLabel: '主要功能',
mainFunction: '前端交互ux整改,完善用户体验',
difficultyLabel: '难点',
difficulty: '大批量数据渲染'
},
{ projectNameLabel: '项目名称',
projectName: 'xx项目后端',
technicalPointLabel: '技术点',
technicalPoint: 'springboot mybatis redis pgsql',
mainFunctionLabel: '主要功能',
mainFunction: '支持用户的特定业务流程',
difficultyLabel: '难点',
difficulty: '大批量数据校验'
}
]
</script>-->
<!--vue2写法-->
<script>
export default {
data() {
return {
form: {
name: '松树戈',
age: '66',
address: '这里',
secondLabel: '我就是第二个标题',
subObjList: []
}
}
},
mounted() {
console.log('在-mounted内部')
},
methods: {
setRenderInfo() {
this.form.subObjList = [
{ projectNameLabel: '项目名称',
projectName: 'xx项目前端',
technicalPointLabel: '技术点',
technicalPoint: 'vue vuex vue-router js',
mainFunctionLabel: '主要功能',
mainFunction: '前端交互ux整改,完善用户体验',
difficultyLabel: '难点',
difficulty: '大批量数据渲染'
},
{ projectNameLabel: '项目名称',
projectName: 'xx项目后端',
technicalPointLabel: '技术点',
technicalPoint: 'springboot mybatis redis pgsql',
mainFunctionLabel: '主要功能',
mainFunction: '支持用户的特定业务流程',
difficultyLabel: '难点',
difficulty: '大批量数据校验'
}
]
},
clearRenderInfo() {
this.form.subObjList = []
}
}
}
</script>
<style scoped>
.about {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
color: rgb(85, 84, 84);
font-size: 18px;
}
</style>