亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Vue編譯器實現(xiàn)代碼生成方法介紹

 更新時間:2023年01月05日 15:57:34   作者:loyd3  
這篇文章主要介紹了Vue編譯器實現(xiàn)代碼生成方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧

這里將討論如何根據(jù)JavaScript AST生成渲染函數(shù)的代碼,即代碼生成。代碼生成本質(zhì)上是字符串拼接的藝術(shù)。需要訪問JavaScript AST中的節(jié)點(diǎn),為每一種類型的節(jié)點(diǎn)生成相符的 JavaScript代碼。

本節(jié),將實現(xiàn) generate函數(shù)來完成代碼生成的任務(wù)。

function compile(template) {
	//模板 AST
	const ast = parse(template)
	//將模板 AST轉(zhuǎn)換為JavaScript AST
	transform(ast)
	// 代碼生成
	const code = generate(ast.jsNode)
	return code
}

在這里,代碼生成也需要上下文對象。

function generate(node){
	const context = {
		// 存儲最終生成的渲染函數(shù)代碼
		code: '',
		// 在生成代碼時,通過調(diào)用 push 函數(shù)完成代碼的拼接
		push(code){
			context.code += code
		}
	}
	// 該方法完成代碼生成的工作
	genNode(node,context)
	// 返回渲染函數(shù)代碼
	return context.code
}

另外,為了讓最終生成的代碼具有較強(qiáng)的可讀性,要考慮生成代碼的格式,這就需要擴(kuò)展context對象,為其增加用來完成換行和縮進(jìn)的工具函數(shù),如下面代碼所示:

function generate(node){
	const context = {
		code: '',
		push(code){
			context.code += code
		},
		// 當(dāng)前縮進(jìn)的級別,初始值為 0,即沒有縮進(jìn)
		currentIndent: 0,
		// 該函數(shù)用來換行,即在代碼字符串的后面追加 \n 字符
		// 另外,換行時應(yīng)該保留縮進(jìn),所以還要追加 currentIndent * 2 個空格字符
		newline(){
			context.code += '\n'+` `.repeat(context.currentIndent)
		},
		// 用來縮進(jìn),即讓 currentIndent 自增后,調(diào)用換行函數(shù)
		indent(){
			context.currentIndent++
			context.newline()
		},
		// 取消縮進(jìn)
		deIndent(){
			context.currentIndent--
			context.newline()
		},
	}
	genNode(node, context)
	return context.code
}

有了這些基礎(chǔ)能力之后,就可以開始編寫 genNode 函數(shù)來完成代碼生成的工作了。代碼生成的原理其實很簡單,只需要匹配各種類型的 JavaScript AST節(jié)點(diǎn),并調(diào)用對應(yīng)的生成函數(shù)即可,如下面的代碼所示:

function genNode(node,context){
	switch(node.type){
		case 'FunctionDecl':
			genFunctionDecl(node,context)
			break
		case 'ReturnStatement':
			genReturnStatement(node,context)
			break
		case 'CallExpression':
			genCallExpression(node,context)
			break
		case 'StringLiteral':
			genStringLiteral(node,context)
			break
		case 'ArrayExpression':
			genArrayExpression(node,context)
			break
	}
}

如果后續(xù)需要增加節(jié)點(diǎn)類型,只需要再genNode函數(shù)中添加相應(yīng)的處理分支即可

接下來逐步完善代碼生成工作,首先實現(xiàn)函數(shù)生命語句的代碼生成,即genFunctionDecl函數(shù),如下面的代碼所示:

function genFunctionDecl(node,context){
	// 從context 對象中取出工具函數(shù)
	const {push, indent, deIndent} = context
	push(`function ${node.id.name}`)
	push(`(`)
	//調(diào)用 genNodeList 為函數(shù)的參數(shù)生成代碼
	genNodeList(node.params, context)
	push(`)`)
	push(`{`)
	indent()
	//為函數(shù)體生成代碼,這里遞歸地調(diào)用了 genNode 函數(shù)
	node.body.forEach(n=>genNode(n,context))
	deIndent()
	push(`}`)
}

genFunctionDecl函數(shù)用來為函數(shù)聲明類型的節(jié)點(diǎn)生成對應(yīng)的 JavaScript代碼。以聲明節(jié)點(diǎn)為例,它最終生成的代碼將會是:

function render(){
	...函數(shù)體
}

genNodeList函數(shù)的實現(xiàn)如下:

function genNodeList(nodes, context){
	const {push} = context
	for(let i=0;i<nodes.length;i++){
		const node = nodes[i]
		genNode(node,context)
		if(i<nodes.length - 1){
			push(',')
		}
	}
}

這里要注意的一點(diǎn)是,每處理完一個節(jié)點(diǎn),需要在生成的代碼后面拼接逗號。

實際上,genArrayExpression函數(shù)就利用了這個特點(diǎn)來實現(xiàn)對數(shù)組表達(dá)式的代碼生成,如下面的代碼所示:

function genArrayExpression(node, context){
	const {push} = context
	// 追加方括號
	push(`[`)
	genNodeList(node.elements, context)
	// 補(bǔ)全方括號
	push(`]`)
}

對于 genFunctionDecl 函數(shù),另外需要注意的是,由于函數(shù)體本身也是一個節(jié)點(diǎn)數(shù)組,所以需要遍歷它并遞歸地調(diào)用 genNode 函數(shù)生成代碼。

對于ReturnStatement和StringLiteral類型的節(jié)點(diǎn)來說,為它們生成代碼很簡單,如下所示:

function genReturnStatement(node, context){
	const {push} = context
	push(`return `)
	genNode(node.return, context)
}
function genStringLiteral(node, context){
	const {push} = context
	// 對于字符串字面量,只需要追加與 node.value 對應(yīng)的字符串即可
	genNode(`'${node.value}'`)
}

最后,只剩下genCallExpression 函數(shù)了,實現(xiàn)如下:

function genCallExpression(node, context){
	const {push} = context
	// 取得被調(diào)用函數(shù)名稱和參數(shù)列表
	const {callee, arguments: args} = node
	// 生成函數(shù)調(diào)用代碼
	push(`${callee.name}`)
	genNodeList(args,context)
	push(`)`)
}

配合上述生成器函數(shù)的實現(xiàn),就能得到符合語氣的渲染函數(shù)代碼,用下面的代碼測試

const ast = parse(`<div><p>Vue</p><p>Template</p></div>`)
transform(ast)
const code = generate(ast.jsNode)

最終得到的代碼字符串如下:

function render (){
	return h('div',[h('p','Vue'), h('p','Template')])
}

到此這篇關(guān)于Vue編譯器實現(xiàn)代碼生成方法介紹的文章就介紹到這了,更多相關(guān)Vue代碼生成內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Vue使用el-dialog關(guān)閉后重置表單方式

    Vue使用el-dialog關(guān)閉后重置表單方式

    這篇文章主要介紹了Vue使用el-dialog關(guān)閉后重置表單方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-02-02
  • vue如何使用外部特殊字體的操作

    vue如何使用外部特殊字體的操作

    這篇文章主要介紹了vue如何使用外部特殊字體的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-07-07
  • vue3輸入單號和張數(shù)如何自動生成連號的單號

    vue3輸入單號和張數(shù)如何自動生成連號的單號

    最近遇到這樣的需求輸入連號事件,需要在表格中輸入物流單號,物流號碼,生成的數(shù)量,名稱,點(diǎn)擊確定自動生成固定數(shù)量的連號物流單號,本文重點(diǎn)介紹vue3輸入單號和張數(shù),自動生成連號的單號,感興趣的朋友一起看看吧
    2024-02-02
  • vite基本常見的配置講解

    vite基本常見的配置講解

    這篇文章主要給大家介紹了關(guān)于vite基本常見配置講解的相關(guān)資料,最近做項目要求將webpack打包方式換成vite,下面將詳細(xì)講解一下配置vite需要改動的東西,需要的朋友可以參考下
    2023-11-11
  • 淺談Vue父子組件和非父子組件傳值問題

    淺談Vue父子組件和非父子組件傳值問題

    本篇文章主要介紹了淺談Vue父子組件和非父子組件傳值問題,具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2017-08-08
  • Vue必學(xué)知識點(diǎn)之forEach()的使用

    Vue必學(xué)知識點(diǎn)之forEach()的使用

    在前端開發(fā)中,經(jīng)常會遇到一些通過遍歷循環(huán)來獲取想要的內(nèi)容的情形,這時候就需要用到forEach()了,下面這篇文章主要給大家介紹了關(guān)于Vue必學(xué)知識點(diǎn)之forEach()使用的相關(guān)資料,需要的朋友可以參考下
    2021-05-05
  • springboot+vue實現(xiàn)文件上傳下載

    springboot+vue實現(xiàn)文件上傳下載

    這篇文章主要為大家詳細(xì)介紹了springboot+vue實現(xiàn)文件上傳下載,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • Vue.js組件實現(xiàn)選項卡以及切換特效

    Vue.js組件實現(xiàn)選項卡以及切換特效

    這篇文章主要為大家詳細(xì)介紹了Vue.js組件實現(xiàn)選項卡以及切換特效,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-07-07
  • vue-router路由參數(shù)刷新消失的問題解決方法

    vue-router路由參數(shù)刷新消失的問題解決方法

    本篇文章主要介紹了vue-router路由參數(shù)刷新消失的問題解決方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • vue實現(xiàn)翻牌動畫

    vue實現(xiàn)翻牌動畫

    這篇文章主要為大家詳細(xì)介紹了vue實現(xiàn)翻牌動畫,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-04-04

最新評論