首页 > 其他分享 >Vue 3.0 计算属性和侦听器

Vue 3.0 计算属性和侦听器

时间:2024-03-01 09:44:06浏览次数:35  
标签:Vue return 3.0 vm 侦听器 books 计算 属性

#计算属性

模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。例如,有一个嵌套数组对象:

 

  1. Vue.createApp({
  2. data() {
  3. return {
  4. author: {
  5. name: 'John Doe',
  6. books: [
  7. 'Vue 2 - Advanced Guide',
  8. 'Vue 3 - Basic Guide',
  9. 'Vue 4 - The Mystery'
  10. ]
  11. }
  12. }
  13. }
  14. })

我们想根据 author 是否已经有一些书来显示不同的消息

 

  1. <div id="computed-basics">
  2. <p>Has published books:</p>
  3. <span>{{ author.books.length > 0 ? 'Yes' : 'No' }}</span>
  4. </div>

此时,模板不再是简单的和声明性的。你必须先看一下它,然后才能意识到它执行的计算取决于 author.books。如果要在模板中多次包含此计算,则问题会变得更糟。

所以,对于任何包含响应式数据的复杂逻辑,你都应该使用计算属性

 

#基本例子

 

  1. <div id="computed-basics">
  2. <p>Has published books:</p>
  3. <span>{{ publishedBooksMessage }}</span>
  4. </div>

 

  1. Vue.createApp({
  2. data() {
  3. return {
  4. author: {
  5. name: 'John Doe',
  6. books: [
  7. 'Vue 2 - Advanced Guide',
  8. 'Vue 3 - Basic Guide',
  9. 'Vue 4 - The Mystery'
  10. ]
  11. }
  12. }
  13. },
  14. computed: {
  15. // 计算属性的 getter
  16. publishedBooksMessage() {
  17. // `this` points to the vm instance
  18. return this.author.books.length > 0 ? 'Yes' : 'No'
  19. }
  20. }
  21. }).mount('#computed-basics')

Result: 点击此处实现

 

这里声明了一个计算属性 publishedBooksMessage

尝试更改应用程序 data 中 books 数组的值,你将看到 publishedBooksMessage 如何相应地更改。

你可以像普通属性一样将数据绑定到模板中的计算属性。Vue 知道 vm.publishedBookMessage 依赖于 vm.author.books,因此当 vm.author.books 发生改变时,所有依赖 vm.publishedBookMessage 绑定也会更新。而且最妙的是我们已经声明的方式创建了这个依赖关系:计算属性的 getter 函数没有副作用,这使得更易于测试和理解。

 

#计算属性缓存 vs 方法

你可能已经注意到我们可以通过在表达式中调用方法来达到同样的效果:

 

  1. <p>{{ calculateBooksMessage() }}</p>

 

  1. // 在组件中
  2. methods: {
  3. calculateBooksMessage() {
  4. return this.author.books.length > 0 ? 'Yes' : 'No'
  5. }
  6. }

我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的反应依赖关系缓存的。计算属性只在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要 author.books 还没有发生改变,多次访问 publishedBookMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。

这也同样意味着下面的计算属性将不再更新,因为 Date.now () 不是响应式依赖:

 

  1. computed: {
  2. now() {
  3. return Date.now()
  4. }
  5. }

相比之下,每当触发重新渲染时,调用方法将总会再次执行函数。

我们为什么需要缓存?假设我们有一个性能开销比较大的计算属性 list,它需要遍历一个巨大的数组并做大量的计算。然后我们可能有其他的计算属性依赖于 list。如果没有缓存,我们将不可避免的多次执行 list 的 getter!如果你不希望有缓存,请用 method 来替代。

 

#计算属性的 Setter

计算属性默认只有 getter,不过在需要时你也可以提供一个 setter:

 

  1. // ...
  2. computed: {
  3. fullName: {
  4. // getter
  5. get() {
  6. return this.firstName + ' ' + this.lastName
  7. },
  8. // setter
  9. set(newValue) {
  10. const names = newValue.split(' ')
  11. this.firstName = names[0]
  12. this.lastName = names[names.length - 1]
  13. }
  14. }
  15. }
  16. // ...

现在再运行 vm.fullName = 'John Doe' 时,setter 会被调用,vm.firstName 和 vm.lastName 也会相应地被更新。

 

#侦听器

虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。

例如:

 

  1. <div id="watch-example">
  2. <p>
  3. Ask a yes/no question:
  4. <input v-model="question" />
  5. </p>
  6. <p>{{ answer }}</p>
  7. </div>

 

  1. <!-- 因为 AJAX 库和通用工具的生态已经相当丰富,Vue 核心代码没有重复 -->
  2. <!-- 提供这些功能以保持精简。这也可以让你自由选择自己更熟悉的工具。 -->
  3. <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/axios.min.js" rel="external nofollow" ></script>
  4. <script>
  5. const watchExampleVM = Vue.createApp({
  6. data() {
  7. return {
  8. question: '',
  9. answer: 'Questions usually contain a question mark. ;-)'
  10. }
  11. },
  12. watch: {
  13. // whenever question changes, this function will run
  14. question(newQuestion, oldQuestion) {
  15. if (newQuestion.indexOf('?') > -1) {
  16. this.getAnswer()
  17. }
  18. }
  19. },
  20. methods: {
  21. getAnswer() {
  22. this.answer = 'Thinking...'
  23. axios
  24. .get('https://yesno.wtf/api')
  25. .then(response => {
  26. this.answer = response.data.answer
  27. })
  28. .catch(error => {
  29. this.answer = 'Error! Could not reach the API. ' + error
  30. })
  31. }
  32. }
  33. }).mount('#watch-example')
  34. </script>

结果: 点击此处实现

 

在这个示例中,使用 watch 选项允许我们执行异步操作 (访问一个 API),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。

除了 watch 选项之外,你还可以使用命令式的 vm.$watch API

 

#计算属性 vs 侦听器

Vue 提供了一种更通用的方式来观察和响应当前活动的实例上的数据变动:侦听属性。当你有一些数据需要随着其它数据变动而变动时,你很容易滥用 watch——特别是如果你之前使用过 AngularJS。然而,通常更好的做法是使用计算属性而不是命令式的 watch 回调。细想一下这个例子:

 

  1. <div id="demo">{{ fullName }}</div>

 

  1. const vm = Vue.createApp({
  2. data() {
  3. return {
  4. firstName: 'Foo',
  5. lastName: 'Bar',
  6. fullName: 'Foo Bar'
  7. }
  8. },
  9. watch: {
  10. firstName(val) {
  11. this.fullName = val + ' ' + this.lastName
  12. },
  13. lastName(val) {
  14. this.fullName = this.firstName + ' ' + val
  15. }
  16. }
  17. }).mount('#demo')

上面代码是命令式且重复的。将它与计算属性的版本进行比较:

 

  1. const vm = Vue.createApp({
  2. data() {
  3. return {
  4. firstName: 'Foo',
  5. lastName: 'Bar'
  6. }
  7. },
  8. computed: {
  9. fullName() {
  10. return this.firstName + ' ' + this.lastName
  11. }
  12. }
  13. }).mount('#demo')

好得多了,不是吗?

标签:Vue,return,3.0,vm,侦听器,books,计算,属性
From: https://www.cnblogs.com/wangtiantian/p/18046261

相关文章

  • 前端学习-vue视频学习003-setup(重要)
    学习教程-尚硅谷视频将原vue2的格式改为vue3---使用setup要点:this在vue3中被弱化,setup函数中不能使用this定义数据时,如果不是响应式的(暂时还不是很理解响应式),不会触发页面的变化vue3支持一个标签直接写多次,如<template><Person/><Person/><Person/></t......
  • JS/Vue 学习小记
    可能要写点轮子。。。先学学前端知识吧,记录一下。遍历:for(letiofS){i...}for(letiinS){S[i]...}JS是弱类型的语言。目前感觉到的特性有:数组不同元素可以是不同类型的函数返回值不需要声明,直接functionF()就可以JS中对象用大括号表示,成员可以是各种类型,包......
  • Vuex系列之(七)getters配置项
    getters配置项概念:getters配置项并不是必须要使用的,当state中的数据需要经过加工后再使用时,可以使用getters加工。应用场景:运算逻辑复杂而且需要复用,用于抽取基于state中数据的公共运算在store.js中追加getters配置......//准备getters——用于加工state中的数据cons......
  • Vuex系列之(六)Vuex Devtools
    VuexDevtools由于Vue和Vuex都是由官方团队开发的,Vue的Devtools和Vuex的Devtools是合二为一的组件页签、Vuex页签、事件页签事件页签:观察自定义事件和全局事件总线中的事件VuexDevtools仅仅捕获mutations中的动作,actions中的动作是不会捕获的context:actions中的上下文......
  • Vuex系列之(五)求和案例
    求和案例//index.jsimportVuefrom'vue'importVuexfrom'vuex'Vue.use(Vuex)constactions={ //对于不包含业务逻辑也不进行Ajax请求转发的操作可以不经过actions,直接调用mutations中的方法即可 //jia(context,value){ // console.log('actions被调用了',conte......
  • Vue UI组件库系列之概述
    概述UI组件库:提供了一些如输入框、布局、按钮等在网页UI布局中常用的元素,并将这些元素以组件的形式提供给我们。一般会说UI组件库是基于哪个框架【Vue/React/...】的、PC端/移动端什么项目适合用UI组件库,什么项目不适合?【UI组件库的应用场景】不适合【页面中包含很多定制化、......
  • VuePress
    VuePress一、部署创建项目文件夹在任意目录下创建文件夹mydocs注:路径中不要包含中文安装VuePressnpminstallvuepress注:如需全局安装,请执行npminstall-gvuepress初始化项目在项目文件夹下打开命令行,执行npminit-y创建必要的目录mydocs├───docs......
  • Vuex系列之(九)模块化和命名空间
    模块化+命名空间Vuex中的高级写法:Vuex的模块化编码把不同分类【业务分类不同,比如订单管理类的和商品管理类的】的mutation放在不同位置模块化编码的最终目标:对actions、mutations、state、getters中的内容进行分类整理1.Vuex模块化编码的步骤根据业务分类划分模块,在store......
  • Vue Router系列之(一)路由
    路由1.SPA应用单页Web应用(singlepagewebapplication,SPA)。整个应用只有一个完整的页面(index.html)。点击页面中的导航链接不会刷新页面,页面不会跳转,只会做页面的局部更新。数据需要通过ajax请求获取。注:多页面应用,多个页面来回跳来跳去2.什么是路由?一个路由(route......
  • Vue CLI 系列之(十九)总结
    总结父组件=》子组件【props】子组件=》父组件【函数类型的props、组件自定义事件】孙组件=》父组件【全局事件总线】在组件中引入库时,顺序是这样的第三方库自己写的组件所有开发人员都要用的样式配置在App中当标签中的属性过多时,可进行改写,改写时通常将原生属性放......