vue-响应式基础
创始人
2025-06-01 04:17:42

vue-响应式基础

  • 声明响应式状态
    • 响应式代理 vs. 原始值
  • 声明方法
    • DOM 更新时机
    • 深层响应性
      • 有状态方法

声明响应式状态

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

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

虽然也可以不在 data 上定义,直接向组件实例添加新属性,但这个属性将无法触发响应式更新。
Vue 在组件实例上暴露的内置 API 使用 $ 作为前缀。它同时也为内部属性保留 _ 前缀。因此,你应该避免在顶层 data 上使用任何以这些字符作前缀的属性。

响应式代理 vs. 原始值

在 Vue 3 中,数据是基于 JavaScript Proxy(代理) 实现响应式的。

export default {data() {return {someObject: {}}},mounted() {const newObject = {}this.someObject = newObjectconsole.log(newObject === this.someObject) // false}
}

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

声明方法

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

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

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

DOM 更新时机

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

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

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

深层响应性

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

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

有状态方法

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

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

不过这种方法对于被重用的组件来说是有问题的,因为这个预置防抖的函数是 有状态的:它在运行时维护着一个内部状态。如果多个组件实例都共享这同一个预置防抖的函数,那么它们之间将会互相影响。
要保持每个组件实例的防抖函数都彼此独立,我们可以改为在 created 生命周期钩子中创建这个预置防抖的函数:

export default {created() {// 每个实例都有了自己的预置防抖的处理函数this.debouncedClick = _.debounce(this.click, 500)},unmounted() {// 最好是在组件卸载时// 清除掉防抖计时器this.debouncedClick.cancel()},methods: {click() {// ... 对点击的响应 ...}}
}

相关内容

热门资讯

科技通报“乐乐互娱炸金花究竟是... 亲.乐乐互娱炸金花这款游戏是可以开挂的,确实是有挂的,通过添加客服【4830828】很多玩家在这款游...
玩家必看“打两圈麻将到底有挂吗... 您好:打两圈麻将这款游戏可以开挂,确实是有挂的,需要软件加微信【4830828】很多玩家在这款游戏中...
重大通报“阿拉游戏牛牛其实真有... 您好:阿拉游戏牛牛这款游戏可以开挂,确实是有挂的,需要了解加客服微信【4194432】很多玩家在阿拉...
玩家攻略「小南娱乐」辅助挂万能... 玩家攻略「小南娱乐」辅助挂万能器!必胜开挂神器亲.小南娱乐这款游戏是可以开挂的,确实是有挂的,通过添...
实测教程"友乐是不是... 您好:这款游戏可以开挂,确实是有挂的需要了解加客服微信【44183365】很多玩家在这款游戏中打牌都...