手写简易版 render 函数

前言

在这个以前咱们须要了解render是什么?html

能够去以前的文章里面看看 《 搞懂vue-render函数(入门篇)》vue

废话很少说,快快快 上车!!!数组

定义一个对象

先定义一个数据对象来做为咱们的数据微信

let data = {
    tag:"h2",
    props:{},
    children:"严老湿"
}

tag 做为标签名,props 做为属性对象,children 做为子元素或者文本节点数据结构

哈哈哈 仍是老套路 先写一个 h2 标签试试水app

获取根节点挂载

这个So Easy啦ide

<div id="app"></div>
// app 做为咱们的根节点
let app = document.querySelector('#app')

获取到 app 节点以后呢? 咱们是否是须要 appendChild 咱们第一步定义的 data 对象函数

// 此时尚未render这个函数
app.appendChild(render(data))

这个 render 函数就是咱们今天要写的重要内容ui

开始重头戏

天才第一步 ,先定义一个 render 函数spa

// 接收传入的参数
const render = (options) = >{
    // 获取数据中的标签并建立
    let el = document.createElement(options.tag);
    // 打印el
    console.log(el) // <h2></h2>
    // 将节点返回
    return el
}
app.appendChild(render(data))

此时咱们的元素已经建立成功,接下来咱们须要作的就是,把它的文本,渲染上去。

渲染文本节点

children 赋值给到节点文本内容

const render = (options) = >{
    let el = document.createElement(options.tag);
    // 咱们在这里传入 children 文本
    el.textContent = options.children
    return el
}
app.appendChild(render(data))

严老湿 :好了,render 写完了,下课吧!

童鞋 :等等!! 就这???

开个玩笑 固然不是啦!这写得也真是太简陋了吧

升级render

刚刚咱们其实已经写了一个简陋版本的render 有不少问题!

  • children 若是是数组,多个子元素呢?
  • 若是props 里面有属性呢?
  • 我还想要点事件触发函数呢?

....

还有不少问题,因此咱们来增强一下,冲鸭!!!

props参数

咱们如今先来升级一下 props 参数,如咱们须要在元素上加 classidon

首先是一号选手 class

咱们先将数据中的props中新增一个class 且 它的值为 myClass

let data = {
    tag:"h2",
    props:{
        class:"myClass"
    },
    children:"严老湿"
}

数据改造好了,咱们来看看 render 改如何升级

const render = (options) = >{
    let el = document.createElement(options.tag);
    // 判断是不是对象,而且不是null
    if(typeof options.props === 'object' && options.props !== null){
        for(key in options.props){
            // 拿到 props 中的 key、val
            vla = options.props[key];
            // 给元素添加指定的属性
            el.setAttribute(key, vla);
        }
    }
    el.textContent = options.children;
    return el
}
app.appendChild(render(data))

这样咱们就已经完成了class的添加

老湿,那ID呢?

等等,我拿下锤子...

第二位选手 id

id其实都不用说了,就改改数据而已,So Easy

let data = {
    tag:"h2",
    props:{
        class:"myClass",
        id:"myId"
    },
    children:"严老湿"
}

props的最后一位选手 on

on 里面是用来绑定事件的,因此咱们不能跟classid 同等对待。渣男!区别对待

仍是先改造数据,咱们加上 on-click

let data = {
    tag:"h2",
    props:{
        class:"myClass",
        id:'myId',
        on:{
            // 传入点击事件
            click:(e)=>{
                console.log(e)
            }
        }
    },
    children:"严老湿"
}

数据改造完成,咱们接着升级 render

const render = (options) = >{
    let el = document.createElement(options.tag);
    if(typeof options.props === 'object' && options.props !== null){
        for(key in options.props){
            vla = options.props[key];
            // 若是key等于on
            if(key === "on"){
                // 将on对象赋值给 incident
                incident = options.props[key]
                for(k in incident){
                    // 给元素绑定事件传入Event
                    el.addEventListener(k,e=>incident[k](e))
                }
            }else{
                // 其余的都进来这里
                el.setAttribute(key, vla);
            }
        }
    }
    el.textContent = options.children;
    return el
}
app.appendChild(render(data))

点击标签以后看看打印

是否是也是很简单

到这里咱们就已经完成了这个 props 里面常常会用到的一些操做了。

多个子元素

有时候咱们的数据中可能不止一个元素,那若是children 是一个数组呢?

那咱们就不能直接赋值给元素的 textContent 了,继续加判断。

咱们仍是同样的先修改数据,将 children 改成一个数组,结构呢仍是个以前同样

let data = {
    tag:"ul",
    props:{
        class:"myClass",
        id:'myId',
    },
    children:[
        {
            tag: 'li',
            props: {
                class: "list",
            },
            children: "4万面五星红旗挂上武汉街头"
        }, {
            tag: 'li',
            props: {
                class: "list",
            },
            children: "机场水门最高礼遇迎接烈士遗骸"
        }
    ]
}

数据结构修改完成以后了,咱们接下来修改 render 函数

const render = (options) = >{
    let el = document.createElement(options.tag);
    if(typeof options.props === 'object' && options.props !== null){
        for(key in options.props){
            vla = options.props[key];
            if(key === "on"){
                incident = options.props[key]
                for(k in incident){
                    el.addEventListener(k,e=>incident[k](e))
                }
            }else{
                el.setAttribute(key, vla);
            }
        }
    }
    // 在内容赋值这里咱们作一个判断
    // 若是 children 是一个数组
    if (options.children instanceof Array) {
        // 咱们进行 forEach 遍历一下
        options.children.forEach((item)=>{
            // 进行递归 render 函数,传入 
            el.appendChild(render(item));
        });
    }else{
        // 若是不是数据,咱们进行赋值
        el.textContent = options.children
    }
    return el
}
app.appendChild(render(data))

是否是已经渲染成功呢?

所有代码

给你们贴一下所有代码吧!

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>老严讲render</title>
</head>
<body>
    <div id="app"></div>
    <script>
        const app = document.querySelector('#app')
        let data = {
            tag: "ul",
            props: {
                class: "myClass",
                id: 'myId',
            },
            children: [
                {
                    tag: 'li',
                    props: {
                        class: "list",
                    },
                    children: "4万面五星红旗挂上武汉街头"
                }, {
                    tag: 'li',
                    props: {
                        class: "list",
                    },
                    children: "机场水门最高礼遇迎接烈士遗骸"
                }
            ]
        }
        const render = (options) => {
            let el = document.createElement(options.tag);
            if (typeof options.props === 'object' && options.props !== null) {
                for (key in options.props) {
                    vla = options.props[key];
                    if (key === "on") {
                        incident = options.props[key]
                        for (k in incident) {
                            el.addEventListener(k, e => incident[k](e))
                        }
                    } else {
                        el.setAttribute(key, vla);
                    }
                }
            }
            if (options.children instanceof Array) {
                options.children.forEach((item) => {
                    el.appendChild(render(item));
                });
            } else {
                el.textContent = options.children
            }
            return el;
        };
        app.appendChild(render(data));
    </script>
</body>
</html>

总结

  • 咱们写的代码是比较简陋的,没那么多判断逻辑,可是咱们已经将render的简单实现学会了

喜欢能够关注微信公众号“悲伤日记”

相关文章
相关标签/搜索