JavaScript原生实现mvvm

15 篇文章 0 订阅
9 篇文章 0 订阅

index.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>
    <div id="app">
        <h1>{{message}}</h1>
        <h2>{{message}}</h2>
        <p>{{foo}}</p>
        <input type="text" v-model="message">
        <input type="checkbox" v-model="completed">
        <h3>{{completed}}</h3>
    </div>
</body>
<script src="./02-event-watch.js"></script>
<script src="./03-vm.js"></script>
<script>
    var app=new Vue({
        el:'#app',
        data:{
            message:'hahaha',
            foo:'123',
            completed:true
        }
    })
</script>
</html>

02-event-watch.js

//myEvent.on('自定义事件名称meow',事件处理函数)
//myEvent.emit('meow')

function EventEmiter(){
    this.callbacks={};
}

EventEmiter.prototype.on=function(eventName,eventHandler){
    if(!this.callbacks[eventName]){
        this.callbacks[eventName]=[];
    }
    this.callbacks[eventName].push(eventHandler);
};

EventEmiter.prototype.emit=function(eventName){
    if(!this.callbacks[eventName]){
        return ;
    }
    var args=[].slice.call(arguments,1);
    this.callbacks[eventName].forEach(function(handler){
        handler.apply(null,args);
    })
};

03-vm.js

var vueEvent = new EventEmiter();

function Vue(options) {
    var { el, data } = options;
    var rootEl = document.querySelector(el);

    //接下来就要手动遍历DOM树
    var childNodes = rootEl.childNodes;

    subscribeEvents(childNodes);


    //遍历DOM树 订阅事件
    function subscribeEvents(childNodes) {
        for (var i = 0, len = childNodes.length; i < len; i++) {
            //判断节点类型
            //如果是文本节点,则验证内容是否包含{{}}
            //  如果是{{xxx}} 则提取xxx
            //  然后注册:xxx事件
            //  然后在事件订阅处理函数中,修改这个节点的textContent
            //如果不是文本节点,则继续递归遍历标签节点的childNodes
            const node = childNodes[i];
            var nodeType = childNodes[i].nodeType;
            //标签节点
            if (nodeType === 1) {
                if(node.nodeName==='INPUT'){
                    if(node.type==='text'){
                        var dataKey=node.attributes['v-model'].value;
                        node.oninput=function(){
                            data[dataKey]=node.value;
                            console.log(data[dataKey]);
                            vueEvent.emit(dataKey);
                        }
                        vueEvent.on(dataKey,function(){
                            node.value=data[dataKey];
                        })
                    }else if(node.type==='checkbox'){
                        var dataKey=node.attributes['v-model'].value;
                        node.onchange=function(){
                            data[dataKey]=node.checked?true:false;
                            vueEvent.emit(dataKey);
                        }
                        vueEvent.on(dataKey,function(){
                            node.checked=data[dataKey];
                        })   
                    }
                    
                }
                //递归遍历所有标签节点
                subscribeEvents(node.childNodes);
                //文本节点
            } else if (nodeType === 3) {
                var reg = /{{(.+)}}/;
                var matches = reg.exec(node.textContent);
                if (matches) {
                    var dataKey = matches[1].trim();
                    vueEvent.on(dataKey, function () {
                        node.textContent = data[dataKey];
                    })
                }

            }

        }
    }


      //数据观测,当数据发生改变的时候,发布这个数据改变对应的事件
    for (let key in data) {
        Object.defineProperty(this, key, {
            get: function () {
                return data.key;
            },
            set: function (value) {
                //改变数据
                //发布一个事件,告诉所有监听了message事件的DOM都去执行自己的处理函数
                data[key] = value;
                vueEvent.emit(key);
            }
        })
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值