代码分别对应:
// vue-template-compiler/build.js/createCompilerCreator
var ast = parse(template.trim(), options)
optimize(ast, options)
var code = generate(ast, options)先前我们的组件ID在 parse 阶段解析开始标签时就会被推入内部储存的数据结构中:
function elementToOpenTagSegments (el, state) {
var segments = [{ type: RAW, value: ("<" + (el.tag)) }] // _scopedId
if (state.options.scopeId) {
segments.push({ type: RAW, value: (" " + (state.options.scopeId)) })
}
segments.push({ type: RAW, value: ">" })
return segments
}先前我们的HTML模板 <div class=’lionad’></div> 中开始标签会被转换成如下数据结构:
[
{ type: RAW, value: '<div' },
{ type: RAW, value: 'class=lionad' },
{ type: RAW, value: 'data-v-xxxxxx' },
{ type: RAW, value: '>' },
]样式模板处理
与 HTML Template 解析的过程类似, 通过 Webpack 将样式模板转交 stylePostLoader 进行处理, 处理逻辑主要引用了 @vue/component-compiler-utils 中的 compileStyle 部分, 后者对样式模板进行解析的过程中, 将会对含 scoped 标记的模板引入插件 stylePlugins/scoped.js, scoped.js 将 data-v-xxxxxx 添加到选择器末尾的过程如下:
selectors.each((selector) => {
selector.each((n) => {
if (n.value === '::v-deep' || n.value === '>>>' || n.value === '/deep/') {
return false;
}
});
selector.insertAfter(node, selectorParser.attribute({
attribute: id
}))
})题外话, 通过以上代码, 我们发现当当前处理到三种特定类型选择器会终止循环, 停止将 data-v-xxx 添加到选择器末尾:
伪类 ::v-deep
选择器 >>>
选择器 /deep/
我们可以利用这个特征, 在组件中写样式穿透, 即内部组件影响外部组件样式 (ε=ε=ε=┏(゜ロ゜;)┛ 主动样式污染), 当然这在特定的情境下是有用的, 比如当我们想主动覆盖第三方UI组件框架的样式, 却不想引入新的CSS文件, 或不想写非 Scoped CSS 模板的时候.
最后
本人前端菜得捉急, 文中不详尽或有错的地方, 欢迎各位大佬斧正. 如果本文对你有所帮助, 那是再好不过, 看到这里都是真爱啊










