JavaScript进阶(二十六):DOM 的编译(一)

经过前面的几篇博客,相信到现在为止,一些 DOM 的基本操作是没问题的,那么接下来就要做点事了,我们来尝试着去编译真实的 DOM 节点。

什么叫编译?很简单。

第一,我要把这个真实存在的元素,变成一个我自己的虚拟 DOM 元素。

第二,我要把这个元素身上,跟我相关的东西,都拿出来。

 

假设现在以 vue 为例,对于 vue 来说,你上面加个 title,人家关心吗?

不关心。人家关心的,其实是跟我有关系的东西。

你比方说我加了个 v-if,或者 @click:

这个我关心。

说白了,就是我在编译的过程当中,我要把跟我有关的,有功能的,这些自定义的属性,给它拎出来,将来我要用。

那么我们现在就直接来看一看,怎么来编译 DOM 节点。

当然,仅仅只算是一个初级版本,因为这个事可大可小,它未来其实会有很多复杂的东西。

所以我们现在要做的是一个初级的版本,所以也不会特别难。

 

那么现在,我希望是这样的,比方说,我有一个姓名 name:

当然顺便一说,我一定得用这个双花括号 {{ }} 吗?一定得跟着 vue 走吗?

不一定,我可以用任何我想的东西,反正是我们自己写的。

比方说,我就想用 % 间隔,行吗?

随便,爱用啥用啥。

只是双花括号 {{ }} 我们用习惯了,所以暂时还是这个。

 

然后继续,比方说,我还希望这里面可以给我做一些简单的运算:

这个要求也不复杂。

以及呢,我还希望这里面可能有一些按钮之类的东西,当我点击这个按钮的时候,这个 a 可以给我++

当然我们先一步一步的来,首先,我们想要来编译这个元素:

那么这个时候,第一件事,我们是不是要把它里面,所有的这些,所谓的模版,我要把它给挑出来啊?

也就是说,我关心的是 {{ 开头,}} 结尾,我关心的是这些东西。

 

那么接下来,我们要怎么做呢,我们一步一步来。

首先,你如果想把这个东西做的好一点,我们肯定是把它封成一个 class:

然后接下来呢,这里面需要一个 options,而且默认的时候,让它是一个空 json:

然后接下来先不管别的,我们先看看这里面具体想干点什么。

别的可能还不是特别关心,至少,我得有个 render 吧:

那么这个 render 具体怎么做是重点,我们一步一步来。

 

首先,为了写起来方便,我们把 js 这块单独的拎走,不然写起来太乱了。

这样的话,我们可以左右对照,看起来也方便一些。

然后,我们这个东西,先不管里面怎么写,我就想看看怎么用。

比方说,我现在就来 new 一个,然后这里面会有一些小小的参数,比如我有一个 root:

然后我们除了需要根元素以外,是不是还需要数据啊?

然后开始的第一个事,我希望可以有一个 assert,这个我们前面已经用过很多次了,熟的很。

那么这个 assert 有了之后,我需要检查很多东西。

首先,我们是不是需要根据 damu 所提供的 root 参数,来具体的把根元素给选出来啊。

那么这时候,是不是就可以跟以前一样,我们单独搞一个小操作,比如 _getElement:

我要的很简单,首先,我需要 assert 一下,参数 obj 你必须得有,没有就报错。

然后接下来,我们就来稍微的判断一下,如果它是 string,我们就自己来选,并且还得在判断一下,这东西有没有。

而反过来,如果它是一个元素,是的话就直接用,如果还不是的话,我就报错。

这个东西我们前面也写了很多遍,太熟了,就直接来了:

现在已经有了_getElement,那么我们就可以得到 _root 了:

然后这个有了之后,还没完,我们还需要用一个特别重要的东西,就是我得让 options.data 变成可响应的状态。

正经的情况下,我们需要各种判断,它是不是一个函数,怎么怎么着。

在这,我们就一切从简,反正这些事,我们前面都做过,所以这里就不再去重复了。

然后这个 data 已经有了,那么剩下的事怎么办?

是不是就可以创建一个 proxy 对象,因为我要监听它里面的东西:

这里我们也可以直接把 options.data 给丢进去,合成一步。

然后接下来,我这里面需要各种各样的东西,比如 get 和 set:

再接下来呢,我们的 render 里面是不是也要开始做事了啊?

到这里为止,你可以发现上面很多的操作都没有细说,因为我们前面做过很多次了,如果不是很懂,可以看下前面的博客。

 

那么到现在,我现在这个 proxy 确实是有了,我们就来看看:

可以看到,我们的实例 damu 身上并没有 a,为什么呀?原因非常简单。

注意,我们在这要区分一个东西,proxy 和 this

我们在外面这么去写:damu.a

请问这时候,我们是从谁上面去拿 a 的?其实是从 this 身上去拿的。

那么我们 this 身上有没有 a 这个东西?并没有。

谁身上有?是不是 proxy 身上有?那这时候怎么办呢?

我们能写 this = proxy 吗?这么写肯定报错的:

那有没有别的办法呢?有。

在这我们就要说一个及其另类的方法。

 

比方说我有一个类:

可以看到,现在一切没问题。

但是,在 js 里面,有一个很变态的特性,就是 constructor 是可以有返回值的。

比如我现在返回一个 json:

那么你可以看到,我现在得到的这个实例 a,就是这个 json。

换句话说,在其他语言里面,比如 java,constructor 其实是不能有 return,不能有返回值的,它的返回值就是刚构造好的那个东西,不能是别的。

而 js 当中,它可以 return 一个东西,只要你愿意,我 return 一个任意的对象都行,比如:

 

那么回到正题,这时候,在外面我们希望设置数据的时候,能够往 proxy 身上设。

所以,我们是不是就可以直接把 proxy 给 return 出去:

既然 return 了 proxy,那相当于我自己的 this 就废了。

当然这时候有人可能会说,那你这 this 身上的 _root 和 timer 不也没了吗?

其实这个 this 其实还是存在的,比方说 set 里面,我们依然调的是 this.render()。

所以说我的 this 并没有消失,只不过我是推出去一个顶雷的:有设置数据的 proxy 去,你顶上。

 

那么现在,我们来试试:

现在就可以看到,damu 上面是有 a 的了。

然后我们还想赋个值:

这时候就可以看到报错了,为什么会报错?

因为在 set 里面,this 指的就是 proxy。

所以我们需要稍微的变一变:

这时候,render 就出来了。

 

当然,这个并不是唯一的选择,我们也可以搞一个箭头函数:

可以看到,也是能出来的。

当然,我个人与其说把大量的函数都写成这种箭头函数,我更愿意用 _this。

 

那么到这为止,我们已经能够让它正确的做出响应了。

但是别忘了,我们的 render 里面到现在为止,什么都没有。

所以,下篇博客我们就开始来干这个事。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章