Vue基础-key,计算属性,过滤器,侦听器
一、更新检测和key的作用
1.1 v-for更新检测
目标结构变化, 触发v-for的更新
数组变更方法, 就会导致v-for更新, 页面更新
push
shift
unshift
pop
sort
splice
reverse
数组非变更方法, 返回新数组, 就不会导致v-for更新, 可采用覆盖数组或this.$set()
filter
slice
concat
this.$set()方法更新某个值
changeBtn() {
// this.arr[0] = 1000
//使用this.$set()
//参数一 更新的目标结构
//参数二 更新的位置
//参数三 更新的值
this.$set(this.arr, 0, 1000)
}
1.2 v-for就地更新
循环出新的虚拟DOM结构, 和旧的虚拟DOM结构对比, 尝试复用标签就地更新内容
1.3 真实DOM
在document对象上, 渲染到浏览器上显示的标签
1.4 虚拟DOM
本质是保存节点信息, 属性和内容的一个JS对象
在内存中比较变化部分,然后给真实DOM打补丁(更新)
虚拟DOM的好处,提高DOM更新的性能,不频繁操作真实的DOM
1.5 diff算法
同级比较-根元素变化,整个dom树删除重建
同级比较-根元素不变,属性改变更新属性
1.6 diff算法-key
根元素没变, 子元素没变, 元素内容改变
1.6.1 无key(就地更新)
v-for不会移动DOM, 而是尝试复用, 就地更新
最大限度尝试就地修改/复用相同类型元素
1.6.2 有key, 值为索引
有key属性, 基于key的来比较新旧虚拟DOM, 移除key不存在元素
先产生新旧虚拟DOM,根据key比较,还是就地更新
1.6.3 有key, 值唯一不重复的字符串或数字
有key属性, 基于key的来比较新旧虚拟DOM, 移除key不存在元素
先产生新旧虚拟DOM, 根据key比较
有id用id, 无id用索引
key的好处可以配合虚拟dom提高更新的性能
1.7 动态class
用v-bind给标签class设置动态的值
语法 :class="{ 类名 : 布尔值 }"
1.8 动态style
给标签动态设置style的值
语法 :style=" { css属性名 : 值 }"
二、过滤器
2.1 定义使用
转换格式,过滤器就是一个函数 传入值返回处理后的结果
过滤器只能用在 插值表达式 和 v-bind动态属性里
定义过滤器的位置
全局过滤器(main.js)
局部过滤器(当前页面,与data同级)
//全局过滤器
//任意的.vue文件内 直接使用
//语法Vue.filter('过滤器名称',值==>处理结果)
Vue.filter('reverse', val => val.split('').reverse().join(''))
--------------------------------------------
//方法二 定义局部过滤器`
//当前vue文件内使用 加s(可定义多个过滤器)
filters: {
toUps: function (val) {
console.log('val');
return val.toUpperCase()
}
}
过滤器的使用
语法 vue变量 | 过滤器名称
<!-- 过滤器使用 {{ 变量|过滤器名称 }} -->
<p>使用反转过滤器{{ msg | reverse }}</p>
<p :title="msg | toUps">鼠标长时间停留111</p>
2.2 传参和使用多个过滤器
语法
传参 变量 | 过滤器(实参)
多个过滤器 变量 | 过滤器1 | 过滤器2
三、计算属性
3.1 computed
一个变量的值依赖另外一些数据计算得来的值
计算属性也是vue数据变量, 所以不要和data里重名, 用法和data相同
export default {
data() {
return {
a: 10,
b: 20
}
},
//计算属性 场景(当一个变量的值,来源于另外变量计算而得来的)
//语法 computed:{计算属性名(){return 值}}
//注意 计算属性和data属性都是变量 不能重名
computed: {
num() {
return this.a + this.b
}
}
}
3.2 缓存
计算属性, 基于依赖项的值进行缓存,依赖的变量不变, 都直接从缓存取结果
当依赖性改变时,会自动执行并重新缓存新值
3.3 完整写法
计算属性也是变量, 如果想要直接赋值, 需要使用完整写法
computed: {
full: {
// return '无名氏'
//给full赋值触发set方法
set(val) {
console.log('val', val);
},
//使用full的值触发get方法
get() {
return '无名氏'
}
}
}
3.4 全选 小选 反选案例
小选影响全选
全选影响小选
反选
<template>
<div>
<span>全选:</span>
<!-- 2.v-model关联选中的状态 -->
<input type="checkbox" v-model="isAll" />
<button @click="btn">反选</button>
<ul>
<li v-for="item in arr">
<!-- 1.关联选中状态 -->
<input type="checkbox" v-model="item.c" />
<span>{{ item.name }}</span>
</li>
</ul>
</div>
</template>
<script>
export default {
//3.计算属性
computed: {
isAll: {
set(val) {
//5.全选框选中状态 改变小选框状态
console.log('打印去到的值', val);
this.arr.forEach(item => item.c = val)
},
get() {
//4.统计小选框的状态
//every 查找数组里不符合条件的 直接原地返回false
return this.arr.every((item) => item.c === true)
}
}
},
methods: {
btn() {
this.arr.forEach((item) => item.c = !item.c)
}
},
data() {
return {
arr: [
{
name: "猪八戒",
c: false,
},
{
name: "孙悟空",
c: false,
},
{
name: "唐僧",
c: false,
},
{
name: "白龙马",
c: false,
},
],
};
}
};
</script>
四、侦听器
4.1 watch
可以侦听data computed(计算属性) 值的改变
4.2 深度侦听和立即执行
侦听复杂类型, 或者立即执行侦听函数
watch: {
user: {
immediate: true,//立即执行
deep: true,//深度侦听复杂类型
handler(newval, oldval) {
console.log(newval, oldval);
}
}
}
五、品牌管理案例
1.品牌管理数据铺设
2.品牌管理数据增加
3.品牌管理数据删除
4.品牌管理时间格式化
5.品牌管理总价和均价
6.品牌管理数据缓存
完整代码
<template>
<div id="app">
<div class="container">
<!-- 顶部框模块 -->
<div class="form-group">
<div class="input-group">
<h4>品牌管理</h4>
</div>
</div>
<!-- 数据表格 -->
<table class="table table-bordered table-hover mt-2">
<thead>
<tr>
<th>编号</th>
<th>资产名称</th>
<th>价格</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="item in list" :key="item.id">
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<!-- 如果价格超过100,就有red这个类 -->
<td :class="{ red: item.price > 100 }">{{ item.price }}</td>
<td>{{ item.time | formaDate }}</td>
<td @click="del(item.id)"><a href="#">删除</a></td>
</tr>
<tr v-if="list.length !== 0" style="background-color: #EEE">
<td>统计:</td>
<td colspan="2">总价钱为: {{ allPrice }}</td>
<td colspan="2">平均价: {{ svgPrice }}</td>
</tr>
</tbody>
<tfoot v-if="list.length <= 0">
<tr>
<td colspan="5" style="text-align: center">暂无数据</td>
</tr>
</tfoot>
</table>
<!-- 添加资产 -->
<form class="form-inline">
<div class="form-group">
<div class="input-group">
<input type="text" v-model="name" class="form-control" placeholder="资产名称" />
</div>
</div>
<div class="form-group">
<div class="input-group">
<input v-model.number="price" type="text" class="form-control" placeholder="价格" />
</div>
</div>
<!-- 阻止表单提交 -->
<button @click.prevent="addBtn" class="btn btn-primary">添加资产</button>
</form>
</div>
</div>
</template>
<script>
//目标 侦听list改变 同步到本地localStorage里边
import moment from 'moment'
export default {
data() {
return {
name: "", // 名称
price: 0, // 价格
//3.本地取出缓存的list
list: JSON.parse(localStorage.getItem('Plist')) || []
};
},
//侦听器 1.list
watch: {
list: {
deep: true,
handler(newval, oldval) {
//2.存入本地
localStorage.setItem('Plist', JSON.stringify(newval))
}
}
},
//过滤器
filters: {
formaDate(val) {
return moment(val).format('YYYY-MM-DD')
}
},
//计算属性
computed: {
allPrice() {
return this.list.reduce((sum, obj) =>
sum += obj.price
, 0)
},
svgPrice() {
// toFixed 保留两位小数
return (this.allPrice / this.list.length).toFixed(2)
}
},
methods: {
//增加按钮
addBtn() {
console.log('名称 价格', this.name, this.price);
if (this.name.trim().length === 0 || this.price === 0) {
return alert('不能为空')
}
let id = this.list.length > 0 ? this.list[this.list.length - 1].id + 1 : 100
console.log('打印id', id);
this.list.push({
id: id,
name: this.name,
price: this.price,
time: new Date()
})
this.name = ''
this.price = 0
},
//删除
del(id) {
console.log('id', id);
let i = ''
// this.list.forEach((item, index) => {
// if (item.id === id) {
// console.log('打印索引', index);
// i = index
// }
// })
i = this.list.findIndex((item, index) => {
return item.id === id
})
this.list.splice(i, 1)
}
}
};
</script>
<style >
.red {
color: red;
}
</style>