1. 条件渲染
1、v-if
- 写法:
v-ifv-else-ifv-else
- 适用于:频率较低的场景
- 特点:创建或移除dom节点
- 注意:以上写法可以连用,但不能被打断,同js语法一致
2、v-show
- 写法:
v-show="表达式" - 适用于:频率较高的场景
- 特点:样式隐藏,display:none
3、v-if可能无法被获取到,v-show永远可以
<div v-if="n===1">1</div> <!-- 1如果成立,后面的就都不走了 -->
<div v-else-if="n===2">2</div>
<div v-else-if="n===3">3</div>
<div v-else>other</div> <!-- 前面的都不走,就走这个了 -->
4、<templata>模板 虚拟标签 不生成实际内容
<templata v-if="n===1">
<div>1</div>
<div>2</div>
<div>3</div>
</templata>
<!-- 会生成三个连续<div>标签,template标签就消失了 -->
2. 列表渲染
1、基础
1、{{}}插值内容可能来源data属性、计算属性、methods或列表行参(item)
2、v-for
- 1、展示列表数据
- 2、语法:
- v-for="(item,index) in list" :key="item.id"
- {{item.name}}
- 3、可遍历的数据:数组、对象、字符串、指定次数
- 4、举例
<!-- 遍历数组 -->
<li v-for="(item,index) in list" :key="item.id">{{item.name}}</li>
<!-- list=[{id:1,name:1},{id:2,name:2}] -->
<!-- 遍历对象 -->
<li v-for="(value,key) in obj" :key="key">{{value}}</li>
<!-- obj={id:1,name:1,age:1} -->
<!-- 第1个行参是value,第2个行参是key -->
<!-- 遍历字符串 -->
<li v-for="(char,index) in str" :key="index">{{value}}</li>
<!-- str="abc" -->
<!-- 第1个行参是char,第2个行参是index -->
<!-- 遍历指定次数 -->
<li v-for="(num,index) in 5" :key="index">{{num}}</li>
<!-- 第1个行参是num,第2个行参是index -->
2、面试题:react、vue中的key有什么作用?(key的内部原理)
1. 虚拟DOM中key的作用:
- key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,
随后Vue对新旧虚拟DOM进行差异比较,其中key是重要的比较方式,比较规则如下:
2.对比规则:
-
旧虚拟DOM与新虚拟DOM的key相同:
- 若虚拟DOM中内容(文本和标签)没变, 直接使用之前的真实DOM;
- 若虚拟DOM中内容变了, 文本变了替换文本,标签变了替换标签,生成新的真实DOM,替换掉页面中之前的真实DOM。
-
旧虚拟DOM中未找到与新虚拟DOM相同的key
- 创建新的真实DOM,随后渲染到到页面。
3. 用index作为key可能会引发的问题:
若对数据进行:逆序添加、逆序删除等破坏顺序操作:
会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。如果结构中还包含输入类的DOM:
会产生错误DOM更新 ==> 界面有问题。
4. 开发中如何选择key?:
- 1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
- 2.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的。
3、 列表过滤和排序
对数组进行数据操作,一般不对原数据直接操作,可以拷贝一份数据
对数组进行筛选然后返回,可以通过原数组过滤赋值到新数组
1.filter不改变原数组,返回新数组
2.watch的immediate是初始化回调函数,其中的newd是初始默认值
3.任何值的indexOf,检测""都能检测到,为0
4.数组sort方法改变原数组,传参两个,升序是前-后,降序是后-前
3.vue如何加工data变成响应式数据
1、简单叙述data数据是如何处理的
- 1.加工用户传入的data(data对象)
- 2.vm._data = data
控制台发现_data的数据都是`reactiveGetter`,是vue加工过的,将用户data数据劫持
- 3._data与vm做代理,使_data代理到vm中
2、js传参中的对象
对象作为函数传参时,传递的实际是对象的内存地址,
函数里面外面指向的是同一个内存地址,改变的自然也就是同一个对象;
但当传参被重新赋值替换整个对象时,传参被赋予一个新的内存地址,切断了与之前地址的联系。
但是却并没有删除或改变原本的外面的内存地址,所以外面的对象依旧指向的是原本的地址
3、对象属性的监听和动态添加对象的属性
//示例1
let data = {
name:'xx',
age:'xx',
}
Object.defineProperty(data,name,{
get(){
return data.name
},
set(val){
data.name=val
}
})
//注意这样写会造成内存溢出,当读取data属性时,会调get方法,而get方法返回data.name,此时相当于又读取了data.name,又读取了get,周而复始,死循环了
//所以原则上一般不对原数据进行直接修改,先深拷贝再处理。
//示例2
//用户传入的data数据
let data = {
name:'xx',
address:'xx',
}
//创建一个监视的实例对象,用于监视data中属性的变化
const obs = new Observer(data)
console.log(obs)
//准备一个vm实例对象
let vm = {}
vm._data = data = obs
//将实例对象赋给data和_data,使三个变量都引用同一内存地址
//data换了新的内存地址,而Observer中的传参却没有更新内存地址,所以访问的是原来的内存地址,强制只有通过构造函数实例才能修改最初的data传参
//而构造函数中修改传参,实际是保留了函数创建时的变量环境,即闭包,这样读取属性不会产生死循环
function Observer(obj){
//汇总对象中所有的属性形成一个数组
const keys = Object.keys(obj)
//遍历
keys.forEach((k)=>{
//拷贝一份data的属性到实例对象obs上,使obs属性被读取或修改时,实际操作的都是data对象
Object.defineProperty(this,k,{
get(){
return obj[k]
},
set(val){
console.log(`${k}被改了,我要去解析模板,生成虚拟DOM.....我要开始忙了`)
obj[k] = val
}
})
})
}
//此处是一层遍历赋值,vue做到了无论多深的层级的对象属性,都能被监听到,做了递归遍历,修改监听所有属性
//get和set只对已经存在的data对象的属性有效,那么在后续使用中需要增加新的属性怎么实现响应式?
// 一级属性可以通过提前添加变量在this上
// 对象中的属性可以通过Vue.set(this.obj,'key',value)添加对象的响应式属性,且即时更新页面
// data=>_data=>vm
// 从data到_data的过程叫做数据劫持,从_data到vm的过程叫做数据代理。虽然底层都用到了Object.defineProperty方法。
// 在数据劫持里,vue处理数据的get和set使其变成响应式数据,set数据更新引起模板重新解析,生成虚拟dom,对比新旧虚拟dom,该更新更新该复用复用。
// 数组的更新看key,key存在,对比内容节点,一样的复用,不一样的更新;新生成的key在旧的里面不存在,直接生成新的
// 从_data到vm的过程,只是为了在页面使用时更加简洁方便。
//添加响应式的对象属性:
//vue对对象中新增的属性默认是不做监听的,需要调用api
//注意obj只能是this下面的对象,不可以直接在this中添加属性。
//以下三者等价
Vue.set(this.student,'sex','男')
vm.$set(this.student,'sex','男')
this.$set(this.student,'sex','男')
//新增对象属性经过以上方法加工后,就变成了与_data中一样的get和set,reactive函数,数据变化会引起模板重新解析
//注意:get和set方法只供于对象属性使用。
4、数组监听和修改
读取一个对象不存在的属性,返回undefined
读取一个不存在的对象/变量,直接报错
// 操作数组下标,不会触发响应式
let arr=["王","李","孙"]
arr[0]="刘" //页面没有反应
// 操作数组下标的属性,不会触发响应式
let arr=[{
age:11
},{
age:10
},{
age:15
}]
arr[0].age=20 //页面被更新了
//arr数组都每项都是对象,而对象的属性都是被vue维护的。可以被监听到
//若操作arr[1]={age:222},不生效,因为是对数组直接操作下标
// _data里的一级属性,对象或数组被重新赋值都可以被监听到
vue如何监听数组的变化呢?
1、vue通过7个数组方法监听数组改变
- push:添加元素至数组最后,改变数组长度
- pop:删除数组最后一个元素,改变数组长度
- shift:删除数组第一个元素,改变数组长度
- unshift:添加元素至数组第一位,改变数组长度
- splice:从起始位置删除n个、替换成..(index,n,"")
- sort:数组排序
- reverse:反转数组元素的顺序
以上7个方法都会改变原数组,并且引起模板重新解析
因为vue包装了以上方法,主要两个方面:
1.是沿用Array.push/pop...
2.增加了模板解析?
2、数组重新赋值:filter方法修改数组不会更新数组内容,所以不会被监听到,可以把新返回的内容重新替换给原数组
3、如用数组下标方式修改:vm.$set(this.arr, index, content)
注意:数组中的对象属性,可以被监听到,任意层级的对象属性都能被监听到