如果阅读有疑问的话,欢迎评论或私信!!
本人会很热心的阐述自己的想法!谢谢!!!
文章目录
- 响应式基础
- 声明响应式状态(属性)
- 响应式代理 vs 原始值
- 声明方法
- 深层响应性
- DOM 更新时机
- 有状态方法
响应式基础
在认识vue之前,就可能许多人听说vue的响应式系统的诱人之处。
声明响应式状态(属性)
在vue中,可以通过data选项
声明一些带有响应式的数据。data选项中需要return出一个对象
,包含你所要在该页面添加的所有响应式数据。Vue会在创建当前实例时对你返回的对象使用响应式系统包装
。并且,这些数据可以在当前实例中使用this
找到,并进行修改。例如:
<template><img :[orderSrc]="imgSrc" />
</template><script>
export default {data() {var imgSrc = "/src/components/icons/newImg.gif";var orderSrc = "src";return {imgSrc,orderSrc,};},mounted(){console.log(this.imgSrc) //控制台输出‘/src/components/icons/newImg.gif’}
};
在vue响应式系统中,vue会在首次创建实例时对data数据进行响应式包装,所以
如果你要响应式的数据
,那么需要确保已经在data中声明
。至于里面的值可以是null或undefined
这些占位符。
data中命名规范:vue中,由于内置API使用了$
作为前缀,并且也为内部属性保留了_
前缀,所以我们在data中声明数据时,要避免使用这些前缀,防止与内置属性冲突
。
响应式代理 vs 原始值
在vue3中,vue使用的是JavaScript中的Proxy代理来实现响应式的。我们先来看一段vue2
中的代码:
<script>export default{data(){var obj = {id:1}return {obj}},mounted(){const newObj = {}this.obj = newObj;console.log(this.obj) //{__ob__: Observer}console.log(newObj) //{__ob__: Observer}console.log(this.obj === newObj) //true}}
</script>
接下来再看一下vue3
中的效果:
<script>export default{data(){var obj = {id:1}return {obj}},mounted(){const newObj = {}this.obj = newObj;console.log(this.obj) //Proxy {}console.log(newObj) //{}console.log(this.obj === newObj) //false}}
</script>
vue3中与vue2不同的是:在vue2
中,newObj是响应式数据
。而在vue3
中,该数据在mouted中定义的newObj就不再是响应式数据
。所以,请确保在其他地方使用this访问响应式状态
声明方法
在vue中,所有的方法都应该生声明在methods对象中,因为只有在methods对象中的this
才会指向当前组件实例
。所以,为了我们的this可以正常指向,所有的方法都应该声明在methods对象中
。而且不应该
在methods对象中使用ES6中的箭头函数
!关于this的更多信息可以点击该链接查询。请注意,这里methods与data和mounted不同的是,methods是一个对象
,而不是一个方法!
我们先来看一下正常的this里面包括什么:
<script>
export default {data() {var objAttr = {id: 123,class: "a",};return {objAttr};},methods:{init(){console.log(this) //Proxy {init: ƒ, …}console.log(this.objAttr) //Proxy {id: 123, class: 'a'}console.log(this.objAttr.id) //123}},mounted(){this.init();}
};
</script>
接下来试一下在箭头函数中的this指向是什么:
<script>
export default {data() {var objAttr = {id: 123,class: "a",};return {objAttr};},methods:{init:()=>{console.log(this) //undefined}},mounted(){this.init();}
};
</script>
所以尽量不要在methods中使用箭头函数!
深层响应性
vue中的响应式是进行深度处理过的,所以不管某个属性
位于哪个对象
,只要在data中进行声明,都可以被响应式处理。
DOM 更新时机
在学习这一节时,我们需要知道JavaScript中的异步处理机制以及ES7中的async语法之后,再来深入的理解。这里简单的说一下,JavaScript中异步有事件循环和任务队列,事件循环通常称为宏任务,任务队列通常称为微任务。我们使用setTimeout来解释这两个名词。来看下面这个代码:
setTimeout1(setTimeout2();
,1000)setTimeout3(setTimeout4();
,1000)
这里setTimeout1和setTimeout3位于事件循环中,而setTimeout2是和1处在同一个任务队列中,3和4处在同一个任务队列中。
如果可以理解上面这个概念的话,就可以继续学习vue中的DOM更新时机了!
vue中会把每次更新时机设置为一个事件循环,所以我们在需要等待DOM更新之后再进行操作的时候,可以使用vue中的nextTick函数,它会等待当前事件循环结束之后再执行接下来的任务。例如vue官方文档这串代码:
import { nextTick } from 'vue'export default {methods: {async increment() {this.count++await nextTick() // await中文指等待,也就是在上面事件循环结束之后再执行nextTick// 现在 DOM 已经更新了}}
}
有状态方法
有时候我们想要创建一个动态的方法
多次复用
,但是同时我们vue组件
也需要被重用
。这个时候就会引起一些问题:我们创建的这个方法内部
是有一个自己的状态
,比如自己的属性
,自己的方法名
。如果这些被重用,那么在执行代码的时候会产生不同结果
。
比如这个方法中有一个名为timer
的定时器,那么我们在进行复用的时候这个timer可能会有多个
,之后我们再想销毁timer时,我们不知道哪一个需要被销毁。
vue官方文档中也为我们提供了一种解决方法:在created函数,也就是实例创建的时候将有状态的方法复制在自己的实例中,并且在实例销毁时(unmounted)删除该方法。