本文介绍: nextTick是前端面试中vue框架中必考的部分,一定要掌握。它主要是处理我们再变更完数据以后,无法立刻拿到最新的DOM节点对象的问题。我们可以这样理解:vue执行完渲染后会执行this.nextTick()里面的callback函数。

nextTick是前端面试中vue框架中必考的部分,一定要掌握。它主要是处理我们再变更完数据以后,无法立刻拿到最新的DOM节点对象的问题。我们可以这样理解:vue执行完渲染后会执行this.nextTick()里面的callback函数。

 

使用场景

我们来看一个实际的vue组件

<template>
  <div class="hello">
    <p ref="p_ref">
      当前姓名:<b>{{ name }}</b>
    </p>
    <button @click="changeName">改变名称</button>
  </div>
</template>

<script>
export default {
  name: "Demo",
  data() {
    return {
      name: "张三",
    };
  },
  methods: {
    changeName() {
      this.name = "李四";
      console.log(this.$refs["p_ref"].innerHTML);
    },
  },
};
</script>

在这个组件中,我们定义了一个name属性和一个changeName方法,并给展示name属性绑定了名为“p_ref”的ref引用,这样我们就可以对该DOM节点进行操作。我们在changeName方法中,做了两件事情:首先我们改变了name属性的值,然后我们使用vue的this.$refs方法拿到了真实的dom节点,并打印了dom节点的内容,控制台打印的内容如下:

当前姓名:<b>张三</b>

 很显然这不是我们想要的数据,因为我们改变了组件属性中的name属性,这时候打印的名称应该是李四才对。 我们来用this.nextTick()方法来改写这个组件:

<template>
  <div class="hello">
    <p ref="p_ref">
      当前姓名:<b>{{ name }}</b>
    </p>
    <button @click="changeName">改变名称</button>
  </div>
</template>

<script>
export default {
  name: "Demo",
  data() {
    return {
      name: "张三",
    };
  },
  methods: {
    changeName() {
      this.name = "李四";
      this.$nextTick(() => {
        console.log(this.$refs["p_ref"].innerHTML);
      });
    },
  },
};
</script>

 我们做的事情很简单,我们使用了this.$nextTick()方法,并在函数中定义了一个箭头函数,然后在箭头函数里面打印p标签里面的内容,结果可以猜到:

 

当前姓名:<b>李四</b>

 

这就是this.$nextTick()的作用,帮助我们在改变组件中属性以后,立刻拿到渲染以后的dom节点对象,那它是怎么实现这一功能的呢?

实现原理

首先vue底层会定义一个callback数组来模拟事件队列,通过cb参数传入的函数会经过一个函数包装,在这个包装过程中会执行传入的函数,并处理执行失败的情况以及cb参数不存在的情况,包装完成后会添加到callbacks数组中;然后调用timerFunc函数,该函数就是用各种异步执行的方法调用flushCallbacks函数,在flushCallbacks函数中,将拷贝callbacks中的每一个函数并执行。vue会定义一个变量pending来保证一个事件循环中只调用一次timerFunc函数。 在这过程中,最关键的是如何定义timerFunc函数,因为在各个浏览器下对创建异步执行函数的方法各不相同,下面来介绍主要的方法。

Promise创建异步执行函数

判断方式为:执行typeof Promise 如果返回的是:function则表示支持promise。创建代码如下:

if (typeof Promise !== 'undefined' && isNative(Promise)) {
  const p = Promise.resolve()
  timerFunc = () => {   
  //timerFunc函数就是用各种异步执行的方法调用flushCallbacks函数。
    p.then(flushCallbacks)
    if (isIOS) setTimeout(noop)
  }
  isUsingMicroTask = true
} 

MutationObserve 创建异步执行函数 

if (!isIE && typeof MutationObserver !== 'undefined' &&
    (isNative(MutationObserver) ||
    MutationObserver.toString() === '[object MutationObserverConstructor]')
) {
    var counter = 1;
    var observer = new MutationObserver(flushCallbacks);
    var textNode = document.createTextNode(String(counter));
    observer.observe(textNode, {
        characterData: true
    });
    timerFunc = function() {
        counter = (counter + 1) % 2;
        textNode.data = String(counter);
    };
    isUsingMicroTask = true;
}

创建并返回一个新的MutationObserver,并吧flushCallbacks作为回调传入,在指定DOM发生变化后会执行传入的函数。

setImmediate 创建异步执行函数
if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
  timerFunc = () => {
    setImmediate(flushCallbacks)
  }
} 

setImmediate仅支持IE10以上的浏览器

setTimeout 创建异步执行函数

 

timerFunc = () => {
    setTimeout(flushCallbacks, 0);
  }

兼容IE10一下的浏览器,由于是宏任务因此比较消耗资源。

原文地址:https://blog.csdn.net/YM_010530/article/details/135789427

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。

如若转载,请注明出处:http://www.7code.cn/show_60957.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注