数据结构
节点类型 type
export const enum NodeTypes {
ROOT,
ELEMENT,
TEXT,
COMMENT,
SIMPLE_EXPRESSION,
INTERPOLATION,
ATTRIBUTE,
DIRECTIVE,
// containers
COMPOUND_EXPRESSION,
IF,
IF_BRANCH,
FOR,
TEXT_CALL,
// codegen
VNODE_CALL,
JS_CALL_EXPRESSION,
JS_OBJECT_EXPRESSION,
JS_PROPERTY,
JS_ARRAY_EXPRESSION,
JS_FUNCTION_EXPRESSION,
JS_CONDITIONAL_EXPRESSION,
JS_CACHE_EXPRESSION,
// ssr codegen
JS_BLOCK_STATEMENT,
JS_TEMPLATE_LITERAL,
JS_IF_STATEMENT,
JS_ASSIGNMENT_EXPRESSION,
JS_SEQUENCE_EXPRESSION,
JS_RETURN_STATEMENT
}
基础数据示例
标签
<div></div>
{
"type": 0,
"children": [
{
"type": 1,
"ns": 0,
"tag": "div",
"tagType": 0,
"props": [],
"isSelfClosing": false,
"children": []
}
],
"helpers": [],
"components": [],
"directives": [],
"hoists": [],
"imports": [],
"cached": 0,
"temps": 0
}
组件
<my-component></my-component>
{
"type": 0,
"children": [
{
"type": 1,
"ns": 0,
"tag": "my-component",
"tagType": 0,
"props": [],
"isSelfClosing": false,
"children": []
}
],
"helpers": [],
"components": [],
"directives": [],
"hoists": [],
"imports": [],
"cached": 0,
"temps": 0
}
静态属性
<div id="test"></div>
{
"type": 0,
"children": [
{
"type": 1,
"ns": 0,
"tag": "div",
"tagType": 0,
"props": [
{
"type": 6,
"name": "id",
"value": {
"type": 2,
"content": "test"
}
}
],
"isSelfClosing": false,
"children": []
}
],
"helpers": [],
"components": [],
"directives": [],
"hoists": [],
"imports": [],
"cached": 0,
"temps": 0
}
注释
<!-- <div class="item"> -->
{
"type": 0,
"children": [
{
"type": 3,
"content": " <div class=\"item\"> "
}
],
"helpers": [],
"components": [],
"directives": [],
"hoists": [],
"imports": [],
"cached": 0,
"temps": 0
}
指令相关
v-bind
<div :key="key"></div>
{
"type": 0,
"children": [
{
"type": 1,
"ns": 0,
"tag": "div",
"tagType": 0,
"props": [
{
"type": 7,
"name": "bind",
"exp": {
"type": 4,
"content": "key",
"isStatic": false,
"constType": 0
},
"arg": {
"type": 4,
"content": "key",
"isStatic": true,
"constType": 3
},
"modifiers": []
}
],
"isSelfClosing": false,
"children": []
}
],
"helpers": [],
"components": [],
"directives": [],
"hoists": [],
"imports": [],
"cached": 0,
"temps": 0
}
v-on
<div @click="handleClick"></div>
{
"type": 0,
"children": [
{
"type": 1,
"ns": 0,
"tag": "div",
"tagType": 0,
"props": [
{
"type": 7,
"name": "on",
"exp": {
"type": 4,
"content": "handleClick",
"isStatic": false,
"constType": 0
},
"arg": {
"type": 4,
"content": "click",
"isStatic": true,
"constType": 3
},
"modifiers": []
}
],
"isSelfClosing": false,
"children": []
}
],
"helpers": [],
"components": [],
"directives": [],
"hoists": [],
"imports": [],
"cached": 0,
"temps": 0
}
v-model
<input v-model="text"/>
{
"type": 0,
"children": [
{
"type": 1,
"ns": 0,
"tag": "input",
"tagType": 0,
"props": [
{
"type": 7,
"name": "model",
"exp": {
"type": 4,
"content": "text",
"isStatic": false,
"constType": 0
},
"modifiers": []
}
],
"isSelfClosing": true,
"children": []
}
],
"helpers": [],
"components": [],
"directives": [],
"hoists": [],
"imports": [],
"cached": 0,
"temps": 0
}
v-if
<div v-if="show"></div>
{
"type": 0,
"children": [
{
"type": 1,
"ns": 0,
"tag": "div",
"tagType": 0,
"props": [
{
"type": 7,
"name": "if",
"exp": {
"type": 4,
"content": "show",
"isStatic": false,
"constType": 0
},
"modifiers": []
}
],
"isSelfClosing": false,
"children": []
}
],
"helpers": [],
"components": [],
"directives": [],
"hoists": [],
"imports": [],
"cached": 0,
"temps": 0
}
v-show
<div v-show="show"></div>
{
"type": 0,
"children": [
{
"type": 1,
"ns": 0,
"tag": "div",
"tagType": 0,
"props": [
{
"type": 7,
"name": "show",
"exp": {
"type": 4,
"content": "show",
"isStatic": false,
"constType": 0
},
"modifiers": []
}
],
"isSelfClosing": false,
"children": []
}
],
"helpers": [],
"components": [],
"directives": [],
"hoists": [],
"imports": [],
"cached": 0,
"temps": 0
}
v-for
<div v-for="(item, index) in list"></div>
{
"type": 0,
"children": [
{
"type": 1,
"ns": 0,
"tag": "div",
"tagType": 0,
"props": [
{
"type": 7,
"name": "for",
"exp": {
"type": 4,
"content": "(item, index) in list",
"isStatic": false,
"constType": 0
},
"modifiers": []
}
],
"isSelfClosing": false,
"children": []
}
],
"helpers": [],
"components": [],
"directives": [],
"hoists": [],
"imports": [],
"cached": 0,
"temps": 0
}
自定义指令
<p v-pin="200"></p>
{
"type": 0,
"children": [
{
"type": 1,
"ns": 0,
"tag": "p",
"tagType": 0,
"props": [
{
"type": 7,
"name": "pin",
"exp": {
"type": 4,
"content": "200",
"isStatic": false,
"constType": 0
},
"modifiers": []
}
],
"isSelfClosing": false,
"children": []
}
],
"helpers": [],
"components": [],
"directives": [],
"hoists": [],
"imports": [],
"cached": 0,
"temps": 0
}
综合示例
<div class="hello-class" v-for="(item, index) in list" v-if="item" :key="index" ></div>
{
"type": 0,
"children": [
{
"type": 1,
"ns": 0,
"tag": "div",
"tagType": 0,
"props": [
{
"type": 6,
"name": "class",
"value": {
"type": 2,
"content": "hello-class"
}
},
{
"type": 7,
"name": "for",
"exp": {
"type": 4,
"content": "(item, index) in list",
"isStatic": false,
"constType": 0
},
"modifiers": []
},
{
"type": 7,
"name": "if",
"exp": {
"type": 4,
"content": "item",
"isStatic": false,
"constType": 0
},
"modifiers": []
},
{
"type": 7,
"name": "bind",
"exp": {
"type": 4,
"content": "index",
"isStatic": false,
"constType": 0
},
"arg": {
"type": 4,
"content": "key",
"isStatic": true,
"constType": 3
},
"modifiers": []
}
],
"isSelfClosing": false,
"children": []
}
],
"helpers": [],
"components": [],
"directives": [],
"hoists": [],
"imports": [],
"cached": 0,
"temps": 0
}
嵌套数据展示
文本
<div>hello</div>
{
"type": 0,
"children": [
{
"type": 1,
"ns": 0,
"tag": "div",
"tagType": 0,
"props": [],
"isSelfClosing": false,
"children": [
{
"type": 2,
"content": "hello"
}
]
}
],
"helpers": [],
"components": [],
"directives": [],
"hoists": [],
"imports": [],
"cached": 0,
"temps": 0
}
插值
<div>{{hello}}</div>
{
"type": 0,
"children": [
{
"type": 1,
"ns": 0,
"tag": "div",
"tagType": 0,
"props": [],
"isSelfClosing": false,
"children": [
{
"type": 5,
"content": {
"type": 4,
"isStatic": false,
"constType": 0,
"content": "hello"
}
}
]
}
],
"helpers": [],
"components": [],
"directives": [],
"hoists": [],
"imports": [],
"cached": 0,
"temps": 0
}
文本 + 插值
<div>{{hello}} world</div>
{
"type": 0,
"children": [
{
"type": 1,
"ns": 0,
"tag": "div",
"tagType": 0,
"props": [],
"isSelfClosing": false,
"children": [
{
"type": 5,
"content": {
"type": 4,
"isStatic": false,
"constType": 0,
"content": "hello"
}
},
{
"type": 2,
"content": " world"
}
]
}
],
"helpers": [],
"components": [],
"directives": [],
"hoists": [],
"imports": [],
"cached": 0,
"temps": 0
}
slot
<my-component>
<template #title>
hello title
</template>
</my-component>
{
"type": 0,
"children": [
{
"type": 1,
"ns": 0,
"tag": "my-component",
"tagType": 0,
"props": [],
"isSelfClosing": false,
"children": [
{
"type": 1,
"ns": 0,
"tag": "template",
"tagType": 3,
"props": [
{
"type": 7,
"name": "slot",
"arg": {
"type": 4,
"content": "title",
"isStatic": true,
"constType": 3
},
"modifiers": []
}
],
"isSelfClosing": false,
"children": [
{
"type": 2,
"content": " hello title "
}
]
}
]
}
],
"helpers": [],
"components": [],
"directives": [],
"hoists": [],
"imports": [],
"cached": 0,
"temps": 0
}
示例代码
const { baseParse } = require('@vue/compiler-core')
const fs = require('fs')
const path = require('path')
const source = `
<div></div>
`.trim()
const result = baseParse(source)
function replacer(key, value) {
if (key === "loc") { // 去除用不到的属性
return undefined;
}
return value;
}
fs.writeFile(path.resolve('.', 'ast.json'), JSON.stringify(result, replacer, 2), (err) => {
})
其他
目前只列出了 template 中的部分写法。