当前位置:   article > 正文

Vue——响应式基础_vue响应式

vue响应式

目录

 一、声明响应式状态

响应式代理 vs. 原始值

二、声明方法

① DOM 更新时机

② 深层响应性

③ 有状态方法


 一、声明响应式状态

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

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

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

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

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

响应式代理 vs. 原始值

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

  1. export default {
  2. data() {
  3. return {
  4. someObject: {}
  5. }
  6. },
  7. mounted() {
  8. const newObject = {}
  9. this.someObject = newObject
  10. console.log(newObject === this.someObject) // false
  11. }
  12. }

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

二、声明方法

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

  1. export default {
  2. data() {
  3. return {
  4. count: 0
  5. }
  6. },
  7. methods: {
  8. increment() {
  9. this.count++
  10. }
  11. },
  12. mounted() {
  13. // 在其他方法或是生命周期中也可以调用方法
  14. this.increment()
  15. }
  16. }

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

  1. export default {
  2. methods: {
  3. increment: () => {
  4. // 反例:无法访问此处的 `this`!
  5. }
  6. }
  7. }

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

<button @click="increment">{{ count }}</button>

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

① DOM 更新时机

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

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

  1. import { nextTick } from 'vue'
  2. export default {
  3. methods: {
  4. increment() {
  5. this.count++
  6. nextTick(() => {
  7. // 访问更新后的 DOM
  8. })
  9. }
  10. }
  11. }

② 深层响应性

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

  1. export default {
  2. data() {
  3. return {
  4. obj: {
  5. nested: { count: 0 },
  6. arr: ['foo', 'bar']
  7. }
  8. }
  9. },
  10. methods: {
  11. mutateDeeply() {
  12. // 以下都会按照期望工作
  13. this.obj.nested.count++
  14. this.obj.arr.push('baz')
  15. }
  16. }
  17. }

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

③ 有状态方法

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

  1. import { debounce } from 'lodash-es'
  2. export default {
  3. methods: {
  4. // 使用 Lodash 的防抖函数
  5. click: debounce(function () {
  6. // ... 对点击的响应 ...
  7. }, 500)
  8. }
  9. }

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

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

  1. export default {
  2. created() {
  3. // 每个实例都有了自己的预置防抖的处理函数
  4. this.debouncedClick = _.debounce(this.click, 500)
  5. },
  6. unmounted() {
  7. // 最好是在组件卸载时
  8. // 清除掉防抖计时器
  9. this.debouncedClick.cancel()
  10. },
  11. methods: {
  12. click() {
  13. // ... 对点击的响应 ...
  14. }
  15. }
  16. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/259233?site
推荐阅读
相关标签
  

闽ICP备14008679号