Vue的基础属性知识
1. Vue基础_更新检测,key作用在上一章我们提到过v-for数组,那么我们的需求是如何v-for数组变化,需要同步更新到页面。但是并不是所有的数组方法都会造成v-for的更新。<template><div><ul><li v-for="(val, index) in arr" :key="index">{{ val }}</li>&
1. Vue基础_更新检测,key作用
在上一章我们提到过v-for数组,那么我们的需求是如何v-for数组变化,需要同步更新到页面。但是并不是所有的数组方法都会造成v-for的更新。
<template>
<div>
<ul>
<li v-for="(val, index) in arr" :key="index">
{{ val }}
</li>
</ul>
<button @click="revBtn">数组翻转</button>
<button @click="sliceBtn">截取前3个</button>
<button @click="updateBtn">更新第一个元素值</button>
</div>
</template>
<script>
export default {
data(){
return {
arr: [5, 3, 9, 2, 1]
}
},
methods: {
revBtn(){
// 1. 数组翻转可以让v-for更新
this.arr.reverse()
},
sliceBtn(){
// 2. 数组slice方法不会造成v-for更新
// slice不会改变原始数组
// this.arr.slice(0, 3)
// 解决v-for更新 - 覆盖原始数组
let newArr = this.arr.slice(0, 3)
this.arr = newArr
},
updateBtn(){
// 3. 更新某个值的时候, v-for是监测不到的
// this.arr[0] = 1000;
// 解决-this.$set()
// 参数1: 更新目标结构
// 参数2: 更新位置
// 参数3: 更新值
this.$set(this.arr, 0, 1000)
}
}
}
</script>
<style>
</style>
上面列举了数组翻转,数组截取和数组更新值的情形。其中push,pop,shift,unshift,splice,sort,reverse等数组方法会导致v-for更新。
但是比如filter,concat,slice等方法不会造成更新,因此我们在使用的时候可以采用覆盖数组的方式。
但是对于赋值的操作我们可采用this.$set()
那么v-for是如何更新DOM的呢?
循环出新的虚拟DOM结构,和旧的虚拟DOM结构对比,尝试复用标签就地更新内容。在内存中比较变化部分,然后给真实DOM打补丁
那我们来回顾一下以前学过的真实DOM树。在document对象上,渲染到浏览器上显示的标签
而虚拟DOM的本质是保存节点信息,属性和内容的一个JS对象。
为什么用虚拟DOM呢?因为真实DOM属性过多,遍历耗时,下面来介绍一种diff算法,同根比较如果根元素变化,整个DOM树删除重建;同级比较如果根元素不变,属性改变更新属性
那么如果标签内子标签或者内容改变,那么diff算法是如何改变的,现在就来引入关键字key,具体来了解key是怎么用的
<template>
<div>
<ul>
<li v-for="(val, ind) in arr" :key="ind">
{{ val }}
</li>
</ul>
<button @click="btn">下标1位置插入新来的</button>
</div>
</template>
<script>
export default {
data(){
return {
arr: ['老大', "老二", '老三']
}
},
methods: {
btn(){
this.arr.splice(1, 0, '新来的')
}
}
}
</script>
<style>
</style>
在上述代码中,我用了:key=ind表示Key是索引值从0开始,一般对于数组的话,可以这样进行设置。这样想,当我们没有设置key的时候,这个更新机制如下图
会最大限度尝试修改/复用相同类型元素,也就是说我们新增了一个li 后面三个li的值都会发生变化。
在我们设置了key值为索引后,根据key比较然后就地更新,也就是说这种方法和上面的无key方法是一样的效果。
在我们设置了key值唯一不重复的字符串或数字,最典型就是id如下所示
<template>
<div>
<ul>
<li v-for="obj in arr" :key="obj.id">
{{ obj.name }}
<input type="text">
</li>
</ul>
<button @click="btn">下标1位置插入新来的</button>
</div>
</template>
<script>
export default {
data() {
return {
arr: [
{
name: '老大',
id: 50
},
{
name: '老二',
id: 31
},
{
name: '老三',
id: 10
}
],
};
},
methods: {
btn(){
this.arr.splice(1, 0, {
id: 19,
name: '新来的'
})
}
}
};
</script>
<style>
</style>
最后的效果如下图所示
原则上是有id用id 无id用索引,并且key可以配合虚拟DOM提高更新的性能。
现对上述内容进行一个总结
下一个问题来讲讲动态class和动态style属性
<template>
<div>
<!-- 语法:
:class="{类名: 布尔值}"
使用场景: vue变量控制标签是否应该有类名
-->
<p :class="{red_str: bool}">动态class</p>
</div>
</template>
<script>
export default {
data(){
return {
bool: true
}
}
}
</script>
<style scoped>
.red_str{
color: red;
}
</style>
<template>
<div>
<!-- 动态style语法
:style="{css属性名: 值}"
-->
<p :style="{backgroundColor: colorStr}">动态style</p>
</div>
</template>
<script>
export default {
data(){
return {
colorStr: 'red'
}
}
}
</script>
<style>
</style>
2. Vue基础_过滤器
过滤器是转换格式,就是一个函数,传入值返回处理后的值。过滤器只能用来插值表达式和v-bind动态属性中。下面列举了v-bind的属性
v-bind:title 鼠标移上的显示 v-bind:src 绑定图片路径 v-bind:html 绑定HTML文本和标签 v-bind:text 绑定文本 v-bind:class 绑定类样式 v-bind:style 动态绑定样式
<template>
<div>
<p>原来的样子: {{ msg }}</p>
<!-- 2. 过滤器使用
语法: {{ 值 | 过滤器名字 }}
-->
<p>使用翻转过滤器: {{ msg | reverse }}</p>
<p :title="msg | toUp">鼠标长停</p>
</div>
</template>
<script>
export default {
data(){
return {
msg: 'Hello, Vue'
}
},
// 方式2: 局部 - 过滤器
// 只能在当前vue文件内使用
/*
语法:
filters: {
过滤器名字 (val) {
return 处理后的值
}
}
*/
filters: {
toUp (val) {
return val.toUpperCase()
}
}
}
</script>
<style>
</style>
上面的过滤器场景是用在字符串翻转和字符串转大写。
如果是在主App.vue文件中,那么属于全局的过滤器,需要用到vue.filter来定义和声明,在单个vue文件中,直接使用filters即可。在使用过滤器时,一定是前者Vue变量后者过滤器名字。那么过滤器既然是个函数,就应该可以给过滤器进行传参,并且一个插值表达式或者动态属性可以使用多个过滤器。如下所示
<template>
<div>
<p>原来的样子: {{ msg }}</p>
<!-- 1.
给过滤器传值
语法: vue变量 | 过滤器名(值)
-->
<p>使用翻转过滤器: {{ msg | reverse('|') }}</p>
<!-- 2.
多个过滤利使用
语法: vue变量 | 过滤器1 | 过滤器2
-->
<p :title="msg | toUp | reverse('|')">鼠标长停</p>
</div>
</template>
<script>
export default {
data(){
return {
msg: 'Hello, Vue'
}
},
filters: {
toUp (val) {
return val.toUpperCase()
}
}
}
</script>
<style>
</style>
3. Vue基础_计算属性
当我们需要a和b变量改变,那么如何同步更新num的值呢?因此我们又引入另一个语法-计算属性。
<template>
<div>
<p>{{ num }}</p>
</div>
</template>
<script>
export default {
data(){
return {
a: 10,
b: 20
}
},
// 计算属性:
// 场景: 一个变量的值, 需要用另外变量计算而得来
/*
语法:
computed: {
计算属性名 () {
return 值
}
}
*/
// 注意: 计算属性和data属性都是变量-不能重名
// 注意2: 函数内变量变化, 会自动重新计算结果返回
computed: {
num(){
return this.a + this.b
}
}
}
</script>
<style>
</style>
计算属性也是vue数据变量,所以不要和data里重名,用法和data相同。同样我们可以用函数调用实现这个功能,那么计算属性的优势在哪呢?
计算属性,基于依赖项的值进行缓存,依赖的变量不变的情况,都直接从缓存取结果。
<template>
<div>
<p>{{ reverseMessage }}</p>
<p>{{ reverseMessage }}</p>
<p>{{ reverseMessage }}</p>
<p>{{ getMessage() }}</p>
<p>{{ getMessage() }}</p>
<p>{{ getMessage() }}</p>
</div>
</template>
<script>
export default {
data(){
return {
msg: "Hello, Vue"
}
},
// 计算属性优势:
// 带缓存
// 计算属性对应函数执行后, 会把return值缓存起来
// 依赖项不变, 多次调用都是从缓存取值
// 依赖项值-变化, 函数会"自动"重新执行-并缓存新的值
computed: {
reverseMessage(){
console.log("计算属性执行了");
return this.msg.split("").reverse().join("")
}
},
methods: {
getMessage(){
console.log("函数执行了");
return this.msg.split("").reverse().join("")
}
}
}
</script>
<style>
</style>
计算属性好处是带缓存,依赖项不变,直接从缓存取,依赖项改变,函数自动执行并重新缓存。计算属性也可以用在输入框上,双向绑定。set函数接收要赋予的值,get里要返回给这个计算属性具体值
<template>
<div>
<div>
<span>姓名:</span>
<input type="text" v-model="full">
</div>
</div>
</template>
<script>
// 问题: 给计算属性赋值 - 需要setter
// 解决:
/*
完整语法:
computed: {
"计算属性名" (){},
"计算属性名": {
set(值){
},
get(){
return 值
}
}
}
*/
export default {
computed: {
full: {
// 给full赋值触发set方法
set(val){
console.log(val)
},
// 使用full的值触发get方法
get(){
return "无名氏"
}
}
}
}
</script>
<style>
</style>
4. Vue基础_侦听器
可以倾听data/computed属性值的改变
<template>
<div>
<input type="text" v-model="name">
</div>
</template>
<script>
export default {
data(){
return {
name: ""
}
},
// 目标: 侦听到name值的改变
/*
语法:
watch: {
变量名 (newVal, oldVal){
// 变量名对应值改变这里自动触发
}
}
*/
watch: {
// newVal: 当前最新值
// oldVal: 上一刻值
name(newVal, oldVal){
console.log(newVal, oldVal);
}
}
}
</script>
<style>
</style>
使用watch配置项,key是要倾听的data,也可以倾听对象。如果需要深度监听的话 需要设置
以上便是整个vue的部分基础知识。在下一章中我会在一个小项目中使用这些语法。
更多推荐
所有评论(0)