• vue中$nextTick详细讲解保证你一看就明白


    1.功能描述

    今天我们要实现这个一个小功能;
    页面渲染完成后展示一个div元素;
    当点击这个div元素后;
    div元素消失;
    出现一个input元素;并且input元素聚焦
    想必大家我觉得简单,我们一起来看看~
    
    创建一个组件,组件名称NextTick.vue;
    在页面中引入注册
    

    2.父组件

    <template>
      <div>
        <next-tick></next-tick>
      </div>
    </template>
    
    <script lang="ts">
    import NextTick from "../components/NextTick.vue"
    export default {
      name:"About",
      components:{
        NextTick
      },
    }
    </script>
    

    3.子组件NextTick.vue

    <template>
        <div>
            <div>我是组件</div>
            <div v-if="flag" class="sun" @click="handerClick">显示input</div>
            <input v-else ref="inputRef" class="yuelaing"/>
        </div>
    </template>
    <script>
    export default {
        data(){
            return{
                flag:true,
            }
        },
        methods: {
            handerClick(){
                this.flag=false;
                this.$refs.inputRef.focus();
            },
        },
    }
    </script>
    

    4为什么是undefined

    this.flag=false;
    this.$refs.inputRef.focus();
    当执行页面操作的时候,this.$refs.inputRef.focus();
    是需要消耗时间的(还没有还得及刷新;还是旧的页面)
    此时还没有获取到dom元素。
    所以会报错。
    
    解决方式1:
    因此只要让页面能够获取元素就行;使用setTimeout
    setTimeout(()=>{
          this.$refs.inputRef.focus();
    },100)
    这样来处理这个问题,是可以的;
    但是显得非常的不专业;
    
    解决方式2:
    //当组件根据最新的data数据,重新在视图上完成渲染后,在执行里面的函调函数
    this.$nextTick(()=>{
        this.$refs.inputRef.focus();
    })
    

    5.将v-if更改为v-show可以获取焦点吗?

    有人说:因为v-if是动态创建和销毁;
    在创建和销毁的过程中,是需要时间的!
    所以才会使用v-if获取不到元素节点
    用v-show就可以避免。
    感觉说的有点道理?
    我们尝试一下将v-if换成v-show
    
    <template>
        <div>
            <div>我是组件</div>
            <div v-show="flag" class="sun" @click="handerClick">显示input</div>
            <input v-show="!flag" ref="inputRef" class="yuelaing"/>
        </div>
    </template>
    <script>
    export default {
        data(){
            return{
                flag:true,
            }
        },
        methods: {
            handerClick(){
                this.flag=false;
                console.log( this.$refs.inputRef);
                this.$refs.inputRef.focus();
            },
        },
    }
    </script>
    

    6.实际结果

    我们发现虽然是页面没有报错,但是还没有聚焦;
    改为v-show明显也不能够解决这个问题
    
    之所以会出现这个问题
    是因为子组件中将this.flag=false后,
    立刻去执行了下面的代码
    this.$refs.inputRef.focus();
    而在执行的时候,视图还没没有来得及刷新;
    还是旧的页面,此时还不能够获取到dom元素
    因此出现了undefined;
    也就是为什么我们加上延时后就可以聚焦了;
    
    当组件根据最新的data数据,
    重新在视图上完成渲染后,在执行里面的函调函数
    这就是$nextTick的基本用法
    this.$nextTick(()=>{
        this.$refs.inputRef.focus();
    })
    

    7.将组件变成页面可以获取焦点吗?

    又有人说:因为是子组件,子组件比父组件后渲染。
    所以没有获取到元素节点。
    这也是理由....
    感觉还没有上一个小伙伴说的对
    为了解决疑惑。我们决定将子组件变成页面在看看
    
    <template>
      <div>
        <div>我是组件</div>
        <div v-show="flag" class="sun" @click="handerClick">显示input</div>
        <input v-show="!flag" ref="inputRef" class="yuelaing"/>
      </div>
    </template>
    <script>
    export default {
      data(){
        return{
            flag:true,
        }
      },
      methods: {
          handerClick(){
            this.flag=false;
            this.$refs.inputRef.focus();
          },
      },
    }
    </script>
    
    我们发现仍然不可以;
    这就充分说明了:
    更新data的数据后,vue并不是实时更新的。
    数据更新到显示到页面有时间差,
    我们在时间差内调用页面数据,当然获取不到。
    也就是说:Vue在更新 DOM 时是异步执行的
    

    8.为什么会有$nextTick

    之所以会有$nextTick;
    因为在vue中数据发生变化后;
    视图上的dom并不会立刻去跟新;
    dom的跟新是需要时间的
    下面我们通过一个小实验来看一下
    
    <template>
      <div>
        <div ref="unique">
          <h1>{{ cont }}</h1>
        </div>
        <div  class="sun" @click="handerClick">改变值</div>
      </div>
    </template>
    <script>
    export default {
      data(){
        return{
          cont:'我是默认值'
        }
      },
      methods: {
          handerClick(){
            this.cont='我改变了默认值';
            console.log('1==>',this.$refs.unique.innerText);
            this.$nextTick(()=>{
              console.log('2==>',this.$refs.unique.innerText);
            })
          },
      },
    }
    </script>
    

    我们发现,第一次的值和第二次的值,是不一样的;
    因为视图上dom的跟新是需要之间的;
    我们在这个之间差内去获取元素值;
    仍然是旧值;所以第一次的值是最初的值;
    第二次的值才是改变后的值;
    由于我们希望跟新数据后,仍然可以立刻获取dom上的值
    所以vue提供了$nextTick就可以解决这个问题
    

    9.Vue.nextTick和this.$nextTick差别

    Vue.nextTick是全局方法
    this.$nextTick( [callback] ) 是实例方法。
    我们都知道一个页面可以有多个实例,
    也就是说this.$nextTick可以精确到某个实例上。
    其实本质上两个是一样的。
    只是一个是全局,一个是精确到某一个实例。
    精确度不一样而已。
    

    10.使用 nextTick的一个小技巧

    我们都知道在生命周期mounted渲染的时候,
    不能百分百保证所有的子组件都能够被渲染,
    因此我们可以在mounted里面使用 this.$nextTick,
    这样就能保证所有的子组件都能被渲染到。
    
    mounted钩子在服务器端渲染期间不被调用。
    mounted: function () {
      this.$nextTick(function () {
        //在数据发生变化,
        //重新在视图上完成渲染后,在执行里面的方法
        //这一句话等同与:
       //将回调延迟到下次 DOM 更新循环之后执行
       //等同于:在修改数据之后,然后等待 DOM 更新后在执行
      })
    }
    
    作者:明月人倚楼
    出处:https://www.cnblogs.com/IwishIcould/

    想问问题,打赏了卑微的博主,求求你备注一下的扣扣或者微信;这样我好联系你;(っ•̀ω•́)っ✎⁾⁾!

    如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,或者关注博主,在此感谢!

    万水千山总是情,打赏5毛买辣条行不行,所以如果你心情还比较高兴,也是可以扫码打赏博主(っ•̀ω•́)っ✎⁾⁾!

    想问问题,打赏了卑微的博主,求求你备注一下的扣扣或者微信;这样我好联系你;(っ•̀ω•́)っ✎⁾⁾!

    支付宝
    微信
    本文版权归作者所有,欢迎转载,未经作者同意须保留此段声明,在文章页面明显位置给出原文连接
    如果文中有什么错误,欢迎指出。以免更多的人被误导。
  • 相关阅读:
    ICPC-Beijing 2006 狼抓兔子
    【模板】多项式求逆
    AHOI2014/JSOI2014 奇怪的计算器
    Hnoi2013 切糕
    Ahoi2014&Jsoi2014 支线剧情
    bzoj3774 最优选择
    WC2019游记
    HNOI2007 分裂游戏
    bzoj1457 棋盘游戏
    poj2484 A Funny Game
  • 原文地址:https://www.cnblogs.com/IwishIcould/p/14961197.html
Copyright © 2020-2023  润新知