zoukankan      html  css  js  c++  java
  • 手写一个render函数

    前言

    在这个之前我们需要了解render是什么?

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

    废话不多说,快快快 上车!!!

    定义一个对象

    先定义一个数据对象来作为我们的数据

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

    tag 作为标签名,props 作为属性对象,children 作为子元素或者文本节点

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

    获取根节点挂载

    这个So Easy啦

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

    获取到 app 节点之后呢? 我们是不是需要 appendChild 我们第一步定义的 data 对象

    // 此时还没有render这个函数
    app.appendChild(render(data))

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

    开始重头戏

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

    // 接收传入的参数
    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的简单实现学会了

    - END -

  • 相关阅读:
    Nginx配置文件说明
    http服务区域组网的一种方法
    InetAddress.getLocalHost()返回ip 地址异常听问题
    #!/bin/bash(转)
    ThreadPoolExecutor运转机制详解(转)
    memcache 入门学习资料
    Too many open files 异常
    Java并发编程之ConcurrentHashMap
    Java NIO 选择器(Selector)的内部实现(poll epoll)
    Python 的sub和replace的区别
  • 原文地址:https://www.cnblogs.com/10ve/p/13743396.html
Copyright © 2011-2022 走看看