【Vue.js】计算属性
前言
我们为什么要引用计算属性?
模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护
<div id="app"> {{ message.split('').reverse().join('') }} </div>2>计算属性的基本使用
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script src="js/vue.js" type="text/javascript" charset="utf-8"></script> </head> <body> <div id="app"> <h2>您的firstname:{{firstName}}</h2> <h2>您的lastname:{{lastName}}</h2> <h2>您的fullname是从计算属性中得到:{{fullName}}</h2> <h2>您的fullname是从方法中得到:{{getFullName()}}</h2> </div> <script> const vm = new Vue({ el:'#app', data(){ return { firstName:'zhang', lastName:'san' } }, methods:{ getFullName(){ return this.firstName + this.lastName } }, computed:{//计算属性 一定要有一个返回值 在页面中渲染时是不需要加小括号的 fullName(){ return this.firstName + this.lastName } } }) </script> </body> </html>计算属性的复杂使用
<div id="app"> <h2>您的总价:{{totalPrice}}</h2> </div>计算书本的总价的几种方法
books: [ {id: 110,name: "JavaScript从入门到入土",price: 119}, {id: 111,name: "Java从入门到放弃",price: 80}, {id: 112,name: "编码艺术",price: 99}, {id: 113,name: "代码大全",price: 150}, ]目前我所知道的方法有以下几种
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="./vue.js"></script> </head> <body> <div id="app"> <h3>您的总价为:{{totalPrice}}</h3> </div> <script> const vm = new Vue({ el: '#app', data() { return { books: [{ id: 110, name: "JavaScript从入门到入土", price: 119 }, { id: 111, name: "Java从入门到放弃", price: 80 }, { id: 112, name: "编码艺术", price: 99 }, { id: 113, name: "代码大全", price: 150 }, ] } }, computed: { // for循环遍历 // totalPrice(){ // let total=0; // for (let i = 0; i < this.books.length; i++) { // total+=this.books[i].price // } // return total // } // for in 循环遍历 // totalPrice(){ // let total = 0; // for (const item in this.books) { // total+=this.books[item].price // } // return total // } // for of 遍历 // totalPrice() { // let total = 0; // for (let index of this.books) { // total += index.price // } // return total // } // foreach 遍历 // totalPrice(){ // let total = 0; // this.books.forEach(item => { // total+= item.price // }) // return total // } // Map 遍历 // totalPrice(){ // let total = 0; // this.books.map(item => { // total+= item.price // }) // return total // } // filter 遍历 // totalPrice(){ // let total = 0; // this.books.filter(item => { // total+= item.price // }) // return total // } // reduce 遍历 // totalPrice() { // return this.books.reduce((total,item)=>{ // return total + item.price // },0) // } // 简写 // totalPrice() { // return this.books.reduce((total, item) => total + item.price, 0) // } // some 遍历 totalPrice() { let total = 0; this.books.some(item => { total += item.price }) return total } } }) </script> </body> </html>实现的结果如下图:
计算属性中的set和get
在计算属性中其实是由这样两个方法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>
初始化时如下图
编辑
当在控制台 修改fullName值是如下图
编辑
小结: 通过这种方式,我们可以在改变计算属性值的同时也改变和计算属性相关联的属性值。
计算属性与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
如下图
编辑
小结:
计算属性与侦听事件
<!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>

测试结论:
- 使用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>
当在输入框中输入数据时, 可以发现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>