提升系列
提升系列,我主要是想写一些平时工作上面,自己会用到的一些好的技巧或者方法。当然,这些技巧和方法是针对我自己的。
除此之外,还可能会写一些解决难点的方法。比如,遇到了某个难点,要通过什么方法来解决它?
正如它的名字一样--提升,通过学习一些好的技巧、方法,或者解决一些难题、难点,来提升我们的能力。
出这个提升系列,一方面,是提升自己的开发能力;另一方面,也希望这个提升系列,可以帮助到部分人,提升他们的开发能力。
在这个系列里,我能想到的或者实现方法,不一定是最好的。欢迎大家参与讨论。
前言
在上一篇文章里面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元素的高度。
这是页面内容
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元素高度,并且打印出来。
我们在浏览器的控制台查看结果:
点击按钮之后,我们发现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元素的高度,而不是直接修改的。
在浏览器控制台查看一下打印结果
这时候我们发现,不是打印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元素高度。
到浏览器控制台里查看打印结果
我们可以看到,第一次打印的是100,这还是div元素没修改之前的高度。而第二次打印的是200,这是div元素修改之后的高度。这样,我们就能获取到dom更新之后的高度了。
小结
本小节通过一个比较简单的案例来进行演示,参考了vue nexttick的源码,使用Promise.then,来延迟执行,获取更新之后的dom。
虽然创建异步队列使用了Promise.then,获取更新之后的dom,也是使用了Promise.then。使用了两次Promise.then,感觉有点奇怪。不过我没想到其它更好的办法,先这样吧。如果你有更好的建议,请告诉我。
最后,放上自己比较喜欢的一句诗句:
千淘万漉虽辛苦,吹尽狂沙始到金 - 唐 刘禹锡《浪淘沙》