概述
前端页面一般都是 JS 负责逻辑控制,样式、布局等由CSS负责,而 CSS 的一般都是通过 class 和 style来作用于 html 的。
接下来探索一下一下 Vue2 中 class 和 style 的实现细节,代码详情class/style的渲染,主要源码是在 src/modules
目录下面
DEMO展示
App.vue
<template>
<div class="msg" :class="className" :style="styleObj">
{{message}}
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
message: '我是一个组件',
className: 'test',
styleObj: {
color: '#f00'
}
}
}
}
</script>
<style>
.msg {
font-size: 14px;
}
.test {
background: rebeccapurple;
}
.t1 {
background: rosybrown;
}
</style>
class渲染demo:

style渲染demo:

过程解析
class/style的渲染都分为两个两个场景: 首次创建、动态更新。之所以分为这两个场景是因为真好对应了 Vue 在渲染元素的各个周期(大致有5个create、active、update、remove、destroy),创建阶段会生成元素,动态更新时,会检测哪些内容需要更新,然后按需更新,也就是diff检测,避免冗余的一些dom操作。
大致过程为:

其中 createElement 和 patchNode 都是 vdom 中的 patch(可以理解就是diff)干的活,两个阶段分别会调用相关的hook。各个阶段的hook结构为:
{
create: [],
activate: [],
update: [],
remove: [],
destroy: []
}
而class/style都会提供各个生命周期的回调函数,以class渲染为为例,导入的实现如下:
{
create: updateClass,
update: updateClass
}
updateClass
会将目标编译之后的 staticClass 和 class 两个属性拼接为为一个字符串:

然后将改字符串通过el.setAttribute('class', xxx)
形式设置到真实的dom结构上面。
而针对style也类似,不过style设置,可以使用两种方式设置:
el.style.setProperty(name, val) // 支持第三个参数,故可以设置 important
// 或者
el.style[name] = val
总结
对应class/style, 在编译Vue模板时就会区分 static、动态类型,像class分为 staticClass 和 class,我理解这样区分还是处于一个性能的考虑,如果只有staticClass,可以只需要简单处理则可。
Vue在渲染元素预留好各个阶段的回调,通过插件形式,以一种低耦合的形式实现了对class/style的支持,同时像 attrs/ref/events等都是通过这种方式实现的。