手寫簡易版 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的簡單實現學會了

喜歡能夠關注微信公衆號「悲傷日記」

相關文章
相關標籤/搜索