Vue响应式基础

2023-01-15 10:58:11 971 转载:网络

选用选项式 API 时,会用data选项来声明组件的响应式状态。此选项的值应为返回一个对象的函数。Vue 将在创建新组件实例的时候调用此函数,并将函数返回的对象用响应式系统进行包装。此对象的所有顶层属性都会被代理到组件实例 (即方法和生命周期钩子中的this) 上。

js

exportdefault{data(){return{count:1}},// `mounted` 是生命周期钩子,之后我们会讲到mounted(){// `this` 指向当前组件实例console.log(this.count)// =; 1// 数据属性也可以被更改this.count=2}}

在演练场中尝试一下

这些实例上的属性仅在实例首次创建时被添加,因此你需要确保它们都出现在data函数返回的对象上。若所需的值还未准备好,在必要时也可以使用nullundefined或者其他一些值占位。

虽然也可以不在data上定义,直接向组件实例添加新属性,但这个属性将无法触发响应式更新。

Vue 在组件实例上暴露的内置 API 使用$作为前缀。它同时也为内部属性保留_前缀。因此,你应该避免在顶层data上使用任何以这些字符作前缀的属性。

响应式代理 vs. 原始值#

在 Vue 3 中,数据是基于JavaScript Proxy(代理)实现响应式的。使用过 Vue 2 的用户可能需要注意下面这样的边界情况:

js

exportdefault{data(){return{someObject:{}}},mounted(){constnewObject={}this.someObject=newObjectconsole.log(newObject===this.someObject)// false}}

当你在赋值后再访问this.someObject,此值已经是原来的newObject的一个响应式代理。与 Vue 2 不同的是,这里原始的newObject不会变为响应式:请确保始终通过this来访问响应式状态。

声明方法#

在 Vue School 上观看免费课程

要为组件添加方法,我们需要用到methods选项。它应该是一个包含所有方法的对象:

js

exportdefault{data(){return{count:0}},methods:{increment(){this.count++}},mounted(){// 在其他方法或是生命周期中也可以调用方法this.increment()}}

Vue 自动为methods中的方法绑定了永远指向组件实例的this。这确保了方法在作为事件监听器或回调函数时始终保持正确的this。你不应该在定义methods时使用箭头函数,因为箭头函数没有自己的this上下文。

js

exportdefault{methods:{increment:()=;{// 反例:无法访问此处的 `this`}}}

和组件实例上的其他属性一样,方法也可以在模板上被访问。在模板中它们常常被用作事件监听器:

template

;button@click="increment";{{count}};/button;

在演练场中尝试一下

在上面的例子中,increment方法会在;button;被点击时调用。

DOM 更新时机#

当你更改响应式状态后,DOM 会自动更新。然而,你得注意 DOM 的更新并不是同步的。相反,Vue 将缓冲它们直到更新周期的 “下个时机” 以确保无论你进行了多少次状态更改,每个组件都只更新一次。

若要等待一个状态改变后的 DOM 更新完成,你可以使用nextTick()这个全局 API:

js

import{nextTick}from'vue'exportdefault{methods:{increment(){this.count++nextTick(()=;{// 访问更新后的 DOM})}}}

深层响应性#

在 Vue 中,状态都是默认深层响应式的。这意味着即使在更改深层次的对象或数组,你的改动也能被检测到。

js

exportdefault{data(){return{obj:{nested:{count:0},arr:['foo','bar']}}},methods:{mutateDeeply(){// 以下都会按照期望工作this.obj.nested.count++this.obj.arr.push('baz')}}}

你也可以直接创建一个浅层响应式对象。它们仅在顶层具有响应性,一般仅在某些特殊场景中需要。

有状态方法#

在某些情况下,我们可能需要动态地创建一个方法函数,比如创建一个预置防抖的事件处理器:

js

import{debounce}from'lodash-es'exportdefault{methods:{// 使用 Lodash 的防抖函数click:debounce(function(){// ... 对点击的响应 ...},500)}}

不过这种方法对于被重用的组件来说是有问题的,因为这个预置防抖的函数是有状态的:它在运行时维护着一个内部状态。如果多个组件实例都共享这同一个预置防抖的函数,那么它们之间将会互相影响。

要保持每个组件实例的防抖函数都彼此独立,我们可以改为在created生命周期钩子中创建这个预置防抖的函数:

js

exportdefault{created(){// 每个实例都有了自己的预置防抖的处理函数this.debouncedClick=_.debounce(this.click,500)},unmounted(){// 最好是在组件卸载时// 清除掉防抖计时器this.debouncedClick.cancel()},methods:{click(){// ... 对点击的响应 ...}}}
*特别说明:本文来自网络,如有侵权,请联系我们删除,非常感谢!