24-获取更新后的dom-2-Promise.then

191 阅读4分钟

提升系列

提升系列,我主要是想写一些平时工作上面,自己会用到的一些好的技巧或者方法。当然,这些技巧和方法是针对我自己的。

除此之外,还可能会写一些解决难点的方法。比如,遇到了某个难点,要通过什么方法来解决它?

正如它的名字一样--提升,通过学习一些好的技巧、方法,或者解决一些难题、难点,来提升我们的能力。

出这个提升系列,一方面,是提升自己的开发能力;另一方面,也希望这个提升系列,可以帮助到部分人,提升他们的开发能力。

在这个系列里,我能想到的或者实现方法,不一定是最好的。欢迎大家参与讨论。

前言

在上一篇文章里面23-获取更新后的dom-1-vue源码分析,我们主要是分析了在vue nexttick源码,是怎么实现的,做了什么操作。接下来,就要按照源码里使用到的方法,来尝试一下,看下有没有效果。

我们先介绍第一个方法,Promise.then。

问题

我在项目里遇到的问题是,在页面里,经过一系列操作之后,会改变了dom的高度。但是在获取dom高度的时候,我获取到的,还是上一次dom的高度,即更新之前的高度。那要怎么获取更新之后dom的高度呢?

思路

怎么获取更新之后dom的高度?在解决这个问题之前,我想先介绍一下vue的源码。因为我解决问题的思路,其实也是参考了一下vue的源码。

在vue的源码里面,在nexttick部分,有介绍了一些方法,来进行延迟操作。

下面是我从vue官方仓库里拿到的vue源码,获取了部分关于nexttick的代码

let timerFunc
if (typeof Promise !== 'undefined' && isNative(Promise)) {
  const p = Promise.resolve()
  timerFunc = () => {
    p.then(flushCallbacks)
  }
  isUsingMicroTask = true
} 

我们将参考vue nextick里的这部分代码,来实现一下。

实现

为了简单演示,没有做特别复杂的效果,这里就不使用创建一个工程项目的方式来开发了。就用一个html文件来实现,就可以了。

所以我们先创建一个index.html文件,我们的代码,将在这个html文件里面完成。

html结构

先写我们的html结构

<style>
      .box {
        width: 100px;
        height: 100px;
        background-color: orange;
​
        margin-bottom: 30px;
      }
</style><div class="box"></div>
<button id="btn">改变高度</button>

我们先创建一个div元素,通过样式,设置它的宽高为100px。同时设置一下它的背景颜色。

下面还创建了一个button按钮,一会我们将要通过这个按钮,来改变div元素的高度。

这是页面内容

0001.png

js代码

接下来,我们就要写js代码了。

  let box = document.querySelector(".box");
      let btn = document.querySelector("#btn");
      btn.addEventListener("click", () => {
           box.style.height = "200px";
        console.log("height-1", box.offsetHeight);
      });

解释一下这段代码逻辑:

先获取两个dom元素,然后给button按钮绑定点击事件。在点击事件里面,修改div元素的高度为200px,然后通过offsetHeight获取div元素高度,并且打印出来。

我们在浏览器的控制台查看结果:

0002.png

点击按钮之后,我们发现div元素的高度发生改变了,同时打印出来的高度为200。看起来,好像没有问题。

不过在vue里面,它是维持了一个异步队列。数据发生改变了,就推到这个队列里。等数据都改变了,再去批量更新数据,而不是数据一改变,就立马进行更新。

那我们也模仿一个异步队列,就用Promise来模仿了。修改一下原来代码

btn.addEventListener("click", () => {
        let pro1 = Promise.resolve();
        pro1.then(() => {
          box.style.height = "200px";
        });
        console.log("height-1", box.offsetHeight);
      });

我们是在Promise.then里面修改div元素的高度,而不是直接修改的。

在浏览器控制台查看一下打印结果

0003.png

这时候我们发现,不是打印200了,而是打印100。说明获取到的,还是div元素旧的高度,而不是新的高度。

怎么办?

回到本文开始所说的,使用Promise.then,来获取更新后的dom。修改一下原来代码

 btn.addEventListener("click", () => {
        let pro1 = Promise.resolve();
        pro1.then(() => {
          box.style.height = "200px";
        });
        console.log("height-1", box.offsetHeight);
        let pro2 = Promise.resolve();
        pro2.then(() => {
          console.log("height-2", box.offsetHeight);
        });
      });

对原来的代码,进行了一些修改。我们也是再创建一个Promise对象,然后在Promise.then里,获取div元素高度。

到浏览器控制台里查看打印结果

0004.png

我们可以看到,第一次打印的是100,这还是div元素没修改之前的高度。而第二次打印的是200,这是div元素修改之后的高度。这样,我们就能获取到dom更新之后的高度了。

小结

本小节通过一个比较简单的案例来进行演示,参考了vue nexttick的源码,使用Promise.then,来延迟执行,获取更新之后的dom。

虽然创建异步队列使用了Promise.then,获取更新之后的dom,也是使用了Promise.then。使用了两次Promise.then,感觉有点奇怪。不过我没想到其它更好的办法,先这样吧。如果你有更好的建议,请告诉我。

最后,放上自己比较喜欢的一句诗句:

千淘万漉虽辛苦,吹尽狂沙始到金 - 唐 刘禹锡《浪淘沙》