Vue 实现单独页面设置 body 样式

在用 Vue 写 demo 的时候发现可能会遇到这样的需求,就是针对不同的页面, <body> 的样式需要做一些变化。比如不同页面设置不同的背景色,但这就碰到一个问题,如果直接在页面里设置 body 的样式,页面并不会生效,如下:

1
2
3
4
5
6
7
8
9
<template>
<div>page</div>
</template>

<style>
body {
backgroud-color: #ff0;
}
</style>

网上搜索了一圈,发现解决办法就是通过 js 是设置 body 的样式,也就是在 created() 中添加样式,然后在 beforeDestory() 中移除样式,说干就干,立马就写了一个 demo 。

我做了 3 个页面,第一个页面无任何样式,第二个页面给 body 设置了字体大小,第三个页面同时给 body 设置了字体大小和背景颜色。但在实际效果里出现了一点问题,当我从第一个页面切换到第二个页面,一切正常,然后再从第二个页面切换到第三个页面,发现第三个页面的样式无法生效(同样的问题也出现在第一个页面 -> 第三个页面 -> 第二个页面)。

这是为什么呢?为什么第一次页面切换能成功,第二次就不行了?这时候我想起了 Vue 的生命周期:

这是 Vue 官网上提供的一张单页面的生命周期图,可我对照了一遍之后,还是没发现问题在哪。没办法,只能再写一个 demo ,实际还原多页面下,页面之间的生命周期执行顺序:

这个 demo 写出来后,真相立马大白了,原来页面在跳转时,在跳转页面执行到 mounted() 前,会先执行原页面的 beforeDestory() 和 destroyed() 方法,然后再执行跳转页面的 mounted() 。

这就解释了为什么第一次跳转页面都是正常,因为第一个页面没有做任何样式操作。然而第二次跳转页面,不管是从第二个页面跳转到第三个页面,还是从第三个页面跳转到第二个页面,因为跳转页面的 created() 会在原页面的 beforeDestory() 之前执行,所以跳转页面设置 body 样式的代码,会在原页面的 beforeDestory() 里一起被清空掉。

了解这一特性后,解决起来就很简单的,只需要把原先写在 created() 里的代码,放到 mounted() 里就行,这样就能确保设置样式的代码是在上一个页面清空样式代码后执行,最终效果如下:

关于这一点特性,我回去重新看了下 Vue 的文档,发现确实没有任何地方有提到,还以为自己又看漏了呢 😛

参考