@@ -1717,8 +1717,10 @@ function generate(ast) {
1717
1717
1718
1718
---
1719
1719
1720
+ <div grid =" ~ cols-2 gap-2 " >
1721
+
1720
1722
``` js
1721
- // 创建上下文,格式化代码字符串
1723
+ // 创建上下文,用于格式化代码字符串
1722
1724
function createCodegenContext () {
1723
1725
const context = {
1724
1726
code: ' ' ,
@@ -1728,10 +1730,8 @@ function createCodegenContext() {
1728
1730
push (code ) {
1729
1731
context .code += code
1730
1732
},
1731
- // 当前缩进级别,初始值为0,即没有缩进
1732
- currentIndent: 0 ,
1733
- // 换行
1734
- newLine () {
1733
+ currentIndent: 0 , // 当前缩进级别,初始值为0,即没有缩进
1734
+ newLine () { // 换行
1735
1735
context .code += ' \n ' + ' ' .repeat (context .currentIndent * 2 )
1736
1736
},
1737
1737
indent () { // 缩进
@@ -1747,6 +1747,213 @@ function createCodegenContext() {
1747
1747
}
1748
1748
```
1749
1749
1750
+ ``` js
1751
+ // 生成渲染函数代码字符串
1752
+ function genCode (node , context ) {
1753
+ const { push , indent , deIndent } = context
1754
+ const fnName = ' render'
1755
+ const args = [' _ctx' , ' config' ]
1756
+ const signature = args .join (' , ' )
1757
+
1758
+ push (` return ` )
1759
+ push (` function ${ fnName} (` )
1760
+ push (signature)
1761
+ push (` ) ` )
1762
+ push (` {` )
1763
+ // 缩进
1764
+ indent ()
1765
+ push (` const { h, _toDisplayString } = config` )
1766
+ indent ()
1767
+ push (` return ` )
1768
+ genNode (node, context)
1769
+ // 取消缩进
1770
+ deIndent ()
1771
+ push (` }` )
1772
+ }
1773
+ ```
1774
+
1775
+ </div >
1776
+
1777
+ ---
1778
+
1779
+ <div grid =" ~ cols-2 gap-2 " >
1780
+
1781
+ ``` js
1782
+ // 根据节点类型生成对应代码
1783
+ function genNode (node , context ) {
1784
+ switch (node .type ) {
1785
+ case NodeTypes .INTERPOLATION :
1786
+ genInterpolation (node, context)
1787
+ break
1788
+ case NodeTypes .SIMPLE_EXPRESSION :
1789
+ genExpression (node, context)
1790
+ break
1791
+ case NodeTypes .ELEMENT :
1792
+ genElement (node, context)
1793
+ break
1794
+ case NodeTypes .TEXT :
1795
+ genText (node, context)
1796
+ break
1797
+ }
1798
+ }
1799
+ ```
1800
+
1801
+ ``` js
1802
+ /**
1803
+ example:
1804
+ {
1805
+ type: 'Interpolation',
1806
+ content: {
1807
+ type: 'Expression',
1808
+ content: '_ctx.msg',
1809
+ }
1810
+ }
1811
+ =>
1812
+ '_ctx.msg'
1813
+ */
1814
+ function genInterpolation (node , context ) {
1815
+ const { push , helper } = context
1816
+ push (` ${ helper (TO_DISPLAY_STRING )} (` )
1817
+ genNode (node .content , context)
1818
+ push (` )` )
1819
+ }
1820
+
1821
+ function genExpression (node , context ) {
1822
+ context .push (node .content )
1823
+ }
1824
+ // { type: 'Text', content: 'hello' } => 'hello'
1825
+ function genText (node , context ) {
1826
+ const { push } = context
1827
+ push (` '${ node .content } '` )
1828
+ }
1829
+ ```
1830
+
1831
+ </div >
1832
+
1833
+ ---
1834
+
1835
+ <div grid =" ~ cols-2 gap-2 " >
1836
+
1837
+ ``` js
1838
+ /**
1839
+ * 生成调用表达式
1840
+ * @example
1841
+ * const node = [
1842
+ * type: ' Element' , tag: ' div' , props: { id: ' foo' }
1843
+ * children: [ { type: ' Text' , content: ' hello' } ]
1844
+ * ]
1845
+ * => h (' div' , { id: ' foo' }, ' hello' )
1846
+ * )
1847
+ */
1848
+ function genElement (node , context ) {
1849
+ const { push , helper } = context
1850
+ const { tag , props , children } = node
1851
+ push (` h('${ tag} ', ` )
1852
+
1853
+ if (props) {
1854
+ genProps (props, context)
1855
+ } else {
1856
+ push (' null, ' )
1857
+ }
1858
+ if (children) {
1859
+ genChildren (children, context)
1860
+ } else {
1861
+ push (' null' )
1862
+ }
1863
+ push (` )` )
1864
+ }
1865
+ ```
1866
+
1867
+ ``` js
1868
+ // const props = [
1869
+ // { type: 'Attribute', name: 'id', value: 'foo' },
1870
+ // { type: 'Attribute', name: 'class', value: 'bar' }
1871
+ // ]
1872
+ // => { id: 'foo', class: 'bar' }
1873
+ //
1874
+ function genProps (props , context ) {
1875
+ const { push } = context
1876
+ if (! props .length ) {
1877
+ push (' {}, ' )
1878
+ return
1879
+ }
1880
+ push (' { ' )
1881
+
1882
+ for (let i = 0 ; i < props .length ; i++ ) {
1883
+ const prop = props[i]
1884
+ const key = prop ? prop .name : ' '
1885
+ const value = prop ? prop .value : prop
1886
+ push (JSON .stringify (key))
1887
+ push (' : ' )
1888
+ push (prop .isStatic ? JSON .stringify (value) : value)
1889
+ if (i < props .length - 1 ) {
1890
+ push (' , ' )
1891
+ }
1892
+ }
1893
+ push (' }, ' )
1894
+ }
1895
+ ```
1896
+
1897
+ </div >
1898
+
1899
+ ---
1900
+
1901
+ <div grid =" ~ cols-2 gap-2 " >
1902
+
1903
+ ``` js
1904
+ // 处理子节点
1905
+ function genChildren (children , context ) {
1906
+ genArrayExpression (children, context)
1907
+ }
1908
+
1909
+ /**
1910
+ * 生成数组表达式
1911
+ * @example
1912
+ * const node = [{
1913
+ * type: ' Element' ,
1914
+ * tag: ' span' ,
1915
+ * children: [
1916
+ * { type: ' Text' , text: ' hello' }
1917
+ * ]
1918
+ * }]
1919
+ * =>
1920
+ * [h (' span' , null , ' hello' )
1921
+ */
1922
+ function genArrayExpression (node , context ) {
1923
+ const { push } = context
1924
+ // 追加方括号
1925
+ push (' [' )
1926
+ // 为数组元素生成代码
1927
+ genNodeList (node, context)
1928
+ push (' ]' )
1929
+ }
1930
+ ```
1931
+
1932
+ ``` js
1933
+ /**
1934
+ * 生成节点列表
1935
+ * @param {Array} nodes
1936
+ * @param {Object} context
1937
+ * @example
1938
+ */
1939
+ function genNodeList (nodes , context ) {
1940
+ const { push } = context
1941
+ for (let i = 0 ; i < nodes .length ; i++ ) {
1942
+ const node = nodes[i]
1943
+ if (typeof node === ' string' ) {
1944
+ push (` '${ node} '` )
1945
+ } else {
1946
+ genNode (node, context)
1947
+ }
1948
+ if (i < nodes .length - 1 ) { // 最后一个参数不需要逗号
1949
+ push (' , ' )
1950
+ }
1951
+ }
1952
+ }
1953
+ ```
1954
+
1955
+ </div >
1956
+
1750
1957
---
1751
1958
1752
1959
## compile 实现
@@ -1756,8 +1963,6 @@ function createCodegenContext() {
1756
1963
<div grid =" ~ cols-2 gap-2 " >
1757
1964
1758
1965
``` js
1759
- // demo: 21-compile.html
1760
-
1761
1966
/**
1762
1967
* 将模板编译为渲染函数字符串
1763
1968
* @param {String} template 模板
@@ -1781,6 +1986,8 @@ function baseCompile(template) {
1781
1986
```
1782
1987
1783
1988
``` js
1989
+ // demo: 21-compile.html
1990
+
1784
1991
/**
1785
1992
* 将模板编译为渲染函数
1786
1993
* @param {String} template 模板
@@ -1879,6 +2086,7 @@ demo: `22-counter.html`
1879
2086
<div grid =" ~ cols-2 gap-2 " >
1880
2087
1881
2088
``` html
2089
+ <script src =" ./static/mini-vue.umd.js" ></script >
1882
2090
<div id =" app" >
1883
2091
<div class =" demo" >
1884
2092
<button @click =" minus" >-1</button >
@@ -1916,12 +2124,3 @@ layout: center
1916
2124
---
1917
2125
1918
2126
# 感谢观看
1919
-
1920
- ---
1921
-
1922
- ## 参考
1923
-
1924
- - 《Vue.js 设计与实现》by 霍春阳
1925
- - https://github.com/vuejs/core
1926
- - https://github.com/cuixiaorui/mini-vue
1927
- - https://github.com/tim101010101/beggar-vue
0 commit comments