目录

vue2-插值语法中使用可选链运算符.compile异常排查思路

vue2 插值语法中使用可选链运算符(.?)compile异常排查思路

@[TOC](vue2 插值语法中使用可选链运算符(.?)compile异常排查思路)

前言

最近接到组内前端求助,在使用v-for进行动态渲染的时候项目突然不能正常编译了,报错提示 SyntaxError: Unexpected token ... 十分奇怪

https://i-blog.csdnimg.cn/direct/0692820535654766b0791b2017030f8d.png

代码可参考如下:

      <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>

https://i-blog.csdnimg.cn/direct/fca22e1347ea464bb82a3320001f515e.png

观察到插值语法中的可选链运算符( .? )比较怪,于是选取一个 el-col 去掉 .? 并放开注释,可以正常渲染

https://i-blog.csdnimg.cn/direct/9cc68bca01124d0ba4d7777a1935fff0.png

再次加上 .? ,重现了编译失败

https://i-blog.csdnimg.cn/direct/828eca7ae94944249715591b218c9d3d.png

由此可以确认是在插值语法中使用可选链运算符( .? )引起的

临时解决措施

去掉可选链运算符( .? ),与前端确认,此处动态渲染的数据需请求接口得到,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>

demo项目完整代码: