虽然你知道了Vue监听对象的原理,但是还有一个API(Vue.set()
)
当添加一个当时没定下来的性别属性
以后随着用户的交互,不能添加代码,毕竟不能让用户动代码;我需要有一个,那怎么办
<h2>性别:{{student.sex}}</h2>
读取了对象里面不存在的属性值返回的是undefined
,直接读取不存在的sex
就会报错
> vm._data.student.sex = '男'
< '男'
页面没有更新
> vm._data
< {__ob__: Observer}
address: (...)
name: (...)
student: Object
age: (...)
friends: (...)
name: (...)
sex: "男"
发现当时写好的属性都有get
和set
,set
可以影响页面
所以你后添加的数据是不做响应式的
> vm
vm身上没有sex
也就是说你想用什么当年你一定要配置好
虽然vm._data.student.sex = '男'
不好用不能添加,但是你可以使用vue
给你的api
来实现后添加的数据也能有响应式的功能,叫做:Vue.set()
,set()
里面可以传三个参数:f(target,key,val)
,target
:目标(你要往谁的身上追加一个属性)
,key
:你要往它的身上追加一个什么名字的属性
,val
:这个属性的值
> Vue.set(student,sex,'男')
这是错的,student不能直接找到,要顺着一条线去找
> Vue.set(vm._data.student,'sex','男')
< '男'
> vm._data
{__ob__: Observer}
address: (...)
name: (...)
student: Object
age: (...)
friends: (...)
name: (...)
sex: (...)
__ob__: Observer {value: {…}, dep: Dep, vmCount: 0}
get age: ƒ reactiveGetter()
set age: ƒ reactiveSetter(newVal)
get friends: ƒ reactiveGetter()
set friends: ƒ reactiveSetter(newVal)
get name: ƒ reactiveGetter()
set name: ƒ reactiveSetter(newVal)
get sex: ƒ reactiveGetter()
set sex: ƒ reactiveSetter(newVal)
其实还有一个api
跟Vue.set()
原理一模一样,就是换了个名字,但不在Vue
身上了,在vm
身上,而且不叫vm.set()
而叫vm.$set()
> vm.$set(vm._data.student,'sex','女')
< '女'
验证是不是响应式:
> vm._data.student.sex = '男'
< '男'
页面也跟着变化
Vue.set(vm._data.student,'sex','男')
这样写我们就忘了数据代理
;我想遇到student
有这么难吗?
> vm._data.student === vm.student
< true
所以你添加一个性别可以再简单一点:
> Vue.set(vm.student,'sex','男')
< '男'
同理:
> vm.$set(vm.student,'sex','女')
< '女'
可以再旁边添加一个按钮点我添加一个性别
<h1>学生信息</h1>
<button @click="addSex">添加一个性别属性,默认值是男</button>
<h2>学生姓名:{{student.name}}</h2>
<h2 v-if="student.sex">学生性别:{{student.sex}}</h2>
<h2>学生真实年龄:{{student.age.rAge}}和对外年龄:{{student.asAge}}</h2>
<h2>朋友们:</h2>
<ul>
<li v-for="(friend,index) in student.friend:key="index">
{{friend.name}}-{{friend.age}}
</li>
</ul>
methods:{
addSex(){
Vue.set(this.student,'sex','男')
}
}
这里的this
指的就是vm
这样写,再F12(开发者模式下的Console)
也可以修改
> vm.student.sex = '女'
< '女'
还可以
methods:{
addSex(){
this.$set(this.student,'sex','男')
}
}
但是Vue.set()
是有局限的
演示一下这个局限:
<h2>校长是:{{leader}}</h2>
不能在写Vue.set(vm._data.student)
了,应该给data
里面加:
> Vue.set(vm._data,'leader','陈睿')
x [Vue warn]:Avoid adding reactive properties to a Vue instance
Avoid adding reactive properties:不允许你添加一个响应式的数据
Vue instance:Vue实例
Avoid adding reactive properties to a Vue instance:不允许你添加一个响应式的数据在Vue的实例身上
也就是说这个Vue.set
只能给data
里的某一个对象追加属性,而不能给data
追加属性
> Vue.set(vm,'leader','陈睿')
x [Vue warn]:Avoid adding reactive properties to a Vue instance
它的意思就是说vm
不允许作为那个target
,vm
身上的根数据(data
)也不允许作为那个target
。如果就想加,可以:
school:{
name: 'bilibili',
address: '上海',
}
<h2>学校名称:{{school.name}}</h2>
<h2>学校地址:{{school.address}}</h2>
<h2>校长是:{{school.leader}}</h2>
> Vue.set(vm.school,'leader','陈睿')
记住一个原则:你只要找到属性就可以,不管你怎么找
用法:
向响应式对象中添加一个 property,并确保这个新 property 同样是响应式的,且触发视图更新。