Vue仿写之Proxy写法

用Proxy仿写Vue

相比较与defineProperty,Proxy不用遍历对象中属性,还不用进行configurable、enumrable的配置

Proxy用法

 let o ={
            name:"张三",
            age:26
        }
        // Proxy会返回一个Proxy对象,主要用于从外部控制对对象内部的访问;
        // 实质上就是通过get()、set()监听对象内部属性的获取和修改,
        // 从外部获取或修改对象内部属性时,就会触发函数
        // 相比较与defineProperty,Proxy不用遍历对象中属性,还不用进行configurable、enumrable的配置
        let newObj = new Proxy(o,{
            get(target,key){
                console.log("get.....")
                return target[key];
            },
            set(target,key,newValue){
                console.log("set....")
                target[key] = newValue;
                return true;
            }
        })
        console.log(newObj.name);
        newObj.name = "李四";
        newObj.hobby = "打球"

运行结果:
运行结果
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>
    <script src="kvue2.js" type="text/javascript"></script>
</head>

<body>
    <div id="app">
        {{message}}
        <div v-html="htmlData"></div>
        <input v-model="modelData" /> {{modelData}}
    </div>
    <script>
        let kvue = new Kvue({
            el: "#app",
            data: {
                message: "测试数据",
                htmlData: "html数据",
                modelData: "绑定的数据"
            }
        })
        console.log(kvue.$options.data);
        // kvue.$options.data.message="123"
        
    </script>
</body>

</html>

js部分:

class Kvue extends EventTarget{
    constructor(options){
        super();
        this.$options = options;
        this.compile();
        this.observe(this.$options.data);

    }
    compile(){
        // 获取节点
        let el =document.querySelector(this.$options.el);
        // 渲染节点
        this.compileNode(el);
    }

    observe(data){
        let _this = this;
        this.$options.data = new Proxy(data,{
            get(target,key){
                console.log("get...")
                return target[key];  
            },
            set(target,key,newValue){
                console.log("set...")
                // 以data中的属性名为事件名创建一个新事件,并将newValue传参
                let event = new CustomEvent(key,{detail:newValue})
                // 每次data中对应属性的数据值改变时就会触发set()函数,相应的就派发事件,达到数据驱动视图的效果
                _this.dispatchEvent(event);
                target[key] = newValue;
                return true;
            }
        })
    }

    compileNode(el){
        // chilNodes获取的是制定节点下的所有子节点
        let childNodes = el.childNodes;
        childNodes.forEach(node => {
            if(node.nodeType==1){
                // nodetype为1是元素节点
                // 
                let attrs = node.attributes;
                
                [...attrs].forEach(attr=>{
                    // console.log(attr);
                    let attrName = attr.name;
                    let attrValue = attr.value;
                    if(attrName.indexOf("v-")===0){
                        // Array.indexOf()返回数组中指定元素的位置
                        attrName = attrName.substr(2);
                        // substr(start,length)截取从start位置开始的指定数目的字符
                        console.log(attrName);
                        if(attrName==="html"){
                            node.innerHTML = this.$options.data[attrValue];
                        }else if (attrName==="model"){
                            node.value = this.$options.data[attrValue];
                            node.addEventListener("input",e=>{
                                // console.log(e.target.value);
                                this.$options.data[attrValue] = e.target.value;
                            })
                        }
                    }
                })
                if(node.childNodes.length>0){
                    this.compileNode(node);
                }
            }
           else if(node.nodeType==3){
                // nodetype为3是文本节点
                // 获取文本节点的文本内容
                let textcontent = node.textContent;
                // 正则表达式匹配规则 匹配{{message}}
                let reg = /\{\{\s*(\S+)\s*\}\}/g;

                if(reg.test(textcontent)){
                    let $1 = RegExp.$1;
                    node.textContent=node.textContent.replace(reg,this.$options.data[$1]);
                    // 在这里绑定事件,$1就是data中的属性值
                    this.addEventListener($1,e=>{
                        // e.detail就是上面defineReact()中数据劫持里创建事件所传的newValue
                        console.log(e.detail);
                        let oldValue = this.$options.data[$1];
                        let reg = new RegExp(oldValue);
                        node.textContent = node.textContent.replace(reg,e.detail);
                    })
                }

            }
        });
    }
}

运行结果:
运行结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值