Vue模板解析简单的实现

122 阅读1分钟

参考链接 www.bilibili.com/video/BV1LE…

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="root">
    <p>firstName:{{ user.name.firstName }}</p>
    <p>lastName:{{ user.name.lastName }}</p>
</div>
</body>
<script>
    /**
     * 通过路径 xx.yy.zz 访问一个对象并返回对应的值
     * @param obj 选项里面的data
     * @param path  路径
     * @returns {*} 键值
     */
    function getValueByPath(obj, path) {
        let paths = path.split('.');
        let res = obj;
        let prop;
        while (prop = paths.shift()) {
            res = res[prop];
        }
        return res;
    }

    let rkuohao = /{{(.+?)}}/g;

    /**
     * 解析编译模板,并赋值
     * @param template  id="root" 的Dom元素
     * @param data     选项里面的data
     */
    function compiler(template, data) {
        let childNodes = template.childNodes;
        for (let i = 0; i < childNodes.length; i++) {
            let type = childNodes[i].nodeType; // 1 元素, 3 文本节点
            if (type === 3) {
                let txt = childNodes[i].nodeValue;
                txt = txt.replace(rkuohao, function (_, g) {
                    let path = g.trim(); // 写在双花括号里面的 东西
                    let value = getValueByPath(data, path);
                    return value;
                });
                childNodes[i].nodeValue = txt;
            } else if (type === 1) {
                compiler(childNodes[i], data);
            }
        }
    }


    class MyVue {
        constructor(options) {
            this._data = options.data;
            this._el = options.el;
            this._templateDOM = document.querySelector(this._el);
            this._parent = this._templateDOM.parentNode;
            this.render()
        }
        render() {
            this.compiler();
        }
        compiler() {
            let realHTMLDOM = this._templateDOM.cloneNode(true);
            compiler(realHTMLDOM, this._data);
            this.update(realHTMLDOM);
        }
        update(realHTMLDOM) {
            this._parent.replaceChild(realHTMLDOM, document.querySelector('#root'));
        }
    }


    let app = new MyVue({
        el: '#root',
        data: {
            user: {
                name: {
                    firstName: "张",
                    lastName: "三"
                }
            }
        }
    });


</script>
</html>