带着一点个人理解,我们来聊聊这个初学者很容易遇到的问题,本人也作为一个初学者,看到这里,思路理清了,记录下这个文章,以防止遗忘。
首先我们来聊聊,响应式。
Vue底层的响应式实现原理来自于Object内置的一个方法
Object.defineProperty()
在搞懂之前,我们必须搞懂这个方法。
这个方法有三个参数。
第一个参数: obj 即你想要操作的对象
第二个参数: 你想要定义的属性名
第三个参数:
一个配置对象(知道什么是配置对象的这个括号可以不用看,配置对象,就是属性名固定,根据你的需要进行配置。)
这个配置对象常用的有三个
第一个是
value属性,用于你来定义你的属性名的值(第二个参数的值)
第二个是
get(){}
或者说
get:function(){}
第三个是
set(){}
或者说
set:funtion(){}
get用于当访问了你定义的属性的时候要干什么(自动执行)
set用于当更改了你定义的属性的时候要干什么(自动执行)
ok这个方法我们就介绍到这里。
接下来看看,响应式,
总的来说,能不能添加成响应式的,就要看你有没有用Vue/vm来添加用Vue封装的几个能改变数组的方法也算。
我们来看几个例子
例子一
<div id="root"></div>
<script>
const vm = new Vue({
el: '#root',
data: {
student: {
name: 'tom',
age: 18,
hobby: ['抽烟', '喝酒', '烫头'],
friends: [
{ name: 'jerry', age: 35 },
{ name: 'tony', age: 36 },
]
}
}
})
vm.$set(vm.student, 'gender', '男');
</script>
我们通过谁添加的?
vm
通过vm添加的,就会有响应式,vm就能看到他的变化,原理就是用我们刚才介绍的方法实现的,底层逻辑是👇来做的。用这个就会为我们的属性添加getter和setter方法
Object.defineProperty()
所以我们能检测到变化,Vue就能在你变化的时候,解析Vue模板,生成虚拟DOM,对比真实DOM,该复用的复用,然后产生页面。
ok,再看一个例子
例子二
<div id="root"></div>
<script>
const vm = new Vue({
el: '#root',
data: {
student: {
name: 'tom',
age: 18,
hobby: ['抽烟', '喝酒', '烫头'],
friends: [
{ name: 'jerry', age: 35 },
{ name: 'tony', age: 36 },
]
}
}
})
vm._data.student.gender = "男"
//也可以写成vm.student.gender="男"
//原理就是数据代理。
</script>
请问我们是利用vm添加的吗?
不是,换句话说,我们不是让vm帮我们添加的,
我们是把vm当成个靶子,往他的身上的student对象身上插了一个属性。
so,没有用vm添加,那就没有用底层的👇方法
Object.defineProperty()
自然不会有getter和setter,自然我们不能检测到变化,自然不会产生响应式,所以,你对他修改,Vue也就看不到。
尽管你有但是你是强插的,不是通过Vue/vm 依据我们说的 Object.defineProperty()添加,那你不可能有getter和setter,你没有Vue就拿不到,拿不到,就不会有虚拟DOM生成,更不会生成真实DOM,也就没有页面了。
例子三
<div id="root">
<h2>{{student.gender}}</h2>
</div>
<script>
const vm = new Vue({
el: '#root',
data: {
student: {
name: 'tom',
age: 18,
gender: '女',
hobby: ['抽烟', '喝酒', '烫头'],
friends: [
{ name: 'jerry', age: 35 },
{ name: 'tony', age: 36 },
]
}
}
})
vm._data.student.gender = "男"
</script>
和例子二很像,我们只不过是给内部写了一个gender数据,请问,这个gender:女 是不是根据Vue添加的?
答案是yes 我们写在Vue里面,最终当然是由Vue添加的。
而为什么可以修改这个值了呢?
因为Vue帮我们配置好getter和setter。
我们是写在Vue里的啊别忘了!
所以最终值可以修改。
例子三
是个判断题,
<div id="root">
<h2>习惯</h2>
<ul>
<li v-for="(h,index) in student.hobby" :key="index">
{{h}}
</li>
</ul>
</div>
<script>
const vm = new Vue({
el: '#root',
data: {
student: {
name: 'tom',
age: 18,
gender: '女',
hobby: ['抽烟', '喝酒', '烫头'],
friends: [
{ name: 'jerry', age: 35 },
{ name: 'tony', age: 36 },
]
}
}
})
vm.student.hobby[0] = '学习'
</script>
请问,这样写,页面产生的是
抽烟喝酒烫头
还是
学习喝酒烫头?
结果是抽烟喝酒烫头。
为啥?
原理很简单,再让我们去回忆一下那句话
Vue检测数据变化的底层逻辑是一个方法
Object.defineProperty()
请问,这个方法是干嘛的?
是不是对对象的属性做监测的啊?
是不是对象的属性做检测的啊?
检测的一定是对象的属性,
那么请问!
一个数组的数组单元,是对象的属性吗?
不是。
那么,你去修改它会有setter或者getter为你服务吗?
不会。
既然不会,那Vue能检测到它的变化吗?
不能
所以,检测不到变化,你改变它就毫无意义,Vue无法根据你的变化生成虚拟DOM,对比真实DOM做出页面的调整。
接下来我们看一个数组的例子。
<div id="root">
<h2>习惯</h2>
<ul>
<li v-for="(h,index) in student.hobby" :key="index">
{{h}}
</li>
</ul>
</div>
<script>
const vm = new Vue({
el: '#root',
data: {
student: {
name: 'tom',
age: 18,
gender: '女',
hobby: ['抽烟', '喝酒', '烫头'],
friends: [
{ name: 'jerry', age: 35 },
{ name: 'tony', age: 36 },
]
}
}
})
// vm.student.hobby[0] = '学习'
vm.student.hobby.push('开车');
</script>
请问这样能添加上,并且响应到页面上吗?
可以
为啥?因为我们用的是vm为我们包装的7个能改变数组自身的方法之一做的。
这是7个能改变数组自身的方法,他们被Vue包装过了,Vue所以能检测到变化,生成虚拟DOM等操作,下图可以证明,push已经被封装,修改过了。添加的功能就是可以被Vue检测到等一系列操作。
所以,总结一下。
总的来说,能不能加成响应式的,要看你没有用Vue/vm来加(指向vm强插不算,因为那时vm根本没发挥它的作用,只不过是当个靶子在往vm身上插属性罢了,)
添加的方式,三种1. Vue.set() 2. vm.$set() 3. 数组自带的7种被Vue包装的方法(都可以影响数组自身变化的那7种)。
判断属性改了会不会有效果: 要取决于你这个属性到底是不是响应式的,即 有没有getter或setter。
数组里的单元,具体到某个单元,是没有getter或settr的!!!!
为啥没有getter和settr?
回忆回忆 object.defineproperty(obj,属性名,),这是getter和setter的起源,getter和setter的起源就在object.defineproperty。而起源的时候,这个方法就是为了对象的属性名而生。
如果数组单元是个对象,对象里的属性,如果是通过vm/Vue或者数组自带的7种被Vue包装的方法添加的。是有getter和setter的!!!
Thanks for watching💕