目录

模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护
表达式的计算逻辑可能会比较复杂,使用计算属性可以使模板内容看起来更加的整洁
例如
- <div id="app">
- {{ message.split('').reverse().join('') }}
- div>2>
- 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},
- ]
-
- // for循环遍历
- totalPrice(){
- let total=0;
- for (let i = 0; i < this.books.length; i++) {
- total+=this.books[i].price
- }
- return total
- }
-
- }
-
- totalPrice(){
- let total = 0;
- for (const item in this.books) {
- total+=this.books[item].price
- }
- return total
- }
-
- totalPrice() {
- let total = 0;
- for (let index of this.books) {
- total += index.price
- }
- return total
- }
-
- totalPrice(){
- let total = 0;
- this.books.forEach(item => {
- total+= item.price
- })
- return total
- }
- totalPrice(){
- let total = 0;
- this.books.map(item => {
- total+= item.price
- })
- return total
- }
-
- totalPrice(){
- let total = 0;
- this.books.filter(item => {
- total+= item.price
- })
- return total
- }
-
- totalPrice() {
- return this.books.reduce((total,item)=>{
- return total + item.price
- },0)
- }
-
- // 简写
- // totalPrice() {
- // return this.books.reduce((total, item) => total + item.price, 0)
- // }
-
- totalPrice() {
- let total = 0;
- this.books.some(item => {
- total += item.price
- })
- return total
- }
- 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>Documenttitle>
- <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>
实现的结果如下图:

在计算属性中其实是由这样两个方法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方法设置值,但是一般不用。
- 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和settertitle>
- <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js">script>
- head>
- <body>
- <div id="app">
- <h1>计算属性:computed的getter/setterh1>
- <h2>fullNameh2>
- {{fullName}}
- <h2>firstNameh2>
- {{firstName}}
- <h2>lastNameh2>
- {{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值是如下图

小结: 通过这种方式,我们可以在改变计算属性值的同时也改变和计算属性相关联的属性值。
分别使用计算属性和方法获得fullName的值
- 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">
-
- <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
如下图

小结:
由此可见计算属性有缓存,在this.firstName + " " + this.lastName的属性不变的情况下,methods调用了四次,而计算属性才调用了一次,性能上计算属性明显比methods好。而且在改动firstName的情况下,计算属性只调用一次,methods依然要调用4次。
- 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>计算属性:computedh1>
- {{fullName}}
- <h1>方法:methodsh1>
- {{fullName2()}}
- <h1>侦听器:watchh1>
- {{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>

测试结论:
缓存功能,当firstName和lastName都不改变的时候,fullName不会重新计算,比如我们改变age的值,fullName的值是不需要重新计算的。计算属性:computed
计算属性范围在Vue实例的fullName内所管理的firstName和lastName,通常监听多个变量 1111
侦听器:watch
监听数据变化,一般只监听一个变量或数组
使用场景
watch(异步场景),computed(数据联动) watch可以在所监听的数据后面直接加字符串形式的方法名
- 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>计算属性:computedh1>
- {{fullName}}
- <h1>方法:methodsh1>
- {{fullName2()}}
- <h1>侦听器:watchh1>
- {{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来修改
- 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>