• myvue 模拟vue核心原理


    // js部分index.js

    class Myvue{
        constructor(options){
            this.data = options.data;
            this.dep = new Dep();
            var id = options.el;
            this.observe();
            var Dom = this.VnodeContainer(document.querySelector(id));
            document.querySelector(id).appendChild(Dom);
        }
        VnodeContainer(node,flag){ // 虚拟DOM容器
            var flag = flag || document.createDocumentFragment();
            var child;
            while(child = node.firstChild){
                this.compile(child);
                flag.appendChild(child);
                this.VnodeContainer(child,flag);
            }
            return flag;
        }
        compile(node){ // 编译DOM
            let reg = /{{(.*)}}/g;
            if(node.nodeType === 1){ // 元素类型
                let attr = node.attributes;
                for(let i=0;i<attr.length;i++){
                    if(attr[i].nodeName === 'v-model'){
                        let name = attr[i].nodeValue;
                        node.addEventListener('input',(e)=>{
                            this.data[name] = e.target.value;
                        });
                        node.value = this.data[name];
    
                        this.dep.add(new Watcher(this.data,node,name));
                    }
                }
            }
            if(node.nodeType === 3){ // text类型节点
                if(reg.test(node.nodeValue)){
                    let name = RegExp.$1; // 匹配到的字符串
                    name = name.trim();
                    node.nodeValue = this.data[name];
    
                    this.dep.add(new Watcher(this.data,node,name));
                }
            }
        }
        observe(){
            Object.keys(this.data).forEach((el)=>{
                this.definePropertyInit(this.data,el,this.data[el]);
            });
        }
        definePropertyInit(target,key,value){ // 将data做成响应式的
            
            Object.defineProperty(target,key,{
                get:()=>{
                    return value;
                },
                set:(newVal)=>{
                    if(newVal === value) return;
                    value = newVal;
                    this.dep.notify(); // 更新
                }
            });
        }
    }
    class Dep{ // 发布者
        constructor(){
            this.subs = [];
        }
        add(sub){
            this.subs.push(sub);
        }
        notify(){
            this.subs.forEach((el)=>{
                el.update();
            });
        }
    }
    class Watcher{ // 观察者(订阅者)
        constructor(vm,node,name){
            Dep.global = this;
            this.vm = vm;
            this.node = node;
            this.name = name;
            this.update();
        }
        update(){
            this.get();
            switch (this.node.nodeType) {
                case 1: // 标签元素
                    this.node.value = this.value;
                    break;
                case 3: // 文本
                    this.node.nodeValue = this.value;
                    break;
                default: break;
            }
        }
        get(){
            this.value = this.vm[this.name];
        }
    }
    
    let vm = new Myvue({
        el: '#app',
        data: {
            msg: 'hello'
        }
    })

    html部分

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    </head>
    <body>
    
    <div id="app">
    <input type="text" id="input" v-model='msg'>
    <div id="box">{{msg}}</div>
    </div>
    
    <script src='./index.js'></script>
    </body>
    </html>
  • 相关阅读:
    知识点
    nodejs总结之redis模块
    nodejs总结之日志模块log4js
    各种类型的串口说明
    linux常用命令
    JAVA总结之编码
    JAVA总结之异常
    JAVA总结之方法重载
    JAVA总结之关键字static和final
    JAVA总结之数组篇
  • 原文地址:https://www.cnblogs.com/plBlog/p/12727180.html
Copyright © 2020-2023  润新知