摘要:轉換成為模板函數聯系上一篇文章,其實模板函數的構造都大同小異,基本是都是通過拼接函數字符串,然后通過對象轉換成一個函數,變成一個函數之后,只要傳入對應的數據,函數就會返回一個模板數據渲染好的字符串。
教程目錄
1.手把手教你從零寫一個簡單的 VUE
2.手把手教你從零寫一個簡單的 VUE--模板篇
Hello,我又回來了,上一次的文章教會了大家如何書寫一個簡單 VUE,里面實現了VUE 的數據驅動視圖渲染模板,更新到頁面的過程,簡單的帶大家了解了類似 VUE 這樣子的數據驅動視圖框架的工作流程,今天我來給大家講一講作為一個前端框架最為核心的部分---模板,代碼還是放在文章的最后,請隨意下載
模板的分類在介紹我們實現的模板語言之前,我們先來了解下,現在市面上比較流行的模板語言:
PHP/ASP/JSP風格<%if(list.length ){%><%for(n = 0; n < list.length; ++n ){%>
<%}%>- <%=list[n]%>
<%}%>
這種是最接近于 js 變成語言的語法,比較直觀,但是由于存在< >的分隔符,對 IDE不太友好,不太好進行格式化處理
mustcache風格{{#if list.length}}{{#each list item}}
{{/if}}- {{item}}
{{/each}}
這種是artTemplate默認的語法,高級語法有限,通常難自定義拓展
DSL風格語法首先介紹下什么是DSL, DSL全稱是Domain Specific Language/DSL領域專用語言,其基本思想是求專不求全,用于解決一個類型,一個領域的問題。比如Vue里面的v-xxx,Vue稱之為指令,其實就是一個DSL,用于解決模板語法等問題,這種模板由于在html語法里面相當于標簽的屬性,所以對IDE友好,不會影響格式化操作。
Vue的模板語法相當于結合了 DSL語法和 mustcache風格, 邏輯控制部分使用DSL語法,輸出展示部分使用 mustcache風格
模板引擎設計思路下面是這個模板引擎的思路:
字符串模板語法定義首先我們要定義一種模板語法,按照上一節的說明,我們使用DSL風格語法,下面是我們測試用的模板
我們采用最簡單的將模板寫在script標簽的配置方式,可以看到我們定義了幾個DSL,分別是dsl-if,dsl-for,dsl-html,分別用于判斷,循環和直接輸出 html,還有使用mustcache作為字符串輸出語法。當然這個只是一個簡單的模板DSL語言,主要為了講解思路,真正的模板需要更加多的模板語法,具體可以參照 VUE文檔
首先解釋下什么是AST,AST 全稱為abstract syntax tree(抽象語法樹),是源代碼的抽象語法結構的樹狀表現形式,每種源碼都可以被抽象成為AST,比如我們常用的 js,css,json 等,都可以解析成為 AST
把模板解析成為AST,就是將模板的 html 結構進行解析,變成一顆附帶結構、關系、屬性的抽象樹,這樣做方便與后面我們多次對模板進行處理,減少了多次解析字符串帶來的損耗,同時變成一顆樹的數據結構之后更加方便于我們的遍歷,關于AST的優點缺點大家可以執行搜索,這里就不展開說明了
上面的字符串模板解析完成之后,會變成以下的一個AST
可以看到字符串模板變成了一個object數組,每個 obj 代表一個節點,里面包含了這個 obj 的屬性,類型,父子關系,用到的DSL等等。這個可以看成是我們的模板的一個中間態,為我們進行進一步處理打下了基礎。
聯系上一篇文章,其實模板函數的構造都大同小異,基本是都是通過拼接函數字符串,然后通過Function對象轉換成一個函數,變成一個函數之后,只要傳入對應的數據,函數就會返回一個模板數據渲染好的 html 字符串。下面是例子中通過AST
這是個函數體,然后使用new Function,就變成一個真正的函數了,至于這個函數體的解釋,我將放在下面具體實現進行講解
由于本文主要是講模板的實現,因此數據部分還是使用延續上一篇文章的綁定,在初始化或者數據發生改變的時候,響應的函數會對數據所關聯的模板函數進行重新調用,生成新的html,重新進行渲染。
模板的開發思路我們就在上面都說明了,主要總結下就是將字符串模板變成 ast,ast 變成模板函數,然后就可以結合數據進行 html 生成及渲染了
具體實現方法首先說明下本教程的方法是對思路的實現,并非完全使用 vue 的實現方法,vue 是一個完整的框架,里面涉及的東西比較多,我們的實現是為了讓大家更好的了解 vue 的原理,而非完全實現
字符串模板變成AST部分1.模板預處理:
由于字符串模板是人為處理的,因此書寫的時候可能會出現標簽不配對,標簽未關閉等問題,因此我們要先做些預處理,來去除這些干擾,做法有很多種,比如通過一些語法分析的工具進行解析,這里我們使用一種比較簡單的方式進行處理,代碼如下(/src/core/render.js):
可以看到我創建了一個div標簽,然后將字符串模板放進去里面,這樣子瀏覽器會對模板進行解析處理,然后我們再通過innerHTML去除前后空格之后拿出來,這樣就對字符串模板進行了處理。
備注:我們按照 vue 的規則,一個模板只有一個根節點,所以我們取了childNodes[0]
2.生成 ast:
上面我們對字符串模板進行了預處理,接下去我們要將字符串模板轉換成ast,代碼比較長,大家有興趣可以看下/src/compiler/ast/parse.js,下面說下解析思路
解析通過正則表達式配合 String.replace(regExt,fn),正則表達式為/<(?:"[^"]*"[""]*|"[^"]*"[""]*|[^"">])+>/g,解析出來標簽和標簽上面的屬性,然后按照需求進行存儲,就生成 ast
生成模板函數的思路就是遞歸遍歷ast 樹,對不同的類型節點,不同的NSL,調用不同的生成函數,最后組合成為模板函數字符串,代碼如下(/src/compiler/compiler-helper.js):
可以看到,處理的函數對 DSL還有不同的標簽類型進行處理,然后都返回了一個輔助函數的調用,比如_i,_f,_c等等,這里的輔助函數是在模板函數被調用的時候才真正的被調用的,下面我們舉例說明一個輔助函數_c
這個輔助函數的功能是用于生成節點,可以看到調用了這個函數之后,對應的 ast 里面的節點被真正生成,變成dom節點,并且會把孩子節點進行插入,通過很多輔助函數的遞歸嵌套調用,最終模板函數一調用,就可以結合數據渲染出來真實的dom節點
下面說一個比較細的知識點,就是輔助函數的調用,我們知道上面的輔助函數調用在生成的時候,其實都是字符串,然后通過new Function讓他變成真正的函數,那么問題就來了,我們知道new Function是的作用域和運行時的代碼是隔離的,是調用不到外面的_c,_f等輔助函數的,那是如何實現調用的呢,這里用了一個我們很少使用的關鍵字with,這個關鍵字在很多書籍里面都不推薦使用,因為他的作用是修改with包含代碼塊的作用域,如果濫用會導致代碼的邏輯不可控,但是在模板函數里面這個關鍵字有奇效,他可以方便的規定把當前的代碼作用域傳到模板函數里面,從而使得模板函數里面可以調用到運行時作用域的函數。大家可以看下上一小節生成的模板函數字符串,會發現就是用整個with(that){}包裹起來的,在模板函數運行時,將當前作用域直接傳入即可,代碼如下:
至此,我們已經生成了模板函數,通過傳入數據運行模板函數,就可以生成 dom,代碼如下:
可以我們直接把compiler_helper附帶上 data 作為作用域,直接調用了模板函數,就可以生成dom,再結合我們第一篇文章寫的數據監聽,就可以實現簡單的數據驅動視圖
至此,我們的VUE模板的基本實現已經介紹完成了,這里主要是介紹如何去實現一個模板引擎的思路,所以功能上上面的實現不是完整的,只是實現了一些簡單的語法,大家可以下下代碼繼續補充。
思考細心的人可能會發現,我們上面的模板有個問題,就是如果改了數據中的其中一個數值,那么整個模板都得重新編譯,重新渲染,這其實是非常損耗性能的,這其實就是我下一篇文章要講的,模板渲染的效率問題,先提出幾個關鍵詞 虛擬dom,diff 算法,最小化渲染,吊吊大家的胃口,哈哈,下一篇文章我會進行全面的介紹,相信學習完下一篇文章,大家會對現有市面上的數據驅動框架的模板部分有個全面的了解~下一篇文章更加精彩哦~~求關注
最后附上源碼點我點我,各位客官給個 star 唄~~
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/87215.html
摘要:本系列是一個教程,下面貼下目錄手把手教你從零寫一個簡單的手把手教你從零寫一個簡單的模板篇今天給大家帶來的是實現一個簡單的類似一樣的前端框架,框架現在應該算是非常主流的前端數據驅動框架,今天我們來從零開始寫一個非常簡單的框架,主要是讓大家 本系列是一個教程,下面貼下目錄~1.手把手教你從零寫一個簡單的 VUE2.手把手教你從零寫一個簡單的 VUE--模板篇 今天給大家帶來的是實現一個簡單...
摘要:前端日報精選專題之跟著學節流冴羽的博客全家桶仿微信項目,支持多人在線聊天和機器人聊天騰訊前端團隊社區編碼的奧秘模塊實現入門淺析知乎專欄前端每周清單發布新版本提升應用性能的方法中文寇可往吾亦可往用實現對決支付寶的微信企業付款到零 2017-06-20 前端日報 精選 JavaScript專題之跟著 underscore 學節流 - 冴羽的JavaScript博客 - SegmentFau...
摘要:有沒有辦法實現就局部刷新呢當然是有第十步執行為了實現局部熱加載,我們需要添加插件。 前言 用了3個多月的vue自認為已經是一名合格的vue框架api搬運工,對于vue的api使用到達了一定瓶頸,無奈水平有限,每每深入底層觀賞源碼時候都迷失了自己。 遂決定再找個框架學習學習看看能否突破思維局限,加上本人早已對React、RN技術垂涎已久,于是決定找找教程來學習。無奈第一步就卡在了環境搭...
閱讀 2513·2023-04-25 17:27
閱讀 1824·2019-08-30 15:54
閱讀 2369·2019-08-30 13:06
閱讀 2980·2019-08-30 11:04
閱讀 746·2019-08-29 15:30
閱讀 729·2019-08-29 15:16
閱讀 1733·2019-08-26 10:10
閱讀 3603·2019-08-23 17:02