关于Vue.$set 、Vue中data选项中的值做为参数传递、Vue.$nextTick、v-if与v-show的总结
一 Vue.$nextTick() 的背景及用法
JS 运行机制(事件循环)
JS执行是单线程的,它是基于事件循环的。
1.所有同步任务都在主线程上执行,形成一个执行栈。
2.主线程之外,会存在一个任务队列,只要异步任务有了结果,就在任务队列中放置一个事件。
3.当执行栈中的所有同步任务执行完后,就会读取任务队列中的任务。任务队列中对应的异步任务,会结束等待状态,进入执行栈。
主线程不断重复第三步。(每执行完第三步渲染一次页面,然后接着执行第三步)
主线程从 " 任务队列 " 中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为 E v e n t L o o p (事件循环)。 主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)。 主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为EventLoop(事件循环)。
也就是说,某些操作(点击按钮,ajax请求)执行后
,会使他们相应的操作(代码)进入任务队列
中,当主线程执行完毕
,会获取任务队列中执行完的结果,渲染页面
,然后再获取结果吗,再渲染页面(循环)。
Vue.nextTick 官网介绍
在下次DOM更新循环结束之后
执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的DOM。
Vue DOM更新是异步
执行的(每从任务队列中取一次数据,才渲染一次页面
),即在任务队列的代码中
修改,获取Dom数据时是获取不到的,因为视图不会立即更新
。所以设置了 Vue.nextTick(),目的就是等同一数据循环中的所有数据变化完成之后,再统一进行视图更新。
demo
//如果有一个 隐藏的input 框 :v-show=‘false’,你把他显示出来并且让他获取焦点
// 反例
show(){
this.show = true //修改 v-show
document.getElementById("input").focus() //在第一个 tick 里,获取不到输入框,自然也获取不到焦点
}
// 正例
show(){
this.show = true //修改 v-show
this.$nextTick( ()=> document.getElementById("input").focus()) // Vue会在dom变化完执行这个操作,所以可以
}
// 获取元素宽度
<div id="app">
<div ref="myW" v-if="show">{{ message }}</div>
<button @click="getMyW">获取div元素宽度</button>
</div>
getMyW() {
this.show = true;
//this.message = this.$refs.myW.offsetWidth;
//报错 TypeError: this.$refs.myW is undefined
this.$nextTick(()=>{
//dom元素更新后执行,此时能拿到p元素的属性
this.message = this.$refs.myW.offsetWidth;
})
}
二 Vue.$set的背景及用法
vue 双向绑定的原理:
Vue 会在初始化实例时对属性执行 getter/setter 转化过程,所以属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的。
受现代 JavaScript 的限制 (而且 Object.observe 也已经被废弃),Vue 不能检测到对象属性的添加或删除。 这个时候可以用this.$set(),给新添加的对象属性,或数组元素添加getter,setter方法
简单说即是:当你发现你给对象加了一个属性,在控制台能打印出来,但是却没有更新到视图上时,也许这个时候就需要用到this.$set()这个方法了
demo
<template>
<div class="home">
<div>{{student}}</div>
<div v-for="(item,index) in items" :key="index">{{item}}</div>
<button @click="btn()">修改</button>
</div>
</template>
<script>
import Vue from 'vue' // 别忘了引入
export default {
name: 'Home',
data(){
return{
student:{
name:'张三',
},
items:[1, 2, 3],
}
},
methods:{
btn(){
Vue.set(this.student, 'age', 18);
Vue.set(this.items, 1, 'two');
console.log(this.student,this.items);
}
}
}
</script>
三 Vue中data选项中的值做为参数传递
把data中的某个对象赋值给一个变量,修改这个变量,把data中的对象也会被一同修改。即这个赋值是引用了地址。
demo
<script>
export default {
data () {
return {
userLists: [
{
id: 1,
name: '张三'
}
]
}
},
methods: {
test () {
// 这里直接赋值给对象
let tmpArr = this.userLists
// 因为是地址引用,所以这个时候data中userLists的id也会变
tmpArr.id = 2
// 正确的赋值方式
let tmpArr = JSON.parse(JSON.stringify(this.userLists))
// 对象深拷贝,这个时候,二者不会相互影响
tmpArr.id = 2
}
}
}
</script>
四 v-if与v-show
相同点:v-if与v-show都可以动态控制dom元素显示隐藏
不同点:v-if显示隐藏是将dom元素整个添加或删除,而v-show隐藏则是为该元素添加css–display:none,dom元素还在。
v-if与v-show使用对比:
1.手段:v-if是动态的向DOM树内添加或者删除DOM元素;v-show是通过设置DOM元素的display样式属性控制显隐;
2.编译过程:v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;v-show只是简单的基于css切换;
3.编译条件:v-if是惰性的,如果初始条件为假,则什么也不做;只有在条件第一次变为真时才开始局部编译(编译被缓存?编译被缓存后,然后再切换的时候进行局部卸载); v-show是在任何条件下(首次条件是否为真)都被编译,然后被缓存,而且DOM元素保留;
4.性能消耗:v-if有更高的切换消耗;v-show有更高的初始渲染消耗;
5.使用场景:v-if适合运营条件不大可能改变;v-show适合频繁切换。