$nextTick使用

81 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

在使用Vue的时候我们能发现,我们在数据里面操作了dom,或者改变了数据,并不能立即同步到真实的dom上,也就是立即改变数据后,我们如果要使用dom上的数据的话,发现还是以前的数据。对此,Vue提供了nextTick的方法,在里面可以拿到dom下次更新后的数据。

我们分三种常见使用场景来看:

在未挂载的时候操作dom:

比如在created和beforeMount中改变dom,因为此时还未挂载,所以其实还没有真实dom,现在改变dom是不生效的。

<body>
    <div id="app">
      <p id="text">{{msg}}</p>
      <button @click="changeHtml">gabian</button>
    </div>
</body>
<script>
    new Vue({
      el: "#app",
      data: {
        msg: "Hello Vue!",
      },
      beforeMount() {
        document.getElementById("text").innerText = "我改变了额!";
      },
    });
</script>

执行可以发现,改变的数据并没有挂载上去,我们试试用$nextTick;

 new Vue({
      el: "#app",
      data: {
        msg: "Hello Vue!",
      },
      beforeMount() {
         this.$nextTick(function () {
            document.getElementById("text").innerText = "我改变了额!";
          });
      },
    });

执行结果:

image.png

其实在这里,nextTick就是在数据挂载(也就是下次更新)之后才去执行的.

通过下面代码,发现mounted的执行是优先于beforeMount中的$nextTick的。

 beforeMount() {
        this.$nextTick(function () {
          setTimeout(function () {
            document.getElementById("text").innerText = "我改变了额!";
          },1000)
          console.log(document.getElementById("text"),'beforeMount');
        });
      },

在mounted中使用

mounted钩子执行的时候,所有的dom不一定全部挂载完成,如果要做dom操作最好在nextTick中执行,像异步组件之类的,我找了一个例子。

 <div id="app">
      <div v-show="status">
        <input
          ref="inp"
          v-model="inputData"
          type="text"
          placeholder="请输入..."
        />
      </div>
    </div>
    
     new Vue({
      el: "#app",
      data: {
        status: false,
      },
      mounted() {
        this.status = true;
        
        // this.$refs.inp.focus({ cursor: "start" }); // 未生效

        this.$nextTick(function () {
          this.$refs.inp.focus({ cursor: "start" }); // 生效
        });
      },
    });

像动态组件和异步组件之类的,就可能会出现当你想要操作时还没挂载完成的问题,这个时候对dom的操作就可以使用nextTick去等待他挂载好后执行。

数据更新:

这种是最常见的场景,当改变数据的时候,数据更新可能还没有挂载到dom上,但这个时候需要用到改变后的数据时,就可以用nextTick。

 <div id="app">
      <p id="text">{{msg}}</p>
      <div v-show="status">
        <input
          ref="inp"
          type="text"
          v-model="inputData"
          placeholder="请输入..."
        />
      </div>

      <button ref="btn" @click="changeHtml">更改</button>
 </div>

  new Vue({
      el: "#app",
      data: {
        msg: "Hello Vue!",
        inputData: "123456",
        status: false,
      },
      methods: {
        changeHtml() {
          this.inputData = "别输了,最大只能放50个字符...";
          console.log(this.$refs.inp.value, 'changeHtml'); // 123456
          this.$nextTick(function () {
            console.log(this.$refs.inp.value, 'changeHtml-nextTick'); //别输了,最大只能放50个字
          });
        },
      },
      mounted() {
        this.status = true;
      },
      beforeUpdate() {
        console.log(this.$refs.inp.value, 'beforeUpdate');  // 123456
        this.$nextTick(function () {
          console.log(this.$refs.inp.value, "beforeUpdate-nextTick"); //别输了,最大只能放50个字符...
        });
      },
    });

这里方法内的$nextTick的回调函数将在update执行完之后执行,执行顺序依次是update、updated里面的nextTick、beforeUpdate里面的nextTick、方法里面的nextTick.

nextTick作用都是在下一次更新后执行里面回调,但是有各种的使用场景,比如之上的,数据更新,数据挂载,数据未挂载时的操作。

对于nextTick了解不是很多,如果有使用上的错误和补充,欢迎指出。