Vue应用的底层原理

vue深入响应式原理

  • 讲到Vue的响应式原理,我们可以从它的兼容性说起,Vue不支持IE8以下版本的浏览器,因为Vue是基于 Object.defineProperty 来实现数据响应的,而 Object.defineProperty 是 ES5 中一个无法 shim 的特性,这也就是为什么 Vue 不支持 IE8 以及更低版本浏览器的原因;Vue通过Object.defineProperty的 getter/setter 对收集的依赖项进行监听,在属性被访问和修改时通知变化,进而更新视图数据;受现代JavaScript 的限制 (以及废弃 Object.observe),Vue不能检测到对象属性的添加或删除。由于 Vue 会在初始化实例时对属性执行 getter/setter 转化过程,所以属性必须在 data 对象上存在才能让Vue转换它,这样才能让它是响应的。

深入响应式原理:

  1. 当视图模型(VM)中的数据模型(M)发生改变时, 视图(V)就会进行更新
  2. Vue通过watcher将data中的属性全部使用Object.definePropery编程getter和setter,当属性值发生
    改变的时候, 就会触发, 然后wather就会触发, 告诉视图(V)进行重新渲染
    • 数据必须放在data选项中才能进行深入响应式
底层原理:

核心使用的是es5的一个方法,这个方法不支持ie8以及以下

Object.defineProperty(obj,obj.attr,descriptor)
参数:

obj:要在其上定义属性的对象。
prop(=obj.attr):要定义或修改的属性的名称。
descriptor:将被定义或修改的属性描述符。它是一个对象, 这个对象有哪些构成?

  • configurable: 决定了对象的key是否可删除
  • enumerable: 决定了对象是否可遍历(枚举)
  • writeable: 决定了对象的key的value是否可修改
存储器:

get函数 ----起了个名字getter 设置当前对象的key的初始值
set函数 ----起了个名字setter 修改当前对象的key的值

总结:
  1. 什么是深入响应式原理?
    深入响应式原理是利用了数据劫持和订阅发布的模式, 当数据模型发生改变的时候, 视图就会响应的进行更新, 那么深入响应式原理是利用es5的Object.defineProperty中个getter/setter来进行数据的劫持的

    名称解释:
    数据劫持: Object.defineProperty中的getter/setter , 然后在执行watcher
    订阅发布:事件(自定义事件)

  • 订阅: 事件的声明 vm.$on
  • 发布: 事件的触发 vm.$emit

非响应式情况

解释
  • 在vm模型的data外定义的属性, 就是非响应式属性, 非响应式属性, 属性值更新, 视图不会更新
非响应式属性如何变成响应式属性

思维: 将非响应式属性合并到响应式属性身上
解决: 利用了Vue提供的 Vue.set/this.$set(vm.dataattr,prop,value)

Vue.set底层原生是什么?

Object.assign(目标对象,对象1, 对象2,对象3)

来一波整体案例代码解析:

<body>
<div id="app">
<h3> {{msg}} </h3>
<h3> {{num}} </h3>
<button @click = "setHandler">
点击
</button>
</div>
</body>
<script>
Vue.config.silent = true
var vm = new Vue({
el: '#app',
data: {
msg: 'hello vue.js',
list: {
id: 1
}
},
methods: {
setHandler(){
this.$set(this.list,'name','张三')
}
},
watch: {
/* watch中存放的是方法, 方法名就是M(data选项) */
msg(){
console.log('msg改变了')
}
}
})
console.log('====================================');
console.log(vm);
console.log('====================================');
// vm.num = 1000 //非响应式的


/* Vue.set(vm.list,'num',1000)
console.log(vm) */
/* var obj = {
name:'张三'
}
Object.defineProperty(obj,'name',{
//存储器
get(){
//要求必须有返回值
return '三三'
},
set(value){ //value就是修改后的对象的key的value
console.log('set')
console.log('====================================');
console.log(value);
console.log('====================================');
document.querySelector('#app').innerHTML = value
}
// 监听机制
})
obj.name = 'Aaa'
// document.querySelector('#app').innerHTML = obj.name */
</script>

vue双向数据绑定原理

vue的双向绑定是由数据劫持结合发布者-订阅者模式实现的,那么什么是数据劫持?vue是如何进行数据劫持的?说白了就是通过Object.defineProperty()来劫持对象属性的setter和getter操作,在数据变动时做你想要做的事情.。

1. 效果

数据改 , 视图更
视图改, 数据更

2. 实现

使用v-model实现

3. 缺点

v-model默认绑定value属性, 所以v-model只能在表单使用

4. 原理

1. 为什么数据能直接在视图显示

v-model默认绑定了DOM对象的value属性, 当它初次绑定的时候,
就会触发getter,watcher就会触发, watcher通知Vue生成新的VDOM树,
再通过render函数进行渲染,生成真实DOM

2. 为什么视图修改数据就会修改

当视图修改是, 意味着DOM的value属性值改变,就会触发setter,watcher监听机制就会执行
watcher通知Vue生成新的VDOM树,再通过render函数进行渲染,生成真实DOM

代码示例

<body>
<div id="app">
<input type="text" v-model = "msg">
</div>
</body>

<script>
new Vue({
         el: '#app',
          data: {
                  msg: 'hello vue.js'
                   }
           })
</script>

watch 监听

(使用这个 属性,可以监视 data 中指定数据的变化,然后触发这个 watch 中对应的 function 处理函数该方法可以不用绑定事件)

watch
1. 作用:

用来监听数据的变换, 当数据模型 (data选项 M)发生改变时, watch就会触发

2. 使用

两种用法:

  1. key的value值是一个函数 普通
new Vue({
watch: {
key(value,oldvalue){}
}
})
  1. key的value值是一个对象 高级
new Vue({
watch: {
key: {
deep: true/false 深入监听,
handler(value,oldvalue){} // 监听的处理函数
}
}
})
watch中的key指的就是data选项中key
现在我们来看几个关于监听的案例:
1。首先是在两个输入框输入我们的姓跟名,然后在第三输入框实时输出我们输入的姓和名的全称

解决:

<body>
<div id="app">
<div>
姓: <input type="text" v-model = "firstName">
</div>
<div>
名: <input type="text" v-model = "lastName">
</div>
<div>
全称: <input type="text" v-model = "fullName">
</div>
</div>
</body>
<script>

new Vue({
el: '#app',
data: {
firstName: '',
lastName: '',
fullName: ''
},
watch: {
firstName(val){
this.fullName = val + this.lastName
},
lastName(val){
this.fullName = this.firstName + val
},
fullName(val){
console.log( val )
this.firstName = val.slice(0,1)
this.lastName = val.slice(1)
}
}
})
</script>
computed

在 computed 中,可以定义一些 属性,这些属性,叫做 【计算属性】, 计算属性的本质,就是 一个方法,只不过我们在使用 这些计算属性的时候,是把它们的名称直接当作属性来使用的;并不会把 计算属性当作方法去调用;computed和methods平级

  • computed不会因为页面中调用几次函数去执行几次,只会根据函数执行来调用函数

注意1: 计算属性,在引用的时候,一定不要加 () 去调用,直接把它当作普通 属性去使用就好了;
注意2: 只要 计算属性,这个 function 内部,所用到的 任何 data 中的数据发送了变化,就会立即重新计算 这个 计算属性的值
注意3:计算属性的求值结果,会被缓存起来,方便下次直接使用; 如果 计算属性方法中,所有的任何数据,都没有发生过变化,则不会重新对计算属性求值;

watch、computed和methods之间的对比
  • computed属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。主要当作属性来使用;
  • methods方法表示一个具体的操作,主要书写业务逻辑;
  • watch一个对象,键是需要观察的表达式,值是对应回调函数。主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操作;可以看作是computed和methods的结合体;

  • ** methods: 事件
    ** computed:
    1. 有逻辑 2. 要像变量一样使用 , 这个时候选computed
      ** watch:
    2. 有异步操作 2. 开销较大

猜你喜欢

转载自blog.csdn.net/xuwei1215225/article/details/89399995