热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

vue数据更新却不render?

以下都基于数据已经渲染到dom上后再对数据进行修改,console出来的数据更新了,但绑定的dom不更新的问题更新对象的属性不renderdata()

以下都基于数据已经渲染到 dom 上后再对数据进行修改,console 出来的数据更新了,但绑定的 dom 不更新的问题

  1. 更新对象的属性不render
    data() {
    return {
    detail: {}
    }
    }
    created() {
    this.detail = {
    a: ‘1’, // 更新
    b: ‘2’ // 更新
    }
    }
    mounted () {
    this.detail.c = ‘12’ // 不更新
    }

    vue 不允许动态添加对象的根级别属性。

Vue 会在初始化实例时对对象的属性执行 getter/setter 转化,所以属性必须在 data 对象上存在才能让 Vue 将它转换为响应式的

解决方法:使用 set给对象添加属性或在初始化对象时就声明属性//方法一this.set 给对象添加属性或在初始化对象时就声明属性 // 方法一 this.set//this.set(this.detail, ‘c’, 12)

// 方法二

this.detail = {
a: ‘1’,
b: ‘2’,
c: ‘12’
}


2. 更新数组数据不render?
// 场景1
export default {
data () {
return {
detail: []
}
},
created () {
this.detail[0] = { a: 2 }
},
mounted () {
this.detail[0].a = 4 // 不更新
}
}

// 场景2
export default {
data () {
return {
detail: []
}
},
created () {
this.detail[0] = 2
},
mounted () {
this.detail[0] = 3 // 不更新
}
}

数组的索引是没有响应式的,比如上面的 detail 的 0 这个位置是没有 setter/getter 的,所以无法检测到该数据的变更,{ a: 2 } 直接赋值给了 0 的位置,所以也无法对 a 做响应式转化

解决方法: 同样可以使用 $set 给数组的索引的内容执行 getter/setter 转化,但也可以使用 变异方法
使用 $set 设置数组指定位置的数据

this.$set(this.detail, 0, { a: 2 })

变异方法:

push()
pop()
splice()
shift()
unshift()
sort()
reverse()
export default {
data () {
return {
detail: []
}
},
created () {
this.detail.splice(0, 1, { a: 2 })
},
mounted () {
this.detail[0].a = 4 // 更新
}
}

还有一种方式,就是给数组重新赋值

this.detail = [{a: 2}]

源码里,其实在 $set 处理数组时,内部也是通过 splice() 对数组的元素进行操作的

export function set (target: Array | Object, key: any, val: any): any {
if (process.env.NODE_ENV !== ‘production’ &&
(isUndef(target) || isPrimitive(target))
) {
warn(Cannot set reactive property on undefined, null, or primitive value: ${(target: any)})
}
// 传入的 第一个参是数组时并且第二个参是有效的索引值
if (Array.isArray(target) && isValidArrayIndex(key)) {
target.length = Math.max(target.length, key)
target.splice(key, 1, val)
return val
}
if (key in target && !(key in Object.prototype)) {
target[key] = val
return val
}
const ob = (target: any).ob
if (target._isVue || (ob && ob.vmCount)) {
process.env.NODE_ENV !== ‘production’ && warn(
'Avoid adding reactive properties to a Vue instance or its root $data ’ +
‘at runtime - declare it upfront in the data option.’
)
return val
}
if (!ob) {
target[key] = val
return val
}
// 响应式转化: 给对象属性执行 setter/getter 转化
defineReactive(ob.value, key, val)
ob.dep.notify()
return val
}

3. 为什么变异方法就能让新增的数据有响应式呢?
这个官方文档并没有细说,但是翻过源码的人就能知道,为什么上面这些数组的原生方法被叫做变异方法呢,字面上了解就是 vue 对原生的这些方法做了一点点的修饰。

// /core/observer/array.js
const methodsToPatch = [
‘push’,
‘pop’,
‘shift’,
‘unshift’,
‘splice’,
‘sort’,
‘reverse’
]
// 通过def 重新定义了数组的原生函数如push等
def(arrayMethods, method, function mutator (…args) {
const result = original.apply(this, args)
const ob = this.ob
let inserted
switch (method) {
case ‘push’:
case ‘unshift’:
inserted = args
break
case ‘splice’:
inserted = args.slice(2)
break
}
// 将数组上述的原生函数的传入的参数做处理
if (inserted) ob.observeArray(inserted)
// notify change
ob.dep.notify()
return result
})

observeArray (items: Array) {
for (let i = 0, l = items.length; i // 遍历参数配置响应式
observe(items[i])
}
}


推荐阅读
author-avatar
为你空手的执着
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有