vue 之 $nextTick

官方说明:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM

疑问:

  1. DOM 更新循环是指什么?
  2. 下次更新循环是什么时候?
  3. 修改数据之后使用,是加快了数据更新进度吗?
  4. 在什么情况下要用到?

原理

   vue的响应式并不是数据发生变化之后DOM立即变化,而是按照一定的方式进行DOM的更新

第一个案例:

<template>
  <div >
    <input type="text" ref="ipt" v-if="isShow" />
    <button @click="fn" v-else>点击修改</button>
  </div>
</template>

<script>

export default {
  name: "App",
  data() {
    return {
      isShow: false,
    };
  },
  methods: {
    fn() {
      this.isShow = true;
      console.log(this.$refs.ipt);  // undefined
this.$refs.ipt.focus() //报错
}, }, }; </script> <style></style>

遇到上述情况怎么解决呢?

this.isShow = true;
setTimeout(() => {
   console.log(this.$refs.ipt); //<input type="text">
this.$refs.ipt.focus()
}, 0); 
//或者
this.$nextTick(() => {
console.log(this.$refs.ipt); //<input type="text">
this.$refs.ipt.focus()
});

分析:因为  this.isShow = true;时,虚拟dom需要通过diff算法进行更新,这个过程是需要时间的,而同步的代码中,this.$refs.ipt 所需时间 小于  这个渲染时间

第二个案例

<template>
  <section>
    <h1 ref="hello">{{ value }}</h1>
    <el-button type="danger" @click="get">点击</el-button>
  </section>
</template>
<script>
  export default {
    data() {
      return {
        value: 'Hello World ~'
      };
    },
    methods: {
      get() {
        this.value = '你好啊';
        console.log(this.$refs['hello'].innerText); // Hello World ~
        this.$nextTick(() => {
          console.log(this.$refs['hello'].innerText); // 你好啊
        });
      }
    },
    mounted() {
    },
    created() {
    }
  }
</script>

  

应用场景:

    需要在视图更新之后,基于新的视图进行操作

思考的问题:$nextTick  如何 结合 created 和 mounted 来处理问题

疑问:

疑问一 . this.$nextTick 为什么要放在 created 或者 mounted ,有什么区别

疑问二 . 为什么$nextTick能保证子组件都加载完?

第一步:了解 created

//组件创建之后
 created() {
      // 可以操作数据,发送ajax请求,并且可以实现
      // vue对页面的影响 应用:发送ajax请求
      console.log('组件创建后:'+this.msg);   //哈哈哈
 }  

第二步:了解mounted

//装载数据到DOM之后
 mounted() {
      // 可以操作DOM
      console.log('DOM装载后:'+document.getElementById('app'));  //<div ></div></div>
 }

第三步:分析

疑问一

1.例如在parent 里面有 两个child组件,但是父组件通过异步获取的数据data(created),data里面有childData1 和 childData2 那么此时通过this.$refs.child1是获取不到的,所以需要用到 this.$nextTick,这样可以解决刚才的案例问题(但是,若是同步的组件,那么在parent里面的 mounted 获取 this.$refs.child1也是可以的,那么就不需要该死的this.$nextTick)

2.将this.$nextTict 写在 created 和 mounted 没太大的区别,只是created 会优先 mounted执行,参考 vue 之 生命周期(钩子)

疑问二

如果是同步子组件,mounted 就已经能保证了同步子组件都加载完了。因为对于一个页面来说,第一次 DOM 更新循环结束,也就是 mounted 的时候。

同步顺序是 parent created → child created → child mounted → child $nextTick → parent mounted → parent $nextTick

如果是异步子组件,你需要在 mounted 里写 $nextTick,但也并不能完全保证子组件加载完毕,因为异步子组件里还可以再套异步孙子组件。

总而言之,同步子组件,写 created + $nextTick 和写 mounted 都行;异步子组件,除非是在父组件中直接操作异步子组件的生命周期钩子、或者子组件通过 $emit 的方式通知父组件,否则单纯靠父组件自己,是无法百分百保证的。

参考:http://errornoerror.com/question/10048646268771205890/