VUE 2.0取字典集后无法更新节点的解决方式的思考

VUE 2.0取字典集后无法更新节点的理解

(前端新手上路的学习日记)
我在现在的项目中,字典集合是放在数据库中,通过redis写了一层缓存,需要我们前端调接口获取来渲染页面的,一个一个调字典又会很卡。故而有getDictList方法来通过传一个由字典id构造而成的数组批量获取字典集合。
进而用字典的id值当作key,构造一个dictList对象(用数组的话会很坑,具体的后文可见)的方式来对表单,表格等节点进行取字典集或通过filter函数来获取字典id渲染出字典值。

html取字典部分是这样写的

            <el-select
              size="medium"
              class="search-sort"
              v-model="findParam.type"
              placeholder="请选择"
            >
              <el-option
                v-for="item in useDict['1059']"
                :key="item.dic_id"
                :label="item.dic_name"
                :value="item.dic_id"
              ></el-option>
            </el-select>

初始代码

代码段:

      getDictList(this.dictIdList).then(res=>{
        // console.log('字典id集合',this.dictIdList)
         if(res.data.code == 20000){
           res.data.data.forEach((item,index)=>{
             //对字典进行处理 方便后续选择框进行选项绑定
             item.sysDictItemList = item.sysDictItemList.map(item => {
               return { dic_name: item.dictItemName, dic_id: item.dictItemId, no: item.dictItemId };
               });
                 this.useDict[item.dictId] = item.sysDictItemList  // 用赋值数据是非响应式的 赋值到最后一个数据再进行节点更新
            })
           console.log( this.useDict,'方法一的字典集合')
          //  this.$forceUpdate() // 更新视图后更新表单 来获取字典
          }else{
           this.$message({
            type: "warning",
            message: "查询字典集接口报错"+ res.data.msg,
          });
          }
      })

这样写之后会带来一个问题,就是由于取字典接口的回调可能在页面节点渲染之后,而

this.useDict[item.dictId] = item.sysDictItemList

// …
检测变化的注意事项
由于 JavaScript 的限制,Vue 不能检测数组和对象的变化。
当你利用索引直接设置一个数组项或对象属性时,例如:vm.items[indexOfItem] = newValue… //

这种方式的赋值语句不会触发页面更新,究其原因自我理解是通过option绑定的方式可能并不是深度监听,一开始渲染时useDict是空的,useDict[‘1059’] 也是空的,因而无法添加getter和setter函数,故而对应前端节点并未订阅这个 useDict[‘1059’] 的数据,哪怕 useDict[‘1059’] 获取到了之后也无法通过双向绑定原理使得前端页面更新视图层,这是刷新节点,重新获取,使得节点的更新在获取到 useDict[‘1059’]之后才行
// 此处用来存放字典集合的useDict的数据类型需要是对象类型,如果是数组的话,给useDict[10000]赋值就会带来9999个空项,会极大程度的增加浏览器的负荷 //
但拖动页面之后可以获取到字典集合(一度让我十分惊讶,可能是拖动页面导致VUE触发了更新视图层的函数?有大佬看到了欢迎指点)

去百度了之后发现了三种解决办法

1.通过Key将字典集合和HTML节点关联起来

对表单页面绑定key值(成功)
    <el-form
      :key="useDict.length"
      :model="formData"
    >

通过useDict的长度当作我方表单的键值,在获取了字典集合之后,useDict的长度发生变化,键值改变,会强行更新整个表格,后来思考了一下,其实只需要更新一个表单中的相应的取了字典的节点就可以了,于是换了一种写法

尝试对对应节点绑定Key值(失败)
          <el-select
            size="medium"
            class="search-sort"
            v-model="findParam.type"
            placeholder="请选择"
          >
            <el-option
              v-for="item in useDict['1059']"
              :key="useDict['1059']"    //这样写是期望能在字典值获取后监听到变化从而通过key的变化更新节点
              :label="item.dic_name"
              :value="item.dic_id"
            ></el-option>
          </el-select>

得到VUE报错:
Avoid using non-primitive value as key, use string/number value instead

自我理解:在节点渲染中需要保证每个节点的键值是不同的,由于确实在一个表单中存在着几个取相同字典的节点存在,这样写可能确实带来隐患,所以希望将对应字典和Html节点通过订阅者原则绑定起来的方式暂时只能走到这里(我太菜了)

2.用VUE$.Set 语句将响应式数据添加到嵌套的对象上

// 用Vue.set(成功)

 this.$set(this.useDict,item.dictId,item.sysDictItemList)

// 用Array.prototype.splice (没试过 应该和.set 效果差不多)

this.useDict.splice(item.dictId, 1, item.sysDictItemList)

则有

      getDictList(this.dictIdList).then(res=>{
        // console.log('字典id集合',this.dictIdList)
         if(res.data.code == 20000){
           res.data.data.forEach((item,index)=>{
             //对字典进行处理 方便后续选择框进行选项绑定
             item.sysDictItemList = item.sysDictItemList.map(item => {
               return { dic_name: item.dictItemName, dic_id: item.dictItemId, no: item.dictItemId };
               });
                 this.$set(this.useDict,item.dictId,item.sysDictItemList)  // 用$set 加数据是响应式的 会带动更新节点
            })
           console.log( this.useDict,'方法一的字典集合')
          //  this.$forceUpdate() // 更新视图后更新表单 来获取字典
          }else{
           this.$message({
            type: "warning",
            message: "查询字典集接口报错"+ res.data.msg,
          });
          }
      })

但是通过自己的理解(不一定对),在循环时触发视图更新可能? 会造成部分的资源损耗,
后续通过学习已证明是错误的 上下两种写法效果是一样的)
于是则有最终版:

            getDictList(this.dictIdList).then(res=>{
        // console.log('字典id集合',this.dictIdList)
         if(res.data.code == 20000){
           res.data.data.forEach((item,index)=>{
             //对字典进行处理 方便后续选择框进行选项绑定
             item.sysDictItemList = item.sysDictItemList.map(item => {
               return { dic_name: item.dictItemName, dic_id: item.dictItemId, no: item.dictItemId };
               });
               if (index == res.data.data.length -1) {
                 this.$set(this.useDict,item.dictId,item.sysDictItemList)  // 用$set 加数据是响应式的 会带动更新节点
               }else{
                 this.useDict[item.dictId] = item.sysDictItemList  // 用赋值数据是非响应式的 赋值到最后一个数据再进行节点更新
               }
            })
           console.log( this.useDict,'方法一的字典集合')
          //  this.$forceUpdate() // 更新视图后更新表单 来获取字典
          }else{
           this.$message({
            type: "warning",
            message: "查询字典集接口报错"+ res.data.msg,
          });
          }
      })

等循环到最后一个字典再触发VUE的视图更新,自我感觉可能?运行效率会更高一些,由于现在还不清楚如何测量前端页面的渲染效率,故而这段学习暂时停到这种程度

.2021 0518 :
破案了 官方文档 对VUE响应式深入理解的后续有介绍

异步更新队列
可能你还没有注意到,Vue 在更新 DOM 时是异步执行的。只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。Vue 在内部对异步队列尝试使用原生的 Promise.then、MutationObserver 和 setImmediate,如果执行环境不支持,则会采用 setTimeout(fn, 0) 代替。
例如,当你设置 vm.someData = ‘new value’,该组件不会立即重新渲染。当刷新队列时,组件会在下一个事件循环“tick”中更新。多数情况我们不需要关心这个过程,但是如果你想基于更新后的 DOM 状态来做点什么,这就可能会有些棘手。虽然 Vue.js 通常鼓励开发人员使用“数据驱动”的方式思考,避免直接接触 DOM,但是有时我们必须要这么做。为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后立即使用 Vue.nextTick(callback)。这样回调函数将在 DOM 更新完成后被调用。

来自VUE官方文档

3.将用到的字典值作为key将useDict对象写在data{} 里面,形如:

useDict:{
1000:[],
1001:[],
1002:[],
1003:[],
1004:[],
1005:[],
1006:[],
}

将视图更新所需要用到的字典id直接写到data里

Vue 无法检测 property 的添加或移除。由于 Vue 会在初始化实例时对 property 执行 getter/setter 转化,所以 property 必须在 data 对象上存在才能让 Vue 将它转换为响应式的。例如:
var vm = new Vue({
data:{
a:1
}
})
// vm.a 是响应式的
vm.b = 2
// vm.b 是非响应式的

//来自VUE官方文档

直接将需要取到的字典ID项直接写在data 里,这样直接用等号赋值,如下:

this.useDict[item.dictId] = item.sysDictItemList 

也能使得视图层监听到数据字典集合的变化从而更新视图了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值