美文网首页
vue简单实现双向绑定

vue简单实现双向绑定

作者: 悠哈121 | 来源:发表于2021-01-10 20:40 被阅读0次
<!DOCTYPE html>
<html>
    <head>
        <title>vue源码学习</title>
        <meta charset = "utf-8">
    </head>
    <body>
        <div id="app">
            <input v-model="msg"/>
            <p>{{msg}}</p>
            <h1 v-html="msg"></h1>
            <button @click="changeEvent">点击事件</button>
        </div>
        <script>
            // 1.构造vue(构造函数/类)
            class Vue{
                constructor(options){
                    this.$el = document.querySelector(options.el);
                    this.$options = options;
                    this.$watchEvent = {};  //监听事件,按照key保存 this.$watchEvent[key] = [event1,event2,...]
                    // 代理数据(循环通过set和get实现代理)
                    this.proxyData(options);
                    // 劫持事件
                    this.observe();
                    //将视图的数据、事件绑定
                    this.compile(this.$el);
                }
                proxyData(options){
                    for(let key in options.data){
                        Object.defineProperty(this,key,{
                            configurable:false,
                            enumerable:true,
                            set(newValue){
                                options.data[key] = newValue;
                            },
                            get(){
                                return options.data[key];
                            }

                        })
                    }
                }
                observe(){
                    for(let key in this.$options.data){
                        let value = this.$options.data[key];
                        let _this = this;
                        Object.defineProperty(this.$options.data,key,{
                            configurable:false,
                            enumerable:true,
                            set(newValue){
                                value = newValue;
                                if(_this.$watchEvent[key]){
                                    _this.$watchEvent[key].forEach(item=>{
                                        item.update()
                                    })
                                }
                            },
                            get(){
                                return value;
                            }

                        })
                    }
                }
                compile(PNode){
                    PNode.childNodes.forEach((node,index)=>{
                        if(node.nodeType == 1){
                            // console.log([node]) //可查看节点对象
                            // 元素类型
                            if(node.hasAttribute("v-html")){
                                let vmKey = node.getAttribute("v-html").trim();
                                node.innerHTML = this[vmKey];
                                let watcher = new Watch(this,vmKey,node,'innerHTML');
                                if(!this.$watchEvent[vmKey]){
                                    this.$watchEvent[vmKey] = [];
                                }
                                this.$watchEvent[vmKey].push(watcher);
                                
                            }
                            if(node.hasAttribute("v-model")){
                                let vmKey = node.getAttribute("v-model").trim();
                                if(this.hasOwnProperty(vmKey)){
                                    node.value = this[vmKey]
                                }
                                let watcher = new Watch(this,vmKey,node,'value');
                                if(!this.$watchEvent[vmKey]){
                                    this.$watchEvent[vmKey] = [];
                                }
                                this.$watchEvent[vmKey].push(watcher);
                                // 事件监听
                                node.addEventListener('input',(e)=>{
                                    this[vmKey] = e.target.value;
                                })
                            }
                            //判断绑定@click事件
                            if(node.hasAttribute("@click")){
                                node.addEventListener('click',(e)=>{
                                    let vmKey = node.getAttribute("@click").trim();
                                    let fn = this.$options.methods[vmKey].bind(this);
                                    fn(e);
                                })
                            }
                            if(node.childNodes.length>0){
                                this.compile(node)
                            }

                        }else if(node.nodeType == 3){
                            // 正则匹配文本类型
                            let reg = /\{\{(.*?)\}\}/g;
                            let text = node.textContent;
                            node.textContent = text.replace(reg,(match,vmKey)=>{
                                vmKey = vmKey.trim();
                                let watcher = new Watch(this,vmKey,node,'textContent');
                                if(!this.$watchEvent[vmKey]){
                                    this.$watchEvent[vmKey] = [];
                                }
                                this.$watchEvent[vmKey].push(watcher);
                                return this[vmKey]
                            })
                            
                        }
                    })
                }
            }
            class Watch{
                constructor(vm,key,node,attr,nType){
                    this.vm = vm; //实例化的app对象
                    this.key = key; //即绑定vm触发的属性
                    this.node = node; //vm[key]数据绑定的html的节点
                    this.attr = attr; //vm[key]数据绑定html节点属性名称
                    this.nType = nType;
                }
                update(){
                    this.node[this.attr] = this.vm[this.key]
                }
            }
        </script>
        <script>
             let app = new Vue({
               el:'#app',
               data:{
                   msg:'hahaha'
               },
               methods:{
                   changeEvent:function(){
                       this.msg = "hello"
                   }
               }
           })
        </script>
    </body>
</html>



相关文章

  • 深入Vue响应式原理

    1.Vue的双向数据绑定 参考 vue的双向绑定原理及实现Vue双向绑定的实现原理Object.definepro...

  • Vue实现数据双向绑定的原理

    Vue实现数据双向绑定的原理:Object.defineProperty() vue实现数据双向绑定主要是:采用数...

  • vue 双向数据绑定

    Vue实现数据双向绑定的原理:Object.defineProperty()vue实现数据双向绑定主要是:采用数据...

  • js实现双向数据绑定

    js双向绑定几种方法的介绍 使用Object.defineProperty实现简单的js双向绑定剖析Vue原理&实...

  • Vue框架基础

    原生js与Vue框架的区别 用原生实现双向数据绑定 用Vue实现双向数据绑定 Vue是一个javaScript框架...

  • Vue2.0原理与MVVM的实现

    剖析Vue原理&实现双向绑定MVVM vue源码 双向绑定 -- MVVM 目前几种主流的MVC框架都实现了单向数...

  • 【转】JavaScript的观察者模式(Vue双向绑定原理)

    关于Vue实现数据双向绑定的原理,请点击:Vue实现数据双向绑定的原理原文链接:JavaScript设计模式之观察...

  • 前端理论面试--VUE

    vue双向绑定的原理(详细链接) VUE实现双向数据绑定的原理就是利用了 Object.definePropert...

  • Vue双向数据绑定原理

    剖析Vue实现原理 - 如何实现双向绑定mvvm 本文能帮你做什么?1、了解vue的双向数据绑定原理以及核心代码模...

  • 关于双向绑定的问题

    剖析Vue实现原理 - 如何实现双向绑定mvvm 本文能帮你做什么?1、了解vue的双向数据绑定原理以及核心代码模...

网友评论

      本文标题:vue简单实现双向绑定

      本文链接:https://www.haomeiwen.com/subject/uxmhjktx.html