1、什么是响应式
响应式,是实现数据驱动视图的第一步,监听数据变化,使得用户在设置数据时,可以通知vue内部进行视图更新。
主要原理在文档的 深入响应式原理章节中可以找到。
用代码来实现:
<template>
<div>
<div> {{ name }} </div>
<button @click="changeName">改名字</button>
</div>
</template>
<script>
export default {
data () {
return {
name: 'A'
}
},
methods: {
changeName () {
this.name = 'B'
}
}
}
</script>
2、实现响应式
在深入学习数据响应式原理之前
我们需要学习一下
需求一:姓名不要括号得到值:
let obj2 = {
姓: "高",
名: "圆圆",
get 姓名() {
return this.姓 + this.名;
},
age: 18
};
console.log("需求二:" + obj2.姓名);
总结:get用于获取一个值(在函数前面加get,不加括号的函数)
需求二:姓名可以被写
let obj3 = {
姓: "高",
名: "圆圆",
get 姓名() {
return this.姓 + this.名;
},
set 姓名(xxx){
this.姓 = xxx[0]
this.名 = xxx.slice(1)
},
age: 18
};
//在定义完一个对象之后,添加新的get和set,只能通过Object.defineProperty()
var _xxx=0 //声明全局变量
Object.defineProperty(obj3,'xxx',{
get(){
return _xxx
},
set(value){
_xxx=value
}
})
obj3.姓名 = '高媛媛'
console.log(`需求三:姓 ${obj3.姓},名 ${obj3.名}`)
总结:set接受一个新的值。用xxx 触发set函数
在定义完一个对象之后,添加新的get和set,只能通过Object.defineProperty()
通过上面的代码,已经知道
getter/setter用于对属性的读写进行监控。Object.defineProperty可以给对象添加属性value,可以给对象添加getter/serter
使用代理
需求三:需求:我们需要存储一个n的值,有一个条件就是n不能小于0。
请问我们怎样保证,不管用户怎么修改n的值,都可以满足我们的要求。
let myData = {n:0}
let data = proxy({ data:myData }) // 括号里是匿名对象,无法访问
function proxy({data}/* 解构赋值,*/){
let value = data.n // 声明一个新的value来获取data.n,这样就可以监听data.n的变化
Object.defineProperty(data, 'n', {
get(){
return value
},
set(newValue){
if(newValue<0)return
value = newValue
}
})
// 就加了上面几句,这几句话会监听 data
const obj = {}
Object.defineProperty(obj, 'n', {
get(){
return data.n
},
set(value){
if(value<0)return//这句话多余了
data.n = value
}
})
return obj // obj 就是代理
}
-
添加代理让
data成为myData的代理对象,对这个对象进行操作 -
对
myData所有属性进行监控 -
为什么要监控?,为了防止
myData的属性变了,data不知道 -
vm知道了又如何? 知道属性变了就可以调用render(data)
-
声明一个新的
value来获取data.n,这样就可以监听data.n的变化 -
接着定义一个新的(虚拟)
n来覆盖原来的data.n,如果你要读取n的值,就调用get函数;如果你要设置新的值,就把新的值给value
其他扩展:
Vue.set 和 this.$set
- 作用一: 新增key
- 如果没有创建过,自动创建代理和监听
- 触发UI更新(但不会立刻更新)
举个例子:
//引用完整版 Vue
import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;
new Vue({
data: {
obj: {
a: 0 // obj.a 会被 Vue 监听 & 代理
}
},
template: `
<div>
{{obj.b}}
<button @click="setB">set b</button>
</div>
`,
methods: {
setB() {
Vue.set(this.obj,'b',1)
// this.$set(this.obj,'b',1) //这句和上面等同
}
}
}).$mount("#app");
数组的解决方案
Q: 刚才说了如果data中新增了key有两种方法可以解决,但有没有可能没有办法提前声明好,只能使用set呢?比如说data里有数组怎么办?
A:好问题,继续看。
方案一:可以用Vue.set或this.$set(不推荐)
方案二:尤雨溪为我们提供了一种数组的变异方法
//引用完整版 Vue
import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;
new Vue({
data: {
array: ["a", "b", "c"]
},
template: `
<div>
{{array}}
<button @click="setD">set d</button>
</div>
`,
methods: {
setD() {
// this.$set(this.array,3,'d') //可以实现,不推荐
this.array.push('d') //可以实现,推荐
}
}
}).$mount("#app");
尤雨溪的做法:
篡改数组的API,见文档中变更方法,这 7 个API都会被Vue篡改,调用后会更新UI.