使用this.$nextTick()获取不到数据更新后的this.$refs.xxx.及场景分析
作者:Rised
使用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的操作
到此这篇关于使用this.$nextTick()获取不到数据更新后的this.$refs.xxx.及场景分析的文章就介绍到这了,更多相关this.$nextTick()获取不到数据内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!