【Vue.js】 计算属性和侦听器的学习以及用法【大结合】。

简介: 学习计算属性和侦听器的使用方法。

目录


1. 计算属性的基本使用


2. 计算属性的复杂使用


3. 计算属性的setter和getter


4. 计算属性和methods的对比


5. Vue计算属性与侦听器总结


1. 计算属性的基本使用

现在有变量姓氏和名字,要得到完整的名字。


使用Mastache语法拼接

{{firstName+ " " + lastName}}

使用方法methods

{{getFullName()}}

使用计算属性computed

{{fullName}}

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>计算属性的基本使用</title>
</head>
<body>
  <div id="app">
    <!-- Mastache语法 -->
    <h2>{{firstName+ " " + lastName}}</h2>
    <!-- 方法 -->
    <h2>{{getFullName()}}</h2>
    <!-- 计算属性 -->
    <h2>{{fullName}}</h2>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el:"#app",
      data:{
        firstName:"skt t1",
        lastName:"faker"
      },
      computed: {
        fullName:function(){
          return this.firstName + " " + this.lastName
        }
      },
      methods: {
        getFullName(){
          return this.firstName + " " + this.lastName
        }
      },
    })
  </script>
</body>
</html>


例子中计算属性computed看起来和方法似乎一样,只是方法调用需要使用(),而计算属性不用,方法取名字一般是动词见名知义,而计算属性是属性是名词,但这只是基本使用。


2. 计算属性的复杂使用


现在有一个数组数据books,里面包含许多book对象,数据结构如下:

books:[
          {id:110,name:"JavaScript从入门到入土",price:119}, 
          {id:111,name:"Java从入门到放弃",price:80},
          {id:112,name:"编码艺术",price:99},
          {id:113,name:"代码大全",price:150},
        ]


要求计算出所有book的总价格totalPrice。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>计算属性的复杂使用</title>
</head>
<body>
  <div id="app">
    <h2>总价格:{{totalPrice}}</h2>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el:"#app",
      data:{
        books:[
          {id:110,name:"JavaScript从入门到入土",price:119},
          {id:111,name:"Java从入门到放弃",price:80},
          {id:112,name:"编码艺术",price:99},
          {id:113,name:"代码大全",price:150},
        ]
      },
      computed: {
        totalPrice(){
          let result= 0;
          for (let i = 0; i < this.books.length; i++) {
            result += this.books[i].price;
          }
          return result
        }
      }
    })
  </script>
</body>
</html>
<!DOCTYPE html>
<html>
  <head>
  <meta charset="utf-8">
  <title></title>
  <style>
  </style>
  </head>
  <body>
  <div id="app">
    <h2>{{firstName+'--'+lastName}}</h2>
    <h2>{{getFullName()}}</h2>
    <h2>{{FullName}}</h2>
    <h2>总价格:{{totalPrice}}</h2>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    const vm = new Vue({
    el: '#app',
    data: {
      firstName: "Lee",
      lastName: "si",
      books: [{
        id: 110,
        name: "JavaScript从入门到入土",
        price: 1
      },
      {
        id: 111,
        name: "Java从入门到放弃",
        price: 8
      },
      {
        id: 112,
        name: "编码艺术",
        price: 2
      },
      {
        id: 113,
        name: "代码大全",
        price: 4
      },
      ]
    },
    methods: {
      getFullName() {
      return this.firstName + '--' + this.lastName
      }
    },
    computed: {
      /* FullName() {
      return this.firstName + '--' + this.lastName
      } */
      FullName: function() {
      return this.firstName + '--' + this.lastName
      },
      /*1.  for循环 totalPrice: function() {
      let total  = 0;
      for (let i = 0; i < this.books.length; i++) {
                           total  += this.books[i].price
      }
      return total 
      } */
      /*2. forEach */
      /* totalPrice: function() {
      let total = 0;
      this.books.forEach((item) => {
        total += item.price
      })
      return total
      } */
      /*3. for in */
      /* totalPrice: function() {
      let total = 0;
      for(let i in this.books){
        total += this.books[i].price
      }
      return total
      } */
      /*4. for of */
      /* totalPrice: function() {
      let total = 0;
      for(let value of this.books){
        total += value.price
      }
      return total
      } */
      /*5. map */
      /* totalPrice: function() {
      let total = 0;
      this.books.map((item)=>{
        total += item.price
      })
      return total
      } */
      /*6. filter */
      /* totalPrice: function() {
      let total = 0;
      this.books.filter((item)=>{
        console.log(item);
        total += item.price
      })
      return total
      } */
      /*7. reduce */
      /* totalPrice: function() {
      return this.books.reduce((currenttotal, item) => {
        console.log(item);
        return currenttotal + item.price
      }, 0)
      } */
      /* totalPrice: function() {
      return this.books.reduce((currenttotal, item) => {
        console.log(item);
        return currenttotal + item.price
      }, 0)
      } */
      /* totalPrice(){
      return this.books.reduce((currenttotal, item)=>currenttotal + item.price,0)
      } */
    }
    })
  </script>
  </body>
</html>


获取每一个book对象的price累加,当其中一个book的价格发生改变时候,总价会随之变化。


3. 计算属性的setter和getter


在计算属性中其实是由这样两个方法setter和getter。

computed: {
        fullName:{
          //计算属性一般没有set方法,只读属性
          set:function(newValue){
            console.log("-----")
            const names = newValue.split(" ")
            this.firstName = names[0]
            this.lastName = names[1]
          },
          get:function(){
            return this.firstName + " " + this.lastName
          }
        }
      }


但是计算属性一般没有set方法,只读属性,只有get方法,但是上述中newValue就是新的值,也可以使用set方法设置值,但是一般不用。


computed的getter/setter


请看如下代码:

<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Vue计算属性的getter和setter</title>
        <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
    </head>
    <body>
        <div id="app">
            <h1>计算属性:computed的getter/setter</h1>
            <h2>fullName</h2>
            {{fullName}}
            <h2>firstName</h2>
            {{firstName}}
            <h2>lastName</h2>
            {{lastName}}
        </div>
        <script>
            var app = new Vue({
                el:"#app",
                data:{
                firstName:"zhang",
                lastName:"san",
                },
                computed: {
                    fullName:{
                        get:function(){
                            return this.firstName+" "+this.lastName
                        },
                        set:function(value){
                            var list = value.split(' ');
                            this.firstName=list[0]
                            this.lastName=list[1]
                        }
                    }
                },
            });
        </script>
    </body>
    </html>


初始化

image.png


修改fullName

image.png



结论


- 通过这种方式,我们可以在改变计算属性值的同时也改变和计算属性相关联的属性值。


4. 计算属性和methods的对比


直接看代码,分别使用计算属性和方法获得fullName的值。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>计算属性和methods的对比</title>
</head>
<body>
  <div id="app">
    <!-- methods,即使firstName和lastName没有改变,也需要再次执行 -->
    <h2>{{getFullName()}}</h2>
    <h2>{{getFullName()}}</h2>
    <h2>{{getFullName()}}</h2>
    <h2>{{getFullName()}}</h2>
    <!-- 计算属性有缓存,只有关联属性改变才会再次计算 -->
    <h2>{{fullName}}</h2>
    <h2>{{fullName}}</h2>
    <h2>{{fullName}}</h2>
    <h2>{{fullName}}</h2>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el:"#app",
      data:{
        firstName:"skt t1",
        lastName:"faker"
      },
      computed: {
        fullName(){
          console.log("调用了计算属性fullName");
          return this.firstName + " " + this.lastName
        }
      },
      methods: {
        getFullName(){
          console.log("调用了getFullName");
          return this.firstName + " " + this.lastName
        }
      },
    })
  </script>
</body>
</html>


分别使用方法和计算属性获取四次fullName,结果如图。

image.png



由此可见计算属性有缓存,在this.firstName + " " + this.lastName的属性不变的情况下,methods调用了四次,而计算属性才调用了一次,性能上计算属性明显比methods好。而且在改动firstName的情况下,计算属性只调用一次,methods依然要调用4次。

image.png



5. Vue计算属性与侦听器总结

照例看一段代码:

<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Vue计算属性/侦听器/方法比较</title>
        <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
    </head>
    <body>
        <div id="app">
            <h1>计算属性:computed</h1>
            {{fullName}}
            <h1>方法:methods</h1>
            {{fullName2()}}
            <h1>侦听器:watch</h1>
            {{watchFullName}}
            <h1>年龄</h1>
            {{age}}
        </div>
        <script>
            var other = 'This is other';
            var app = new Vue({
                el:"#app",
                data:{
                firstName:"zhang",
                lastName:"san",
                watchFullName:"zhangsan",
                age:18,
                },
                watch: {
                    firstName:function(newFirstName, oldFirstName){
                        console.log("firstName触发了watch,newFirstName="+newFirstName+",oldFirstName="+oldFirstName)
                        this.watchFullName = this.firstName+this.lastName+","+other
                    },
                    lastName:function(newLastName, oldLastName){
                        console.log("lastName触发了watch,newLastName="+newLastName+",oldLastName="+oldLastName)
                        this.watchFullName = this.firstName+this.lastName+","+other
                    }  
                },
                computed: {
                    fullName:function(){
                    console.log("调用了fullName,计算了一次属性")
                    return this.firstName+this.lastName+","+other;
                    }
                },
                methods: {
                    fullName2:function(){
                        console.log("调用了fullName,执行了一次方法")
                        fullName2 = this.firstName+this.lastName+","+other;
                        return fullName2;
                    }
                }
            });
        </script>
    </body>
    </html>


初始化:

image.png


修改firstName/lastName/两者都修改

image.png


修改computed中没计算的age

image.png


修改Vue实例外的对象

image.png


修改Vue实例外对象后在修改Vue实例内的对象

image.png



测试结论:


使用computed计算了fullName属性,值为firstName+lastName。计算属性具有缓存功能,当firstName和lastName都不改变的时候,fullName不会重新计算,比如我们改变age的值,fullName的值是不需要重新计算的。

methods并没有缓存特性,比如我们改变age的值,fullName2()方法会被执行一遍。

当一个功能可以用上面三个方法来实现的时候,明显使用computed更合适,代码简单也有缓存特性。

计算属性范围在vue实例内,修改vue实例外部对象,不会重新计算渲染,但是如果先修改了vue实例外对象,在修改vue计算属性的对象,那么外部对象的值也会重新渲染。

计算属性:computed


计算属性范围在Vue实例的fullName内所管理的firstName和lastName,通常监听多个变量 1111


侦听器:watch


监听数据变化,一般只监听一个变量或数组


使用场景


watch(异步场景),computed(数据联动) watch可以在所监听的数据后面直接加字符串形式的方法名

<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Vue计算属性/侦听器/方法比较</title>
        <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
    </head>
    <body>
        <div id="app">
            <h1>计算属性:computed</h1>
            {{fullName}}
            <h1>方法:methods</h1>
            {{fullName2()}}
            <h1>侦听器:watch</h1>
            {{watchFullName}}
            <h1>年龄</h1>
            {{age}}
        </div>
        <script>
            var other = 'This is other';
            var app = new Vue({
                el:"#app",
                data:{
                firstName:"zhang",
                lastName:"san",
                watchFullName:"zhangsan",
                age:18,
                },
                watch: {
                    firstName:function(newFirstName, oldFirstName){
                        console.log("firstName触发了watch,newFirstName="+newFirstName+",oldFirstName="+oldFirstName)
                        this.watchFullName = this.firstName+this.lastName+","+other
                    },
                    lastName:function(newLastName, oldLastName){
                        console.log("lastName触发了watch,newLastName="+newLastName+",oldLastName="+oldLastName)
                        this.watchFullName = this.firstName+this.lastName+","+other
                    },
                    watchFullName:"change"
                },
                computed: {
                    fullName:function(){
                    console.log("调用了fullName,计算了一次属性")
                    return this.firstName+this.lastName+","+other;
                    }
                },
                methods: {
                    fullName2:function(){
                        console.log("调用了fullName,执行了一次方法")
                        fullName2 = this.firstName+this.lastName+","+other;
                        return fullName2;
                    },
                    change(){
                        console.log("调用了change,触发了watch")
                        return this.watchFullName='111'
                    }
                }
            });
        </script>
    </body>
    </html>


handler方法就相当于普通侦听器触发的事件,从结果可以看到,组件初始化的时候,侦听器并没有handler方法 ,所以fullName是没有值的


当修改以上代码,加上immediate: true,immediate:true代表watch里面声明了之后会立马执行handler里面的函数。执行相应的逻辑。组件初始化的时候,侦听器会立马(immediate)触发handler方法

<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Vue计算属性/侦听器/方法比较</title>
        <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
    </head>
    <body>
        <div id="app">
          <div>
            <p>FullName: {{person.fullname}}</p>
            <p>FirstName: <input type="text" v-model="person.firstname"></p>
          </div>
        </div>
        <script>
            var other = 'This is other';
            var app = new Vue({
              el: '#app',
               data(){
                return {
                    person: {
                        firstname: 'Menghui',
                        lastname: 'Jin',
                        fullname: ''
                    }
                }
              },
             watch: {
              person: {
                  handler(n,o){
                      this.person.fullname = n.firstname + '' + this.person.lastname;
                  },
                   immediate: true,  //刷新加载 立马触发一次handler
                  deep: true  // 可以深度检测到 person 对象的属性值的变化
              }
              }
            })
        </script>
    </body>
    </html>


当在输入框中输入数据时, 可以发现fullName的值并没有随之改变 这是因为vue无法检测到对象内部属性值的变化,比如person.firstname的变化


所以此时 需要用到vue的深度监听(deep)


此时加上代码 deep: true


可以发现 每次输入框数据变化 fullname随之改变


上面的可以发现handler监听的新值和老值是一样的 这是有vue2.0的坑 犹豫同源导致的 可以用computed来修改

<!DOCTYPE html>
<html>
  <head>
  <meta charset="utf-8">
  <title></title>
  </head>
  <body>
  <div id="app">
             <p>FullName: {{person.fullname}}</p>
             <p>FirstName: <input type="text" v-model="person.firstname"></p>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
  <script>
    const app = new Vue({
    el: "#app",
    data() {
      return {
      person: {
        firstname: 'Menghui',
        lastname: 'Jin',
        fullname: ''
      }
      }
    },
    methods: {
    },
    computed: {
                   person2(){
         return JSON.parse(JSON.stringify(this.person));
       }//解决深度监听新老值同源问题
    },
    watch:{
       person2:{
          handler(n,o){
        console.log(this.person);
        console.log(n.firstname);
                      console.log(o.firstname);
        /* this.person.fullname = this.person.firstname + this.person.lastname */
       },
      /* immediate: true, */
       deep: true  // 可以深度检测到 person 对象的属性值的变化
       }
    }
    })
  </script>
  </body>
</html>


相关实践学习
Serverless极速搭建Hexo博客
本场景介绍如何使用阿里云函数计算服务命令行工具快速搭建一个Hexo博客。
相关文章
|
13天前
|
JavaScript 前端开发
|
18天前
|
监控 JavaScript 前端开发
确定使用 `defer` 属性还是 `async` 属性来异步加载 JavaScript
【10月更文挑战第24天】选择使用 `defer` 属性还是 `async` 属性来异步加载 JavaScript 是一个需要综合考虑多个因素的决策。需要根据脚本之间的依赖关系、页面加载性能要求、脚本的功能和重要性等因素来进行权衡。在实际应用中,需要通过测试和验证来确定最适合的加载方式,以提供更好的用户体验和页面性能。
|
19天前
|
存储 JavaScript 前端开发
vue3的脚手架模板你真的了解吗?里面有很多值得我们学习的地方!
【10月更文挑战第21天】 vue3的脚手架模板你真的了解吗?里面有很多值得我们学习的地方!
vue3的脚手架模板你真的了解吗?里面有很多值得我们学习的地方!
|
6天前
|
存储 缓存 JavaScript
如何在大型 Vue 应用中有效地管理计算属性和侦听器
在大型 Vue 应用中,合理管理计算属性和侦听器是优化性能和维护性的关键。本文介绍了如何通过模块化、状态管理和避免冗余计算等方法,有效提升应用的响应性和可维护性。
|
6天前
|
JavaScript 前端开发 UED
vue学习第二章
欢迎来到我的博客!我是一名自学了2年半前端的大一学生,熟悉JavaScript与Vue,目前正在向全栈方向发展。如果你从我的博客中有所收获,欢迎关注我,我将持续更新更多优质文章。你的支持是我最大的动力!🎉🎉🎉
|
6天前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript和Vue的大一学生。自学前端2年半,熟悉JavaScript与Vue,正向全栈方向发展。博客内容涵盖Vue基础、列表展示及计数器案例等,希望能对你有所帮助。关注我,持续更新中!🎉🎉🎉
|
18天前
|
监控 JavaScript 前端开发
使用 `defer` 属性异步加载 JavaScript
【10月更文挑战第24天】使用 `defer` 属性异步加载 JavaScript 是一种有效的提高页面性能和用户体验的方法。通过合理设置 `defer` 属性,可以在不影响页面渲染的情况下异步加载脚本,并确保脚本的执行顺序。在实际应用中,需要根据具体情况选择合适的加载方式,并注意处理可能出现的问题,以确保页面能够正常加载和执行。
|
1月前
|
监控 JavaScript 开发者
在 Vue 中,子组件为何不可以修改父组件传递的 Prop,如果修改了,Vue 是如何监控到属性的修改并给出警告的
在 Vue 中,子组件不能直接修改父组件传递的 Prop,以确保数据流的单向性和可预测性。如果子组件尝试修改 Prop,Vue 会通过响应式系统检测到这一变化,并在控制台发出警告,提示开发者避免这种操作。
|
1月前
|
JavaScript
《进阶篇第9章》学习vuex知识点后练习:求和案例_纯vue版代码
《进阶篇第9章》学习vuex知识点后练习:求和案例_纯vue版代码
13 1
|
1月前
|
缓存 JavaScript Serverless
vue中computed计算属性、watch侦听器、methods方法的区别以及用法
vue中computed计算属性、watch侦听器、methods方法的区别以及用法
103 0