vue的refs和ref
获取dom元素
- 通过refs获取dom元素一般在mounted生命周期函数执行时获取
- 在mounted函数执行之前是无法获取到dom元素的,因为此时dom还没有挂载到页面中
- 当ref绑定在
v-for
里面时,此时通过refs获取到的是一个数组
#普通绑定
<div id="app">
<p ref="p1">普通绑定</p>
</div>
<script>
new Vue({
el:"#app",
created(){
console.log(this.$refs.p1) #undefined
},
mounted(){
console.log(this.$refs.p1) #p1的dom元素
}
})
</script>
#在v-for中绑定
<div id="app">
<ul>
<li v-for="i in 5" ref="li">{{i}}</li>
</ul>
</div>
<script>
new Vue({
el:"#app",
mounted(){
console.log(this.$refs.li) #获取到的是一个含有5个li元素的数组
}
})
</script>
refs获取dom元素异常
- 当从后台获取数据,然后通过v-if或v-for动态渲染页面元素时,如果在mounted函数中直接通过refs获取dom元素,得到的结果是undefined
- vue在更新dom元素时是采用异步的方式,只要检测到数据的变化,就开启的一个异步队列,然后把这个异步队列放到事件循环的末尾,等待执行
- 也就是vue在数据更新后不是直接重新渲染页面元素,而是等待下一次事件循环开始才进行重新渲染的
- 当在created或则mounted发起请求获取数据时,data和methods中的数据已经初始化完成,也就是此时获取数据之后修改data中的数据,代表着数据更新
- 解决方式1:添加nextTick函数
- 调用nextTick函数:this.$nextTick()
- nextTick函数返回的是一个promise对象
- nextTick函数作用:在数据更新之后,它会等待重新渲染页面元素完成,才会执行它的回调函数
<body>
<div id="app">
<ul>
<li v-for="i in arr" :key="i.id" ref="li">
<span>{{i.name}}</span>
</li>
</ul>
</div>
<script src="./data.js"></script>
<script>
new Vue({
el: "#app",
data: {
arr: [],
bool: false
},
methods: {
async getData() {
data().then(async data => {
this.arr = data
await this.$nextTick()
console.log(this.$refs.li) #获取到的是一个含有5个li元素的数组
})
},
},
created() {
this.getData()
},
})
</script>
</body>
- 解决方式2:在mounted函数中调用修改数据函数时,添加async,await修饰符
- 只适合修改函数返回一个promise对象的情况
- 原理:在async函数中,只要遇到await修饰的代码段,程序都会停止下来,等待代码段执行完成之后,才会继续向下执行,此时分为两部分"修改数据,更新dom元素都属于await修饰的代码段",await修饰的代码段执行完成,就代表着dom元素已经更新完成
<body>
<div id="app">
<ul>
<li v-for="i in arr" :key="i.id" ref="li">
<span>{{i.name}}</span>
</li>
</ul>
</div>
<script src="./data.js"></script>
<script>
new Vue({
el: "#app",
data: {
arr: [],
bool: false
},
methods: {
async getData() {
let arr = await data().catch(err => err)
this.arr = arr
},
},
async mounted(){
await this.getData()
console.log(this.$refs.li) #获取到的是一个含有5个li元素的数组
}
})
</script>
</body>
- 解决方式3:由于无论在任何一个地方调用methods中的函数修改data中的数据都会重新渲染页面中的元素,也就是代表着updated()生命周期函数都会执行
- updated生命周期函数执行时,页面中的元素都已经重新渲染完成,所以可以获取dom元素
<body>
<div id="app">
<ul>
<li v-for="i in arr" :key="i.id" ref="li">
<span>{{i.name}}</span>
</li>
</ul>
</div>
<script src="./data.js"></script>
<script>
new Vue({
el: "#app",
data: {
arr: [],
bool: false
},
methods: {
async getData() {
let arr = await data().catch(err => err)
this.arr = arr
},
},
mounted(){
this.getData()
},
updated(){
console.log(this.$refs.li) #获取到的是一个含有5个li元素的数组
}
})
</script>
</body>