前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Preact 源码解析系列一 :简单DOM渲染

Preact 源码解析系列一 :简单DOM渲染

作者头像
IMWeb前端团队
发布2017-12-29 18:50:25
1K0
发布2017-12-29 18:50:25
举报
文章被收录于专栏:IMWeb前端团队IMWeb前端团队

用过Preact的人都知道,在每个JS文件之前,都需要写 /** @jsx h */,那这句话是什么作用呢?

先从JSX说起。

解析与编译

JSX实际上就是一个语法糖,让我们能以下简单明了的形式来定义UI长什么样,但是它需要编译器帮助编译,这里使用Babel。

Before:

代码语言:javascript
复制
/** @jsx h */
let foo = <div id="foo">Hello!</div>;

/** @jsx h */ 这句话就是为了告诉编辑器,每个解析后的jsx节点都需要调用h这个函数解析。

经过Babel编译之后就变成了,

代码语言:javascript
复制
var foo = h('div', {id:"foo"}, 'Hello!');

h()

接下来看看 h 做了一件什么事,它其实相当于react.createElement(),用于创建虚拟DOM,而所谓的虚拟DOM实际上就是一个JS对象,它长这样

代码语言:javascript
复制
{
    nodeName: "div",
    attributes: {'id': 'foo'},
    children: ['hello']
}

我们给它一个类装着

代码语言:javascript
复制
function Vnode(nodeName, attributes, children) {
  this.nodeName =  nodeName;
  this.attributes = attributes;
  this.children = children;
}

其实h的源码很简单,就是把后面的child做成数组,给children,返回一个虚拟DOM对象。

代码语言:javascript
复制
function h(nodeName, attributes, ...args) {  
      let children = args.length ? [].concat(...args) : null;
      return new Vnode( nodeName, attributes, children );
}

接着在render()函数里将其渲染成一个真实的DOM

代码语言:javascript
复制
Preact = {
    render: function(vNode, container) {
        // 当其类型为string的时候,返回一个文本节点
        if(typeof vNode === 'string') {
            return document.createTextNode(vNode);
        }
        let{nodeName, attributes: attrs, children} = vNode;
        let node;
        if(typeof nodeName === 'string') {
            node = document.createElement(nodeName);

            if(attrs) {
            // 用for in 来遍历对象的时候,使用hasOwnProperty可以很好的避免来自原型对象扩展所带来的困扰
                for(let key in attrs) {
                    if(attrs.hasOwnProperty(key)) {
                        node.setAttribute(key, attrs[key]);
                    }
                }
            }
            (children || []).forEach(function(child){
               //使用递归渲染
                node.appendChild(Preact.render(child))
            })       
        }
        container.appendChild(node)
    }
}

接着,调用render这个方法就可以渲染出想要的结果

代码语言:javascript
复制
Preact.render(h('div',{id: 'daisy'},'hello world'), document.getElementById('container'))

接着我们就可以在浏览器里看到hello world啦

总结一下: 其实Preact的渲染的还是很简单的,整个过程就是

1、Babel解析JSX

2、h函数将解析后JSX节点转成虚拟DOM

3、render函数把它转成真实的节点

当然这个例子还很简单,对于render的element只考虑到了string跟浏览器的已有元素(div)的情况,但是没有考虑到渲染component的情况,同时也没有diff算法加快渲染。

下一节,来看渲染自定义的component是如何渲染的。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 解析与编译
  • h()
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档