开篇致辞:在Vue中任何操作DOM的操作都是在作死!
组件数据来源(单向)
父元素的属性
组件自身的状态data
(后续单讲)来自状态管理器,如 vuex,Vue.observable
状态data 与 属性 props
状态是组件自身的数据
属性是来自父组件的数据
状态的改变未必会触发更新
属性的改变未必会触发更新
DEMO
两者都不会触发更新!!,但是值会发生变化,这个是肯定的
代码很简单,就是通过button改变data值而已!
name为什么没有更新!因为name并没有做响应式,可以看到name是直接通过属性赋值的,这里我特意打印了实例的$data
可以看到set get并没有name
info明明在为什么没有更新呢?,因为此时仅仅info存在于响应上,number并没有
那么这里只需要注册number即可
data() {
this.name=name
return {
info: {
number:''
},
};
},
那么此时就会触发组件的更新了
受 ES5 的限制,Vue.js 不能检测到对象属性的添加或删除。因为 Vue.js 在初始化实例时将属性转为 getter/setter,所以属性必须在 data 对象上才能让 Vue.js 转换它,才能让它是响应的。
Vue给我们了$set()方法,既可以新增属性,又可以触发视图更新
this.$set(this.info, 'number', 1)
这样也是会触发更新的
还有一种情况就是更新了未用到的data,比如你data里声明了a,但是你压根就没显示a你更新a也没什么用
另外最常见的数组,支持响应式更新的方法:push(),pop(),shift(),unshift(),splice(),sort(),reverse(),因为这些方法会改变原数组。
不支持响应式更新的方法:filter(),concat(),slice(),这3个放法会返回新数组,可以用新数组替换原数组解决
响应式更新
稍微整理一下:在vue render的时候,会对data下面的数据进行get/set转换(之前文章演示过),可以说相当于给所有数做了一个代理层,不管是取数据还是修改数据都会经过这个代理层然后做一些相应的操作。可以理解为,我们将所有用到的数据,在初始化的时候都被一个watcher看住了(已用到的数据),只有在watcher外的即使操作也不会去更新
计算属性(Computed)
减少模板中的计算逻辑
数据缓存
依赖固定的数据类型
关于computed,个人理解他是用于数据的计算,并可以直接返回结果值,由于返回的是值,因此可以直接使用该数据,而不是绑定函数,驱动computed执行的是数据是否变化这个条件,所以可以理解为,computed里面的函数监听了数据是否变化。
DEMO
Reversed message1: "{{ reversedMessage1 }}"
{{ now }}
(上面的代码少了一个v-moedl 绑定,效果图不一样,不用在意)
可以看到我把函数的返回值直接用双括号绑定的方法渲染在模板里。
Reversed message1: "{{ reversedMessage1 }}"
Reversed message2: "{{ reversedMessage2() }}"
{{ now }}
接下来,我写了一个方法reversedMessage2,并且加了一个强制刷新页面的按钮(这个方法也适用于层级太多数据更新未更新组件的情况)
可以看到此时都执行了两个方法
当我点击刷新的时候,computed由于未更新则没有重新计算
watch
监听数据变化,用法很简单
{{ $data }}
需要注意的就是第一个参数是新值,而第二个参数是旧值。这是一种简写
a:{
handler(newval,old){
}
}
最终会翻译成这样,这里 watch 的一个特点是,最初绑定的时候是不会执行的,要等到 firstName 改变时才执行监听计算。如果想初始化进行操作,设置 immediate: true
a:{
handler(newval,old){
console.log(newval,old)
},
immediate: true
}
一般情况下 字符串跟数组都是比较容易监听的,唯有对象有点恶心!
{{ $data }}
现在我更新了,b下面c的值,此时是没办法监听到函数触发的,但是值是更新了,毕竟方法触发了
b:{
handler(newval,old){
console.log(newval,old)
},
deep:true
}
这种时候就需要加个 deep:true 就可以了,当然你可以监听c
'b.c':{
handler(newval,old){
console.log(newval,old)
}
}
像这样直接监听改变的内容就不需要什么deep了
这里有个细节
'b':{
handler(newval,old){
this.e.push('666')
console.log(newval,old)
},
deep:true
},
e(newval,old){
console.log(newval,old)
}
对象返回的内容两者是一样的,因为这个是引用类型,引用没有发生改变,这个不是bug