前端Vue2-Day48
计算属性:(computed属性)要使用的数据不存在,须通过已有属性计算得出。
原理:使用了Object.defineproperty方法提供的getter和setter。
get函数的执行时机:1.在初次获取元素时调用(产生缓存防止重复调用)2.修改数据时调用
优势:相较于methods,内部存在缓存机制,效率更高,调试方便。
备注:计算属性会挂载到vm上,直接调用即可。如果计算属性发生修改,需要去内部编写set方法响应修改,且要修改依赖的数据。
computed: {
fullName: {
// 读取时自动调用
// 初次读取和修改时重新调用
get() {
return `${this.firstName}-${this.lastName}`
},
// 修改时自动调用
set(value) {
const arr = value.split('-')
this.firstName = arr[0]
this.lastName = arr[1]
}
}
}
计算属性简写:当不发生修改时,即无set方法时。直接将属性写成方法并返回值。
new Vue({
el: '#root',
data: {
firstName: '张',
lastName: '三'
},
computed: {
// 简写:不发生修改
fullName() {
return `${this.firstName}-${this.lastName}`
}
}
})
监视属性:(watch)当监视的属性发生变化时,回调函数handler调用。handler属性默认为newValue和oldValue。
监视属性的写法:
① new Vue中加入配置项watch进行相关配置(immediate:初始化是否立即执行,handler为变化执行的回调函数)
② 使用vm.$watch进行配置。$watch('属性名',{回调函数})
深度监视:监视对象内部值变化。
① Vue中的watch属性默认不检测对象内部的改变。
② 配置watch中的deep属性为true即可达到多级监视的目的。
new Vue({
el: '#root',
data: {
isHot: true,
numbers: {
a: 1,
b: 2,
}
},
methods: {
changeWeather() {
this.isHot = !this.isHot
}
},
computed: {
info() {
return this.isHot ? '炎热' : '凉爽'
}
},
watch: {
// 监视多级解构中某个属性的变化
'numbers.a': {
handler(newValue, oldValue) {
}
},
// 监视多级结构中所有属性的变化
numbers: {
deep:true,
handler(newValue, oldValue) {
console.log('change');
}
}
}
})
监视属性简便写法:不考虑设置immediate和deep时直接将监视属性作为handler函数返回。
// 简便写法1:
isHot(newValue, oldValue) {
console.log('change');
}
// 简便写法2:
vm.$watch('isHot', function (newValue, oldValue) {
console.log('change');
})
computed和watch的区别:
① computed能完成的功能,watch都能完成。
② watch能完成的功能,computed不一定能完成,如使用watch实现异步操作。
注意:所有由Vue管理的函数,最好写成普通函数,这样this执行为vm即Vue实例对象。而不被Vue管理的函数(定时器,Ajax回调函数,Promise回调函数等)最好写成箭头函数,这样this才指向vm。
绑定样式:
绑定Class样式:写法:class="xxx" xxx可以为字符串,数组或对象。
- 字符串适用于类名不确定,需要动态获取。
- 数组适用于要绑定多个样式,个数和名字均确定,但要动态决定是否选用。
- 对象适用于要绑定多个样式,个数和名字均不确定。
绑定Style样式:写法:style="{fontSize:xxx}"其中xxx为动态值,:style="[a,b,c]"其中abc为样式对象。
条件渲染:v-show和v-if
v-if:v-if="xxx" / v-else-if="xxx" / v-else
适用于低频率变化的场景,不展示的DOM元素直接被移除,v-if和v-else-if和v-else使用时必须相接不能被打断。
v-show:v-show="xxx"
高频率变化使用v-show,不展示的DOM元素未被移除,仅仅是display:none隐藏掉。
template标签:与v-if一起使用,隐藏时会在页面随之隐藏,显示和隐藏均不会存在该节点。
<template v-if="n===1">
<h1>12</h1>
<h2>23</h2>
</template>
列表渲染:
v-for命令:用于展示列表数据。
语法:v-for="(item,index)" in "xxx" :key="yyy"(这里用in和of均可)
虚拟DOM中key的作用:key是虚拟DOM对象的唯一标识。当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,随后Vue进行【新虚拟DOM】和【旧虚拟DOM】的差异比较。
新旧虚拟DOM比较规则(Diff算法):
(1)旧虚拟DOM中找到了与新虚拟DOM相同的key值:
- ① 若新虚拟DOM中内容没变,则直接使用之前生成的真实DOM。
- ② 若新虚拟DOM中内容变化了,则直接生成新的真实DOM,随后替换掉之前生成的旧真实DOM。
(2)旧虚拟DOM中未找到和新虚拟DOM相同的key值:则直接生成新的真实DOM,渲染至页面。
使用下标index作为key的问题:若对数据进行:逆序添加、逆序删除等破坏顺序的操作,会产生没有必要的真实DOM更新,造成效率低下。如果结构中还包含输入类DOM则会产生错误的真实DOM更新,造成页面渲染出错。
筛选列表事例:
1.使用监视属性实现时,改变的是页面遍历的数组。故设立一个新数组于data中。handler进行筛选改变,需要immediate立即执行。
2.使用计算属性实现时,将页面要展现的新数组计算出来。设置新的数组作为计算属性,直接对其进行get方法改变即可。
这里的种种操作是因为筛选数组用到的filter方法不会改变原数组,而是生成一个新数组作为返回值。
<div id="root">
<h2>人员列表</h2>
<input type="text" placeholder="请输入名字" v-model="keyWord">
<ul>
<li v-for="(p,index) in filPersons" :key="p.id">
{{p.name}}-{{p.age}}
</li>
</ul>
</div>
<script>
// 利用 watch实现
new Vue({
el: '#root',
data: {
keyWord: '',
persons: [
{
id: 001,
name: '马冬梅',
age: 18,
gender: '女'
},
{
id: 002,
name: '周冬雨',
age: 20,
gender: '女'
},
{
id: 003,
name: '周杰伦',
age: 30,
gender: '男'
},
{
id: 004,
name: '温兆伦',
age: 35,
gender: '男'
}
],
// 存放新数据
filPersons: []
},
watch: {
keyWord: {
immediate: true,
handler(value) {
this.filPersons = this.persons.filter(p => {
return p.name.indexOf(value) !== -1
})
}
}
}
})
// 利用 computed实现
new Vue({
el: '#root',
data: {
keyWord: '',
persons: [
{
id: 001,
name: '马冬梅',
age: 18,
gender: '女'
},
{
id: 002,
name: '周冬雨',
age: 20,
gender: '女'
},
{
id: 003,
name: '周杰伦',
age: 30,
gender: '男'
},
{
id: 004,
name: '温兆伦',
age: 35,
gender: '男'
}
],
},
computed: {
filPersons() {
return this.persons.filter(e => {
return e.name.indexOf(this.keyWord) !== -1
})
}
}
})
</script>
列表排序事例:
给各排序按钮设置事件改变定义的sortType属性,在计算属性内部进行判断是否需要进行重排序,由于计算属性触发时机为依赖属性改变故总会随按钮点击而变化。
<div id="root">
<h2>人员列表</h2>
<input type="text" placeholder="请输入名字" v-model="keyWord">
<button @click="sortType=0">年龄升序</button>
<button @click="sortType=1">年龄降序</button>
<button @click="sortType=2">原顺序</button>
<ul>
<li v-for="(p,index) in filPersons" :key="p.id">
{{p.name}}-{{p.age}}
</li>
</ul>
</div>
<script>
new Vue({
el: '#root',
// 0为原顺序,1为降序,2为升序
data: {
keyWord: '',
sortType: 0,
persons: [
{
id: 001,
name: '马冬梅',
age: 28,
gender: '女'
},
{
id: 002,
name: '周冬雨',
age: 20,
gender: '女'
},
{
id: 003,
name: '周杰伦',
age: 30,
gender: '男'
},
{
id: 004,
name: '温兆伦',
age: 35,
gender: '男'
}
],
},
// 计算属性的依赖属性改变时也会重新执行!
computed: {
filPersons() {
const arr = this.persons.filter(e => {
return e.name.indexOf(this.keyWord) !== -1
})
// 判断是否需要排序
if (this.sortType) {
this.sortType === 1 ? arr.sort((x, y) => {
return x.age - y.age
}) : arr.sort((x, y) => {
return y.age - x.age
})
}
return arr
}
}
})
</script>