使用this.$nextTick()获取不到数据更新后的this.$refs.xxx.及场景分析
Rised 人气:0使用this.$nextTick()获取不到数据更新后的this.$refs.xxx.
今天遇到了这样一个场景,在数据更新之后,使用this.$nextTick(()=>{console.log(this.$refs.xxx)}) 获取不到改dom,但是用setTimeout能够获取到,在此记录一下。
先看代码
<!--这是模板代码,父级用的v-else-if,与父级同级的还有两个盒子,分别用v-if和v-else控制着--> <div ref="articleContent" class="right" v-html="articles.content"></div> //这是script代码 mounted() { this.getArticlesDetail() }, methods: { async getArticlesDetail(){ try { const {data}= await getArticlesDetail(this.articleId); /* vue数据更新是异步的 ,在这一步数据加载出来,但是组件还没没有渲染出来,因为在组件中有个v-if判断,在数据加载出来之后,才能渲染出来组件*/ /* console.log(this.$refs.articleContent) */ /* 所以要放在定时器是异步执行,试了用this.$nextTick,不行 */ /* */ this.articles = data /* 只能用setitmeout是因为数据在在下个Event Loop中也出不来,这是因为v-if中的条件在下次事件循环中也不一定能够满足。但是setTimeout的执行时机是没有办法确定前边的任务到底需要多长时间执行完 */ this.$nextTick(() => { console.log(this.$refs.articleContent) }); console.log(data) } catch (error) { if(error.response && error.response.status===404){ this.errStatus=404; this.$toast('服务器错误') } console.log(error) this.$toast('请求失败,请稍后再试') } /* 无论成功失败都要调用loading为false,关闭它 */ this.loading=false } },
这是控制台打印的效果.
获取不到.
vue官网中对于vue.nextTick()中的解释:
也就是说在下个事件循环中没有满足v-if中的条件,所以没有获取到数据。
在vue 中的devtools中 可以获取到。
然后我们修改成setTimeout
<!--这是模板代码,父级用的v-else-if,与父级同级的还有两个盒子,分别用v-if和v-else控制着--> <div ref="articleContent" class="right" v-html="articles.content"></div> //这是script代码 mounted() { this.getArticlesDetail() }, methods: { async getArticlesDetail(){ try { const {data}= await getArticlesDetail(this.articleId); /* vue数据更新是异步的 ,在这一步数据加载出来,但是组件还没没有渲染出来,因为在组件中有个v-if判断,在数据加载出来之后,才能渲染出来组件*/ /* console.log(this.$refs.articleContent) */ /* 所以要放在定时器是异步执行,试了用this.$nextTick,不行 */ /* */ this.articles = data /* 只能用setitmeout是因为数据在在下个Event Loop中也出不来,这是因为v-if中的条件在下次事件循环中也不一定能够满足。但是setTimeout的执行时机是没有办法确定前边的任务到底需要多长时间执行完 */ setTimeout(() => { console.log(this.$refs.articleContent) }); console.log(data) } catch (error) { if(error.response && error.response.status===404){ this.errStatus=404; this.$toast('服务器错误') } console.log(error) this.$toast('请求失败,请稍后再试') } /* 无论成功失败都要调用loading为false,关闭它 */ this.loading=false } },
这是控制台打印的效果
可以看出来有效果.
在vue中的devtools中也有,
这是为什么呢?
只能用setitmeout是因为数据在在下个Event Loop中也出不来,这是因为v-if中的条件在下次事件循环中也不一定能够满足。但是setTimeout的执行时机是没有办法确定前边的任务到底需要多长时间执行完,所以使用setTimeout会更好。
补充:详解Vue中this.$nextTick()用法
语法:
this.$nextTick( [ callback ] )
用法:
this.$nextTick将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法 Vue.nextTick
一样,不同的是回调的 this
自动绑定到调用它的实例上,等同于updated生命周期函数
updated用法:由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。
示例:
下面讲解一个点击按钮是输入框聚焦的示例:
<template> <div> <input ref="myInp" type="text" placeholder="这是一个输入框" v-if="isShow"> <button v-else @click="btn">点击我进行搜索</button> </div> </template> <script> // 获取到输入框 // 输入框调用事件方法focus()达到聚焦行为 export default { data(){ return { isShow: false } }, methods: { btn(){ this.isShow = true; this.$refs.myInp.focus(); // 没有效果 // 原因: data变化更新DOM是异步的 // 输入框还没有挂载到真实DOM上 // 解决: // this.$nextTick(() => { // this.$refs.myInp.focus() // }) } //async btn(){ // this.isShow = true; // // // 扩展: await取代回调函数 // // $nextTick()原地返回Promise对象 // await this.$nextTick() // this.$refs.myInp.focus() //} }, //扩展 updated(){ // this.$refs.myInp.focus() } } </script>
直接在methods获取DOM调用聚焦方法是没有效果的,更改之后的文本是需要 dom 更新之后才会实现的,就像我们把将要打印输出的代码放在 setTimeout(fn, 0) 中,这时候用this.$nextTick就能合理解决此问题,如果我们想进页面就处于聚焦状态的话就可以使用updated生命周期函数,调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作
加载全部内容