vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue2升级Vue3作用域插槽语法变更

从Vue2升级Vue3过程中遇到作用域插槽语法变更问题的解决方法

作者:爱看星星的猪_

在将项目从 Vue 2 升级到 Vue 3 的过程中,遇到了两处典型的兼容性问题,主要涉及 作用域插槽语法变更 和 响应式数据类型处理差异,本文通过具体代码示例,说明问题原因、Vue 版本机制差异,并给出推荐改法,需要的朋友可以参考下

一、问题代码片段及功能说明

场景 1:表格中动态字段的样式与标题控制(输入框)

<!-- Vue 2 原始写法 -->
<template slot-scope="scope">
  <el-input-number
    :class="{ 'text-red': originTableDataCopy[scope.$index]['EXT_FIELD' + (firstChidIndex + 1)]?.split('?')[1] !== 'null' }"
    :title="originTableDataCopy[scope.$index]['EXT_FIELD' + (firstChidIndex + 1)]?.split('?')[1] || ''"
    v-model="scope.row['EXT_FIELD' + (firstChidIndex + 1)]"
  />
</template>

功能说明

场景 2:更复杂的动态字段名与条件渲染

<!-- Vue 2 原始写法 -->
<template slot-scope="scope">
  <el-input-number
    :class="{ 'text-red': 
      loanAccounttype === 'issued' &&
      originTableDataCopy[scope.$index]['EXT_FIELD.' + firstChid.functFldEnNm + (index + 1)]?.split('?')[1] &&
      originTableDataCopy[scope.$index]['EXT_FIELD.' + firstChid.functFldEnNm + (index + 1)]?.split('?')[1] !== 'null'
    }"
    v-model="scope.row['EXT_FIELD.' + firstChid.functFldEnNm + (index + 1)]"
    v-if="!secondChid.name?.includes('参考值')"
  />
  <span v-else>{{ scope.row['REF_VALUE_0'] }}...</span>
</template>

功能说明

二、Vue 2 与 Vue 3 的机制差异

维度Vue 2Vue 3
作用域插槽语法<template slot-scope="scope"><template #default="{ row, $index }">
插槽参数scope 是对象,含 row, $index 等属性直接解构 { row, $index }$index 仍可用但非必须
$index 是否存在✅ 存在✅ 存在(作为默认属性),但不再通过 scope.$index 访问
响应式代理方式Object.defineProperty + __ob__Proxy 包装,控制台显示为 Proxy(Array)
数据访问建议可通过 data[index]scope.row强烈推荐直接使用 row,避免依赖外部数组索引

关键变化
Vue 3 中 slot-scope 已废弃,且虽然 $index 仍可解构使用,但只要用不到索引,就不应引入。更重要的是,row 就是当前行的真实引用,等价于 originTableDataCopy[$index],且更安全

三、迁移后的正确写法(Vue 3 兼容)

改造原则:

  1. 使用 #default="{ row }" 替代 slot-scope="scope"
  2. row['xxx'] 替代 originTableDataCopy[scope.$index]['xxx']
  3. 添加 typeof ... === 'string' 防御性判断,避免 .split() 报错

示例:场景 2 的 Vue 3 安全写法

<template #default="{ row }">
  <el-input-number
    type="number"
    :controls="false"
    :class="{
      'text-red':
        loanAccounttype === 'issued' &&
        typeof row['EXT_FIELD.' + firstChid.functFldEnNm + (index + 1)] === 'string' &&
        row['EXT_FIELD.' + firstChid.functFldEnNm + (index + 1)].split('?')[1] &&
        row['EXT_FIELD.' + firstChid.functFldEnNm + (index + 1)].split('?')[1] !== 'null'
    }"
    :title="
      loanAccounttype === 'issued' &&
      typeof row['EXT_FIELD.' + firstChid.functFldEnNm + (index + 1)] === 'string' &&
      row['EXT_FIELD.' + firstChid.functFldEnNm + (index + 1)].split('?')[1]
        ? row['EXT_FIELD.' + firstChid.functFldEnNm + (index + 1)].split('?')[1]
        : ''
    "
    v-model="row['EXT_FIELD.' + firstChid.functFldEnNm + (index + 1)]"
    v-if="originTableDataCopy.length > 0 && editable && !secondChid.name?.includes('参考值')"
  />
  <el-input-number
    v-else-if="!secondChid.name?.includes('参考值')"
    type="number"
    :controls="false"
    v-model="row['EXT_FIELD.' + firstChid.functFldEnNm + (index + 1)]"
  />
  <span class="text-red" v-else>
    {{ 
      row['REF_VALUE_0'] + 
      (secondChid.twolvlClsf?.includes('轻度') ? '1' : 
       secondChid.twolvlClsf?.includes('中度') ? '2' : '3')
    }}
  </span>
</template>

关键改进:

  • 移除 scope.$index,使用 row 直接访问;
  • 添加 typeof ... === 'string' 防止 .split() 在非字符串上调用;
  • 保留业务逻辑不变,提升健壮性。

四、总结与最佳实践

问题类型Vue 2 写法Vue 3 推荐写法原因
作用域插槽slot-scope="scope"#default="{ row }"语法标准化,更简洁
行数据访问originTableDataCopy[scope.$index]row更安全,避免索引错位
类型安全无防御typeof val === 'string'防止 .split() 在 number/null 上调用
布尔表达式cond ? true : false直接用 cond冗余,JS 表达式本身即布尔值

最佳实践建议:

  1. 永远优先使用 row 而非 data[index]:它更可靠,不受数组变更影响;
  2. .split(), .replace() 等字符串方法做类型检查
  3. 避免 JSON.parse(JSON.stringify()) 深拷贝,改用 structuredClone{...} + map
  4. 按需解构插槽参数:不用 $index 就不要写它。

以上就是从Vue2升级Vue3过程中遇到作用域插槽语法变更问题的解决方法的详细内容,更多关于Vue2升级Vue3作用域插槽语法变更的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文