Special handling of instruction compilation
Special Handling of Directive Compilation
Vue3's directive system undergoes a transformation from template strings to executable code during the compilation phase. This conversion involves several key steps, including directive parsing, AST generation, and code generation. The uniqueness of directives lies in their need to handle both static attributes and dynamic bindings simultaneously, which requires additional processing logic during compilation.
Basic Flow of Directive Parsing
When the compiler encounters attributes with the v-
prefix, it recognizes them as directives and enters a special processing flow. The parsing process first separates the directive name and its arguments:
// Example directive: v-bind:title="message"
const dirRE = /^v-([^:]+)(?:$|:(.*)$)/;
const match = dirRE.exec('v-bind:title');
// match result: ["v-bind:title", "bind", "title"]
For modifiers, the compiler parses them into an object format:
// v-model.trim.number is parsed as
const modifiers = {
trim: true,
number: true
}
Transformation of Structural Directives
Structural directives like v-if
and v-for
alter the basic DOM structure. During compilation, they are converted into conditional expressions or loop statements. For example:
<div v-if="show">Content</div>
is compiled into:
function render() {
return (show)
? _createVNode("div", null, "Content")
: _createCommentVNode("v-if", true)
}
The processing of v-for
directives is more complex, requiring the generation of iteration functions:
<li v-for="(item, index) in items" :key="item.id">
{{ item.name }}
</li>
The compilation result is:
function render() {
return _renderList(items, (item, index) => {
return _createVNode("li", { key: item.id }, [
_toDisplayString(item.name)
])
})
}
Encapsulation of Event Directives
Event directives like v-on
need to handle event modifiers and multiple event bindings. The compiler generates wrapper functions that include modifier logic:
<button v-on:click.stop.prevent="handleClick">Click</button>
The compiled code includes modifier handling:
function render() {
return _createVNode("button", {
onClick: _withModifiers(handleClick, ["stop", "prevent"])
}, "Click")
}
Compilation Path for Custom Directives
After registering custom directives via the directives
option, the compiler generates special patch flags for them:
app.directive('focus', {
mounted(el) {
el.focus()
}
})
When used in templates:
<input v-focus />
The compilation result includes lifecycle calls for the directive:
function render() {
return _withDirectives(_createVNode("input"), [
[_directive_focus]
])
}
Special Handling of Dynamic Arguments
Dynamic argument directives require additional runtime parsing logic:
<div v-bind:[key]="value"></div>
The compiled code includes dynamic property name handling:
function render() {
return _createVNode("div", {
[key]: value
})
}
Directive Merge Strategy
When multiple directives are applied to the same element, the compiler needs to determine their execution order. For example, when both v-if
and v-for
are present:
<div v-for="item in list" v-if="item.visible"></div>
In this case, the compiler prioritizes v-for
, treating it as the outer loop, while v-if
becomes an internal conditional check:
function render() {
return _renderList(list, (item) => {
return item.visible
? _createVNode("div", null, [...])
: null
})
}
Directive Differences in Server-Side Rendering
In SSR environments, certain client-side directives require special handling. For example, v-show
is always rendered in the visible state on the server:
<div v-show="isVisible">Content</div>
The SSR compilation result ignores the v-show
directive:
function render() {
return _createVNode("div", null, "Content")
}
Performance Optimization Flags for Directives
The compiler adds optimization flags to static directives to avoid unnecessary update checks. For example, static class
bindings:
<div class="static" v-bind:class="{ active: isActive }"></div>
During compilation, static and dynamic parts are separated:
function render() {
return _createVNode("div", {
class: _normalizeClass(["static", { active: isActive }])
})
}
Compile-Time Directive Conversion
Certain directives are converted into simpler JavaScript expressions during compilation. For example, the v-once
directive:
<span v-once>{{ message }}</span>
is compiled into a static string:
function render() {
return _createVNode("span", null, _toDisplayString(message), 1 /* TEXT */)
}
Here, 1
is a static flag indicating that the node will not update.
Directives and Scoped Styles
When directives affect DOM structure, the compiler ensures scoped styles are correctly applied. For example, in v-if
branches:
<style scoped>
.box { color: red }
</style>
<div v-if="show" class="box"></div>
The compiler adds attribute selectors for scoped styles:
function render() {
return (show)
? _createVNode("div", { class: "box", "data-v-xxxx": "" })
: null
}
Cross-Platform Handling of Directives
Different platforms may support directives differently. The compiler converts directives based on the target platform. For example, in WeChat Mini Programs:
<view v-if="show"></view>
might be compiled into a Mini Program conditional statement:
// WeChat Mini Program compilation result
{
"type": "view",
"wx:if": "{{show}}"
}
TypeScript Support for Directives
In TypeScript environments, the compiler ensures type safety for directive parameters. For example, generating type checks for v-model
:
interface DirectiveBinding<T = any> {
value: T
oldValue: T | null
// ...
}
function useDirective(binding: DirectiveBinding<string>) {
// Only accepts string values
}
Compilation Caching for Directives
The compiler caches frequently used directive patterns for optimization. For example, identical v-for
patterns:
<div v-for="item in list" :key="item.id">{{ item.name }}</div>
The compilation result is cached to avoid repeated parsing:
const _hoisted_for_template = (item) => [
_createTextVNode(_toDisplayString(item.name))
]
function render() {
return _renderList(list, (item) => {
return _createVNode("div", { key: item.id }, _hoisted_for_template(item))
})
}
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn