vue3(三)基础语法 : 计算属性vs侦听器

130 阅读3分钟

一:计算属性 computed

  • 1.1 模板中的表达式虽然方便,但也只能用来做简单的操作。如果在模板中写太多逻辑,会让模板变得臃肿,难以维护。
export default {
  data() {
    return {
      author: {
        name: 'John Doe',
        books: [
          'Vue 2 - Advanced Guide',
          'Vue 3 - Basic Guide',
          'Vue 4 - The Mystery'
        ]
      }
    }
  }
}

<p>Has published books:</p>
<span>{{ author.books.length > 0 ? 'Yes' : 'No' }}</span>

因此我们推荐使用计算属性来描述依赖响应式状态的复杂逻辑。

export default {
  data() {
    return {
      author: {
        name: 'John Doe',
        books: [
          'Vue 2 - Advanced Guide',
          'Vue 3 - Basic Guide',
          'Vue 4 - The Mystery'
        ]
      }
    }
  },
  computed: {
    // 一个计算属性的 getter
    publishedBooksMessage() {
      // `this` 指向当前组件实例
      return this.author.books.length > 0 ? 'Yes' : 'No'
    }
  }
}


<p>Has published books:</p>
<span>{{ publishedBooksMessage }}</span>

watch 选项也支持把键设置成用 . 分隔的路径:

export default {
  watch: {
    // 注意:只能是简单的路径,不支持表达式。
    'some.nested.key'(newValue) {
      // ...
    }
  }
}

  • 1.2 可写计算属性

计算属性默认是只读的。当你尝试修改一个计算属性时,你会收到一个运行时警告。只在某些特殊场景中你可能才需要用到“可写”的属性,你可以通过同时提供 getter 和 setter 来创建:

export default {
  data() {
    return {
      firstName: 'John',
      lastName: 'Doe'
    }
  },
  computed: {
    fullName: {
      // getter
      get() {
        return this.firstName + ' ' + this.lastName
      },
      // setter
      set(newValue) {
        // 注意:我们这里使用的是解构赋值语法
        [this.firstName, this.lastName] = newValue.split(' ')
      }
    }
  }
}

现在当你再运行 this.fullName = 'John Doe' 时,setter 会被调用而 this.firstName 和 this.lastName 会随之更新。

二:侦听器 watch

  • 2.1 默认侦听
export default {
  data() {
    return {
      name: '',
      answer: 'Questions usually contain a question mark. ;-)'
    }
  },
  watch: {
    // 每当 question 改变时,这个函数就会执行
    name(newQuestion, oldQuestion) {
        this.getAnswer()
    }
  },
  methods: {
    getAnswer() {
      this.answer = 'hello' + this.name
    }
  }
}

<p>
  Ask yes name:
  <input v-model="name" />
</p>
<p>{{ answer }}</p>

  • 2.2 深层侦听器#

watch 默认是浅层的:被侦听的属性,仅在被赋新值时,才会触发回调函数——而嵌套属性的变化不会触发。如果想侦听所有嵌套的变更,你需要深层侦听器:

export default {
  watch: {
    someObject: {
      handler(newValue, oldValue) {
        // 若设置了 immediate: true  则 在组件实例创建时会立即调用
        
      },
      // deep 设置诶 true 为深层侦听
      deep: true, 
      // 强制立即执行回调 
      immediate: true, 
      // 回调的触发时机
      flush: 'post'
    }
  }
}

  • 2.3 即时回调的侦听器

在侦听的属性里面设置 immediate: true , 代码如上。

  • 2.4 回调的触发时机
    • 默认情况下,用户创建的侦听器回调,都会在 Vue 组件更新之前被调用。这意味着你在侦听器回调中访问的 DOM 将是被 Vue 更新之前的状态。

如果想在侦听器回调中能访问被 Vue 更新之后的 DOM,你需要指明 flush: 'post' 选项:

在侦听的属性里面设置 flush: 'post' , 代码如上。

  • 2.5 this.$watch()

我们也可以使用组件实例的 $watch() 方法来命令式地创建一个侦听器:

export default {
  created() {
    this.$watch('question', (newQuestion) => {
      // ...
    })
  }
}

如果要在特定条件下设置一个侦听器,或者只侦听响应用户交互的内容,这方法很有用。它还允许你提前停止该侦听器。

  • 2.6 停止侦听器
const unwatch = this.$watch('foo', callback)

// ...当该侦听器不再需要时
unwatch()

代码

<template> 
    <div> 
        <input v-model="firstName" />
        <br/>
        <input v-model="lastName" />
        <br/>
        fullName: {{fullName}}
        <button @click="unWatch"> unWatch </button>
    </div> 
</template>

export default {
  data() {
    return {
      firstName: 'John',
      lastName: 'Doe'
    }
  },
  computed: {
    fullName: {
      // getter
      get() {
        return this.firstName + ' ' + this.lastName
      },
      // setter
      set(newValue) {
        console.log('newValue', newValue)
      }
    }
  },
  mounted(){
      this.unwatchHanndler = this.$watch('fullName', callback)
  },
  methods: {
      callback(){
          console.log('callback')
          
      },
      unWatch(){
         this.unwatchHanndler()
      },
  
  }
}


将watch赋值给一个变量,当达到条件调用watch赋值的那个变量就可以终止监听了。

2.7 是否可以认为 写在 watch 里面的侦听由于没有赋值,不可以终止侦听?

三:计算属性 computed VS 侦听器 watch

  • 计算属性 注重变化结果,其他属性变化导致了该计算属性变化。

  • 侦听器 注重变化过程, 侦听的属性变化时要做什么事件。