web技术支持| 简单实现Vue第一章:模板编译

164 阅读1分钟

创建vue构造函数

function Vue(option) {
    this.$option = option;
}

挂载方法

Vue.prototype.$mount = function(element) {
    const rootNode = document.getElementById(element);
    if (rootNode) {
        this.$rootNode = rootNode;
    } else {
        throw new Error('$mount Receives an ID node');
    }

    if (this.$option.template) {
        this.$render();
    } else {
        throw new Error('The lack of the template');
    }

    return this;
}


Vue.prototype.$render = function render() {
    this.$AST = this.$templateCompilation(this.$option.template);
}


Vue.prototype.$templateCompilation = function templateCompilation(html) {
    const AST = {
        attrs: [],
        children: []
    };

    function start(AST) {
        let result = html.match(startReg.startTag);
        AST.tagName = result[0];
        cuttingHTML(result);

        while (html.match(startReg.endTag).index) {
            result = html.match(startReg.startAttrs);
            AST.attrs.push({
                key: result[0].split('=')[0],
                value: result[1]
            });
            cuttingHTML(result);
        }
        
        cuttingHTML(html.match(startReg.endTag));
        text(AST);
        return AST;
    }
    

    function text(parent) {
        while (html && html.match(textReg.endTag).index) {
            let result = html.match(textReg.startTag);
            if (result && !result.index) {
                parent.children.push(start(JSON.parse(JSON.stringify(AST))));
            } else {
                result = html.match(textReg.text);
                parent.children.push(result[0]);
                cuttingHTML(result);
            }
        }
        
        cuttingHTML(html.match(textReg.endTag));
    }
    
    function cuttingHTML(result) {
        html = html.substr(result.index + result[0].length);
    }

    return start(JSON.parse(JSON.stringify(AST)));
}

创建reg.js

const startReg = {
    startTag: /[\w\d]+/,
    startAttrs: /[^\s=]+\s*=\s*('[^'>]*'|"[^">]*")/,
    endTag: /\s*>/
};


const textReg = {
    startTag: /\s*<[\w\d]+/,
    text: /[^<]+/,
    endTag: /\s*<\/[a-z0-9]+>/i
};

使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./reg.js"></script>
    <script src="./vue.js"></script>

    <style>
        .box {
            display: flex;
        }

        img {
            width: 200px;
            height: 100%;
            margin-right: 20px;
        }

        .content {
            line-height: 27px;
            font-size: 14px;
        }

        .content span {
            color: #000;
            font-weight: 600;
        }
    </style>
</head>
<body>
    <div id="app"></div>
    <script>
        const template = `<div class='box' style='
        width: 900px; 
        height: 300px; 
        border: 1px solid green; 
        margin: 150px auto; 
        padding: 20px; 
        box-sizing: border-box'>
            <img src='./touxiang.webp'></img>
            <div class='content'>
                您好,我是 <span>{{ name }}</span>,毕业于 <span>{{ university.name }}</span> 大学 <span>{{ university.professional }}</span> 专业。
                今天应聘的是贵公司的xxxx岗位。在校期间,我在学校的学生会/团总支/社团/班级/寝室担任xxxx职务。
                期间,我参加xxx活动。课余,我还参加了xxxx的实践活动。我的兴趣爱好是xxxx,擅长xxxx。
                我对贵公司和xxxx这个岗位十分感兴趣,希望您能给我一个机会。 
                <br></br>
                <br></br>
                您好,我是 <span>{{ name }}</span>,毕业于 <span>{{ university.name }}</span> 大学 <span>{{ university.professional }}</span> 专业。
                今天应聘的是贵公司的xxxx岗位。在校期间,我在学校的学生会/团总支/社团/班级/寝室担任xxxx职务。
                期间,我参加xxx活动。课余,我还参加了xxxx的实践活动。我的兴趣爱好是xxxx,擅长xxxx。
                我对贵公司和xxxx这个岗位十分感兴趣,希望您能给我一个机会。    
            </div>
        </div>`;

        const vn = new Vue({
            template,
            data() {
                return {
                    name: 'Jack',
                    age: 23,
                    university: {
                        name: 'Shanghai Jiao Tong',
                        professional: 'Computer information'
                    }
                }
            }
        }).$mount('app');


        console.log(vn);
    </script>
</body>
</html>

效果截图

注意:上述代码无法实现以下效果,本章代码只进行了模板编译,还没有渲染真实DOM;

image.png

在这里插入图片描述