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

本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!前端

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>
复制代码

01.gif

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>
复制代码

02.gif

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>
复制代码

03.png

咱们发现,第一次的值和第二次的值,是不同的;
由于视图上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 更新后在执行
  })
}
复制代码
相关文章
相关标签/搜索