首页 > 其他分享 >Vue中nextTick的使用及原理

Vue中nextTick的使用及原理

时间:2023-11-06 17:02:53浏览次数:33  
标签:nextTick 异步 Vue DOM 更新 Promise 原理

在Vue.js中,nextTick方法可以让我们在DOM更新后执行一些操作。通常情况下,在数据发生变化后,Vue.js会异步地更新DOM,这样可以减少不必要的DOM操作,提高性能。但是,有时候我们需要在DOM更新后对页面进行一些后续操作,比如修改元素的样式、设置定时器等,这时候就需要用到nextTick方法。

一、nextTick的使用场景

1. 访问更新后的DOM

在一些特殊的场景中,我们可能需要访问更新后的DOM,比如在通过ref访问组件或子元素时,由于DOM更新是异步的,所以需要使用nextTick方法来确保能够访问到更新后的DOM。

<template>
  <div>
    <p ref="msg">Hello, World!</p>
  </div>
</template>

<script>
export default {
  mounted() {
    // 此时访问DOM元素是无法获取到更新后的text值,需要使用nextTick方法
    console.log(this.$refs.msg.innerText); // 输出:Hello, World!
    this.$nextTick(() => {
      console.log(this.$refs.msg.innerText); // 输出:Hello, Vue!
    });
  },
  methods: {
    updateMessage() {
      this.$refs.msg.innerText = 'Hello, Vue!';
    }
  }
}
</script>

在上述代码中,当mounted钩子函数被调用时,this.$refs.msg是无法获取到更新后的text值,需要使用nextTick方法来确保能够访问到更新后的DOM。

2. 在更新后执行某些操作

有时候,我们需要在DOM更新后执行某些操作,比如在动态修改元素的样式、设置定时器等。这种情况下,同样也需要使用nextTick方法。

<template>
  <div>
    <button @click="changeColor">Change Color</button>
    <p :style="{ color: textColor }">Hello, World!</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      textColor: 'black'
    }
  },
  methods: {
    changeColor() {
      // 使用nextTick确保视图已经更新完成
      this.$nextTick(() => {
        this.textColor = 'red';
      });
    }
  }
}
</script>

在上述代码中,当用户点击按钮时,我们需要动态地将文本颜色修改为红色。由于DOM更新是异步的,如果直接在点击事件处理函数中修改文本颜色可能无法生效。因此,我们需要使用nextTick方法确保DOM更新完成后再进行修改。

二、nextTick的原理

在Vue.js中,nextTick方法的实现原理主要基于两个核心技术:Promise和microtask。

Promise

Promise是ES6引入的一个新特性,它可以异步地执行JavaScript代码并返回异步操作的结果。Promise使用起来非常简单,我们只需要调用其构造函数即可创建一个Promise实例。

const promise = new Promise((resolve, reject) => {
  // 异步执行的代码
  setTimeout(() => {
    resolve('success');
  }, 1000);
});

promise.then(result => {
  console.log(result);
}).catch(error => {
  console.log(error);
});

在上述代码中,我们通过Promise构造函数创建了一个异步操作,它会在1秒后返回一个成功的结果'success'。然后,我们使用then方法来处理异步操作返回的结果。

microtask

microtask是JavaScript引擎中的一个任务队列,它用于存储一些需要异步执行的任务。当主线程执行完成后,会立即执行microtask队列中的所有任务,然后再执行下一轮的渲染更新。

在Vue.js中,nextTick方法就是利用了Promise和microtask技术来实现的。当我们调用nextTick方法时,Vue.js会将回调函数添加到一个microtask队列中,在DOM更新完成后立即执行这个回调函数。

Vue.prototype.$nextTick = function (fn: Function) {
  const _this = this;
  if (pending) {
    callbacks.push(() => {
      fn.call(_this);
    });
  } else {
    pending = true;
    timerFunc(() => {
      const ctx = _this ? _this.$options.context : null;
      fn.call(ctx);
      flushCallbacks();
    });
  }
};

在Vue.js的源码中,我们可以看到nextTick方法的实现逻辑:如果已经有回调函数在等待执行,会将新的回调函数加入到队列中;否则,会调用timerFunc函数异步地将回调函数添加到microtask队列中,然后在DOM更新后立即执行。

const callbacks = [];
let pending = false;

function flushCallbacks() {
  pending = false;
  const copies = callbacks.slice(0);
  callbacks.length = 0;
  for (let i = 0; i < copies.length; i++) {
    copies[i]();
  }
}

let timerFunc;

if (typeof Promise !== 'undefined' && isNative(Promise)) {
  timerFunc = () => {
    Promise.resolve().then(flushCallbacks)
  };
} else if (!isIE && typeof MutationObserver !== 'undefined' && (isNative(MutationObserver) || MutationObserver.toString() === '[object MutationObserverConstructor]')) {
  let counter = 1;
  const observer = new MutationObserver(flushCallbacks);
  const textNode = document.createTextNode(String(counter));
  observer.observe(textNode, {
    characterData: true
  });
  timerFunc = () => {
    counter = (counter + 1) % 2;
    textNode.data = String(counter);
  };
} else {
  timerFunc = () => {
    setTimeout(flushCallbacks, 0);
  };
}

在上述代码中,timerFunc函数是nextTick方法的关键。它会根据当前浏览器环境的支持情况,选择不同的异步执行方式。如果浏览器支持Promise对象,则使用Promise.resolve().then(flushCallbacks)来添加microtask任务;如果浏览器不支持Promise对象但支持MutationObserver,则使用MutationObserver,在文本节点变化时执行回调函数;否则,使用setTimeout来异步地执行回调函数。

综合以上讨论,我们可以得出nextTick的执行流程:

  1. 将回调函数加入到callbacks队列中;
  2. 如果没有正在等待执行的回调函数,使用timerFunc异步地将回调函数添加到microtask队列中;
  3. 在DOM更新后立即执行microtask队列中的所有回调函数。

三、小结

本文主要介绍了Vue.js中nextTick方法的使用场景和原理。nextTick方法可以让我们在DOM更新后执行一些操作,它的原理基于Promise和microtask技术。当调用nextTick方法时,Vue.js会将回调函数添加到一个microtask队列中,在DOM更新完成后立即执行这个回调函数。需要注意的是,在使用nextTick方法时,要确保回调函数不会频繁地触发DOM更新,否则可能会影响性能。

标签:nextTick,异步,Vue,DOM,更新,Promise,原理
From: https://blog.51cto.com/u_15723831/8214368

相关文章

  • vue3.0 + ts 实现上传工厂(oss与cos)
    概述将上传基类命名为MOS(MineObjectStorage)mos.ts代码import{MosType}from'./mosConfig'import{Loading}from'../loading'import{typeBinaryFile,typeMosFile}from'./fileUtil'importtype{PathTemplate}from'./pathTempla......
  • vuejs3.0 从入门到精通——组件传值方法——兄弟组件之间的传值
    兄弟组件之间的传值 A组件-->父组件-->B组件一、组件安装npminstallmitt-Smkdir-pvVITE-PROJECT/plugin/Bus.jsecho"importmittfrom'mitt';constemitter=mitt();exportdefaultemitter;">> VITE-PROJECT/plugin/Bus.js一、A组件二、父组件三、B......
  • PHP如何判断一个网址是否被百度搜索引擎收录?判断的原理又是什么?
    下面就是我今天用PHP实现这个功能的具体代码:1234567891011121314151617181920212223242526function checkBaiduInclude($url){    $url = 'http://www.baidu.com/s?wd='.$url;    $ch = curl_init();    curl_setopt($ch,......
  • vue视频直接播放rtsp流;vue视频延迟问题解决;webRTC占cpu太大卡死问题解决;解决webRTC播
    vue视频直接播放rtsp流;vue视频延迟问题解决;webRTC占cpu太大卡死问题解决;解决webRTC播放卡花屏问题::https://blog.csdn.net/killerdoubie/article/details/133884070......
  • 使用panjiachen的vue-admin-template项目时出现的问题及解决方案
    问题项目执行npminstall时出现python环境问题:python--versionpython3--version发现没有python2版本的环境,之后我安装python等一系列操作,没啥用。那么会不会是npm的版本不对,于是我重新安装了[email protected]:ModernJSalreadyguaranteesArra......
  • Vue.js 获取当前日期前几个月的日期
    1、获取当前日期并想获取6个月前的日期getDate(){varnow=newDate();varyear=now.getFullYear();//得到年份varmonth=now.getMonth()+1;//得到月份vardate=now.getDate();//得到日期varhour="00:00:00";/......
  • nginx ingress controller EWMA负载均衡策略工作原理及修改过程
    1、概念 EWMA(ExponentiallyWeightedMovingAverage)策略是NGINXIngressController中的一种负载均衡算法,它用于决定请求应该由后端服务的哪个实例处理。 2、工作原理 EWMA策略通过指数加权移动平均的方式计算每个后端服务实例的权重,并根据权重来分配请求。 它的......
  • Vue3 中的hook函数和 toRef(toRefs)
    一、自定义hook函数  1、什么是hook?      本质是一个函数,把setup函数中使用的CompositionAPI进行了封装  2、类似于vue2.x中的mixin  3、自定义hook的优势:复用代码,让setup中的逻辑更清楚易懂。二、toRef  1、作用:创建一个ref对象,其valu......
  • Vue3的生命周期
    1、setup():开始创建组件之前,在beforeCreate和created之前执行,创建的是data和method2、onBeforeMount():组件挂载到节点上之前执行的函数;3、onMounted():组件挂载完成后执行的函数;4、onBeforeUpdate():组件更新之前执行的函数;5、onUpdated():组件更新完成之后......
  • 【开源】基于Vue.js的电子元器件管理系统的设计和实现
    一、摘要1.1项目简介电子元器件是高校电子实验室进行实验的必备物品,随着电子元器件的种类不断增多,人工管理的方式容易出现错误,对实验室管理员的体验感也不是很好,所以需要开发一套电子元器件管理系统实现对电子元器件的数字化管理需求,其中包括对电子元器件档案的管理和采购入库、学......