【笔记】Vue计算属性

266 阅读5分钟

计算属性

模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护

  • 模板内表达式用于简单计算
{{text.split('').reverse().join('')}}
  • 计算属性适用于复杂计算
<div id='app'>
  {{reverseText}}
</div>
<script>
var app = new Vue({
  el: '#demo',
  data: {
    text: '123,456,789'
  },
  computed: {
    reverseText:function(){
    return this.text.split(',').reverse().join(',');
  }
  }
})
</script>

计算属性方法

  • 计算属性可以依赖其他计算属性
  • 计算属性可以依赖其他实例的数据
  • 计算属性的属性值必须是一个函数
  • 计算属性不能执行异步任务,异步任务交给侦听属性
  • 在 getter 中收集依赖,在 setter 中触发依赖
<div id="app">
  {{fullName}}
</div>
  <script>
  var app = new Vue({
    el: '#app',
    data: {
      firstName: 'li',
      lastName: 'bai'
    },
    computed: {
      fullName:{
       get: function(){
        	return this.firstName + ' ' + this.lastName
      },
      	set: function(newValue){
        	var names = newValue.split(' ')
        	this.firstName = names[0]
        	this.lastName = names[1]
      	}
        }
    }
  })
    现在运行app.fullName = 'zhang hua',setter会被调用,app.firstName和app.lastName也会随之改变
  </script>

getter

如果计算属性直接接一个函数,默认属性时 getter

computed: function(){

}

setter

手动修改计算属性值会触发 setter

set 设置属性,并不是直接修改计算属性,而是修改它的依赖。

计算属性缓存

计算属性是基于它们的响应式依赖进行缓存的,一个计算属性所依赖的数据未发生变化,计算属性就不更新

methods 方法具有相同效果,还可以接受参数,使用更灵活。

watch、computed、methods 比较

  • computed 是依赖与其他属性的一个计算值,依赖于缓存,只有当其依赖的数据发生变化时它才更新
  • watch 是监听的属性发生变化时,触发回调执行逻辑
  • computed 是计算出一个属性,watch 是上报数据等
  • computed 与 methods 的选择取决于你是否需要缓存,computed 属性的依赖不发生变化就不会重新计算,遍历大数组和做大量计算时使用计算属性。methods 是看到一次计算一次

侦听属性

观察和响应 Vue 实例上的数据变动,watch

参考:Vue.js 的 computed 和 watch 是如何工作的?- 慕晨同学

<div id="app">
  <div>fullName: {{fullName}}</div>
  firstName: <input type="text" v-model="firstName">
</div>
<script>
var app = new Vue({
  el: '#app',
  data: {
    firstName: 'li',
    lastName: 'bai',
    fullName: 'li bai'
  },
  watch: {
      firstName(newName, oldName) {
        console.log('第一次没有执行')
      this.fullName = newName + ' ' + this.lastName;
    }
  }
})
</script>

通过下图可以看出,初始化时 watch 是不执行的,当 firstName 发生改变时,watch 才监听计算

handler 用法

绑定 handler 方法,immediate:true; 立即执行 handler 方法

实例

var app =new Vue({
  el: '#app',
  data: {
    firstName: 'li',
    lastName: 'bai',
    fullName:''
  },

  watch: {
    firstName: {
    handler(newName,oldName){
      console.log('第一次执行了')
      this.fullName = newName + ' '+ this.lastName
    },
    immediate:true
  }
  }
})

immediate:true 立即执行。immediate:false 时与例子 1 相同,初始化时控制台不会出现信息

deep 用法

deep:true 深度监听

实例

var app = new Vue({
  el: '#app',
  data: {
    obj: {
    	a: 1,
      b: 2,
      c: 3
    }
  },
  watch: {
    obj: {
      handler(val) {
       console.log('obj.a changed')
      },
      immediate: true,
//       deep: true
    }
  }

在 input 框输入数据不是响应式的(数据不在 data 对象上,在更深层的位置),hanlder 方法在输入数据时不执行 deep:true 深度监听 obj 里的属性值,会在对象层层往下遍历,使每层都加上监听器,触发深层对象的依赖,追踪其变化,使 handler 方法每次能够执行。

缺点

每层加上监听器,性能开销太大

  • 优化方法:
    • 用字符串方式,给'obj.a'属性设置监听函数
var app = new Vue({
  el: '#app',
  data: {
    obj: {
    	a: 1,
      b: 2,
      c: 3
    }
  },
  watch: {
    'obj.a': {
      handler(val) {
       console.log('obj.a changed')
      },
      immediate: true
    }
  }
})

class 与 style 绑定

用 v-bind 处理

绑定 class 的几种方式

对象语法

传给 v-bind:class 一个对象,以动态地切换 class。

对象语法实例

<div id="app">
    <div :class="{active:isActive}"></div>
  </div>

isActive值为true/false
var app = new Vue({
  el: '#app',
  data: {
    isActive: true
  }
})

数组语法

把一个数组传给 v-bind:class,以应用一个 class 列表。

数组语法实例

<div :class="[activeClass,errorClass]"></div>
var app = new Vue({
  el: '#app',
  data: {
    activeClass: 'active',
    errorClass: 'error'
  }
})

数组对象混合语法

混合实例

  <div id="app">
    <div v-bind:class="[{'active':isActive},errorClass]"></div>
  </div>
.active {
  width: 100px;
  height: 100px;
  background: lightgreen;
}
.error {
  border: 5px solid;
}
var app = new Vue({
  el: '#app',
  data: {
  isActive: true,
  errorClass: 'error'
}
})

用在组件时

在一个自定义组件上使用 class property 时,class 被添加的组件的更元素上但是不会覆盖原有的 class,共存。

实例

  <div id="app">
    <my-component :class="{active:isActive}"></my-component>
  </div>
.active {
 width: 100px;
 height: 100px;
 background: pink;
}
Vue.component('my-component',{
 template: '<div class="foo">hi</div>'
})
var app =new Vue({
 el: '#app',
 data: {
   isActive: true
 }
})

绑定内联样式

对象语法

实例

<div id="app">
    <div v-bind:style="{color: activeColor, fontSize: fontSize + 'px'}">hello world</div>
    <div v-bind:style="styleObject">hello vue</div>
</div>
var app = new Vue({
  el: '#app',
  data: {
  activeColor: 'red',
  fontSize: 20,
  styleObject: {
    color: 'green',
    font: 16
  }
}
})

数组语法

实例

<div id="app">
    <div v-bind:style='[styleA,styleB]'>hello</div>
</div>
var app = new Vue({
  el: '#app',
  data: {
  styleA: {
    color:'red',
    background: 'yellow'
  },
    styleB: {
    border: '3px solid black'
  }
}
})

内置指令

基本指令

v-cloak

解决初始化慢导致页面闪动。

实例

<div id="app">
    <div v-cloak>{{msg}}</div>
</div>
[v-cloak] {
  display: none;
}

var app = new Vue({
  el: '#app',
  data: {
  msg: 'hello'
}
})
//输入msg可以观察到变化

v-once

只渲染元素和组件一次

实例

条件渲染指令

v-if、v-else、v-else-if

<div id="app">
     <div v-if="6<3">{{correct}}</div>
     <div v-else-if='9>5'>{{correct}}</div>
     <div v-else>{{error}}</div>
 </div>
var app = new Vue({
  el: '#app',
  data: {
  correct: 'true',
  error: 'false'
}
})

用 key 管理可复用元素

实例

问题: 元素复用

弊端:处于效率考虑,会尽可能复用已有的元素(切换用户/密码框,input 填写内容不变)

解决方法: 用 key 管理可复用的元素,表达他们是独立的两个元素,不要复用

<template>元素上使用 v-if 条件渲染分组

若是想切换多个元素,可以在<template>元素上使用 v-if 包裹,最终渲染结果不包括<template>元素。

实例

<template v-if="ok">
  <h1>Title</h1>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</template>

v-show

根据条件展示语句,只改变 css 属性 display,带有 v-show 的元素始终会被渲染并保留在 DOM 中 实例

v-if 与 v-show 比较

  • v-if 实时渲染,显示才开始渲染,不显示就移除
  • v-show 元素永远存在页面中,总是渲染,只改变 display 属性
  • 选择:频繁切换使用 v-show,条件很少改变使用 v-if

列表渲染指令

v-for

将一个数组遍历或枚举一个对象属性的时候循环显示

语法

item in items // item是源数组数据,items是被迭代的数组元素的别名
(item,index) in items
value in object
(value,name,index) in object

遍历多个对象

实例

<div id="app">
    <ul>
      <li v-for="item in items" :key="item.message">
        {{item.message}}
      </li>
    </ul>
 </div>
<script>
 var app = new Vue({
  el: '#app',
  data: {
  items: [
    {message: 'hello'},
    {message: 'world'}
]
}
})
</script>

注意:v-for默认采用“就地更新” 在使用 v-for 时提供 key attribute,在数据项改变时可以跟踪每个节点,重新排序,而不是就地更新

实例

<div id="app">
    <ul>
      <li v-for="(item,index) in items">
        {{ parentMessage }} - {{ index }} - {{ item.message }}
      </li>
    </ul>
</div>
<script>
var app = new Vue({
  el: '#app',
  data: {
    parentMessage: 'Parent',
  items: [
    {message: 'hello'},
    {message: 'world'}
]
}
})
</script>

遍历一个对象的多个属性

实例

<div id="app">
  <ul>
    <li v-for="value in Object">
      {{value}}
    </li>
  </ul>
</div>
<script>
var app = new Vue({
  el: '#app',
  data: {
    Object: {
      Name : 'Vue',
      Date: '2020'
    }
  }
})
</script>

v-if 和 v-for 能否一起使用

  • 不推荐 v-if 和 v-for 一起使用(v-for 比 v-if 级别更高)
  • v-if 和 v-for 一起使用出现的优先级问题:实例

数组更新

变更方法

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

实例

替换数组

不变更原始数组,总是返回一个新数组

  • filter()
  • concat()
  • slice()

实例

computed: {
    matchO: function(){
      return this.items.filter(function(items){
        return items.match(/o/);
      })
    },
    concat: function(){
      return this.items.concat('four');
    },
    slice: function(){
      return this.items.slice(2)
    }
  }