实现vue中的MVVM原理

现成MVVM

菜单教程

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <input type="text" v-model="message">
        <p>{{ message }}</p>
    </div>

    <script>
        let vm = new Vue({
            el: '#app',
            data: {
                message: 'Hello Vue.js!'
            }
        })
    </script>
</body>

</html>

视图影响数据

实现vue中的MVVM原理

数据影响视图

实现vue中的MVVM原理

项目构架

<!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>Document</title>
</head>

<body>

</body>

</html>
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
    <script src="./js/mvvm.js"></script>
    <script src="./js/compile.js"></script>
</head>

<body>
    <div id="app">
        <input type="text" v-model="message">
        <div>{{message}}</div>
        <ul>
            <li></li>
        </ul>
        {{message}}
    </div>

    <script>
        let vm = new MVVM({
            el: '#app',
            data: {
                message: 'Hello Vue.js!'
            }
        })
    </script>
</body>

</html>

mvvm.html

<!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>Document</title>
</head>

<body>

</body>

</html>
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
    <script src="./js/mvvm.js"></script>
    <script src="./js/compile.js"></script>
</head>

<body>
    <div id="app">
        <input type="text" v-model="message">
        <div>{{message}}</div>
        <ul>
            <li></li>
        </ul>
        {{message}}
    </div>

    <script>
        let vm = new MVVM({
            el: '#app',
            data: {
                message: 'Hello Vue.js!'
            }
        })
    </script>
</body>

</html>

mvvm.js

class MVVM {
    constructor(options) {
        this.$el = options.el;
        this.$data = options.data;

        if (this.$el) {
            new Compile(this.$el);
        }

    }
}

compile

把dom节点,放在内存中操作(到35分钟)

class Compile {
    constructor(el, vm) {
        this.el = this.isElementNode(el) ? el : document.querySelector(el);
        this.vm = vm;
        if (this.el) {
            let fragment = this.node2frament(this.el);
            this.compile(fragment);
        }
    }

    //辅助方法
    isElementNode(node) {
        return node.nodeType === 1;
    }

    //核心方法
    compile(fragment) {
        let childNodes = fragment.childNodes;
        console.log(childNodes)
    }
    node2frament(el) {
        let fragment = document.createDocumentFragment();
        let firstChild;
        while (firstChild = el.firstChild) {
            fragment.appendChild(firstChild);
        }
        return fragment
    }
}

分类元素节点和文本节点(52分钟)

class Compile {
    constructor(el, vm) {
        this.el = this.isElementNode(el) ? el : document.querySelector(el);
        this.vm = vm;
        if (this.el) {
            let fragment = this.node2frament(this.el);
            this.compile(fragment);
        }
    }

    //辅助方法
    isElementNode(node) {
        return node.nodeType === 1;
    }
    isDirective(name) {
        return name.includes('v-')
    }

    //核心方法
    compileElement(node) {
        let attrs = node.attributes;
        Array.from(attrs).forEach(arrt => {
            let attrName = attr.name;
            if (this.isDirective(attrName)) {
                let expr = attr.value;
            }
        })
    }
    compileText(node) {
        let text = node.textContent;
        let reg = /\{\{([^}]+)\}\}/g;
        if (reg.test(text)) {

        }
    }
    compile(fragment) {
        let childNodes = fragment.childNodes;
        Array.from(childNodes).forEach(node => {
            if (this.isElementNode(node)) {
                this.compile(node)
            } else {
                console.log('text', node)
            }
        })
    }
    node2frament(el) {
        let fragment = document.createDocumentFragment();
        let firstChild;
        while (firstChild = el.firstChild) {
            fragment.appendChild(firstChild);
        }
        return fragment
    }
}

元素节点

实现vue中的MVVM原理

文本节点

实现vue中的MVVM原理

把data中的数据,显示在视图上(到1:16分)

class Compile {
    constructor(el, vm) {
        this.el = this.isElementNode(el) ? el : document.querySelector(el);
        this.vm = vm;
        if (this.el) {
            let fragment = this.node2frament(this.el);
            this.compile(fragment);
            this.el.appendChild(fragment)
        }
    }

    //辅助方法
    isElementNode(node) {
        return node.nodeType === 1;
    }
    isDirective(name) {
        return name.includes('v-')
    }

    //核心方法
    compileElement(node) {
        let attrs = node.attributes;
        Array.from(attrs).forEach(attr => {
            let attrName = attr.name;
            if (this.isDirective(attrName)) {
                let expr = attr.value;
                let [, type] = attrName.split('-');
                CompileUtil[type](node, this.vm, expr)
            }
        })
    }
    compileText(node) {
        console.log(node)
        let expr = node.textContent;
        let reg = /\{\{([^}]+)\}\}/g;
        if (reg.test(expr)) {
            CompileUtil['text'](node, this.vm, expr)
        }
    }
    compile(fragment) {
        let childNodes = fragment.childNodes;
        Array.from(childNodes).forEach(node => {
            if (this.isElementNode(node)) {
                this.compileElement(node)
                this.compile(node)
            } else {
                this.compileText(node)
            }
        })
    }
    node2frament(el) {
        let fragment = document.createDocumentFragment();
        let firstChild;
        while (firstChild = el.firstChild) {
            fragment.appendChild(firstChild);
        }
        return fragment
    }
}


CompileUtil = {
    getVal(vm, expr) { // 获取实例上对应的数据
        expr = expr.split('.'); // [message,a]
        return expr.reduce((prev, next) => { // vm.$data.a
            return prev[next];
        }, vm.$data);
    },
    getTextVal(vm, expr) { // 获取编译文本后的结果
        return expr.replace(/\{\{([^}]+)\}\}/g, (...arguments) => {
            return this.getVal(vm, arguments[1]);
        })
    },
    text(node, vm, expr) { //文本处理
        let updateFn = this.updater['textUpdater'];
        let value = this.getTextVal(vm, expr);
        updateFn && updateFn(node, value)
    },

    model(node, vm, expr) {
        let updateFn = this.updater['modelUpdater'];
        updateFn && updateFn(node, this.getVal(vm, expr));
    },
    updater: {
        textUpdater(node, value) {
            node.textContent = value;
        },
        modelUpdater(node, value) {
            node.value = value;
        }
    }
}

v-model类型

modelUpdater(node, value) {
            node.value = value;
            console.log(node)
            console.log(value)
            console.log(node.value)
        }

实现vue中的MVVM原理

相关推荐