vue 双向数据绑定 实现原理

1 篇文章 0 订阅
1 篇文章 0 订阅

随着自己在前端越来越深入,也越来越喜欢前端。自己的路还有很长,希望能和大家一起努力进步。 本人不太习惯写博客,但正在尝试习惯。每增加一个阅读量,感觉就很受到鼓励。 这一次自己摸索出vue双向数据绑定的原理,不足的地方希望大家给予指正

class Mvvm {
    constructor({el,data}){
        this.$el=document.querySelector(el);//获取dom元素
        this.data=data 
        this.arr=[] //存放每一个监听函数
        this.init()
        this.initDom()
    }
    init(){
        this.intercept(this.data)
    }
    intercept(data){//数据劫持 
        let _this=this
        if(!data || typeof(data)!=='object'){
            return 
        }
        Object.keys(data).forEach(item=>{ //将对象或数组 KEY 取出 遍历
            let val=data[item] //定义每一索引对应的val
            Object.defineProperty(data,item,{ //添加劫持
                get(){
                    return val //默认返回每一次遍历取到的数据
                },
                set(newVal){
                    if(val===newVal){return} //数据没有变化不执行
                    val=newVal
                    _this.arr.forEach(item=>{item()})//每一次触发get 函数都会触发一次获取函数
                }
            })
            this.intercept(val)
        })
    }
    initDom(){
        let createObj=this.createElement();
        this.findNode(createObj)
        this.$el.appendChild(createObj)
    }
    createElement(){//创建文档碎片
        let fragment=document.createDocumentFragment();
       let childrens;
       while(childrens=this.$el.firstChild){ //将元素里的节点都放到文档碎片
           fragment.appendChild(childrens)
       }
       return fragment
   }
    findNode(node){//节点处理  在文档碎片里处理数据  不会引起浏览器的重排和重绘
        let _this=this;
        if(node.nodeType===1){//节点类型为1
            let attr=[...node.attributes] //获取节点属性 为一个数组
            attr.forEach(item=>{
                if(item.nodeName==='v-model'){
                    node.value=_this.getdata(this.data,item.nodeValue) //获取数据函数
                    node.addEventListener("input",(e)=>{//input 添加事件
                        this.data ,
                        _this.getval(_this.data,item.nodeValue,e.target.value) //input=>value 
                    },false)
                }
            })
        }else if(node.nodeType===3){
            let content=node.textContent
            if(content.indexOf("{{")>-1){   
                let str= content.split("{{")[1].split("}}")[0]
                node.textContent=this.getdata(this.data,str) //{{}}里的文本替换为数据
                //创建watcher 方法[()=>{}]
                    str && _this.arr.push(_this.watch(this.data,str,(newVal)=>{ //每一个{{}}的文本节点 都会绑定一个 watcher方法=>里面存储着当前文本节点的数据
                        node.textContent=newVal})) //重点为回调函数 对应watch方法里的callback 每一次触发defineProperty函数的set方法都会触发监听函数  监听函数会返回一个获取到的最新的修改后的val
            }
        }   
        if(node.childNodes &&node.childNodes.length>0){//递归 确保每一级节点都能遍历到
            [...node.childNodes].forEach(item=>{
                this.findNode(item)
            })
        }
    }
    getdata(data,key){//解析{{}} 和v-model
        if(key.indexOf(".")>-1){
            key.split(".").forEach(item=>{
                data=data[item]
            })
            return data
        }else{
            return data[key]
        }
    }
    getval(data,key,newVal){//input输入事件  将value值赋给数据
        if(key.indexOf(".")>-1){
           let arr=key.split(".")
           for(let i=0;i<arr.length-1;i++){
               data=data[arr[i]]  //{}/}
           }
           data[arr[arr.length-1]]=newVal 
        }else{
             data[key]=newVal
        }
    }
    watch=(data,key,callback)=>()=>{//监听函数
            let newVal=this.getdata(data,key)
         	callback(newVal) //此处为回调函数调用的参数 传递给 定义的位置
    } 
}
   
new Mvvm({
			el:".box",
			data:{
				val:"我帅不帅",
				person:{
					a:{
						b:"当然"
					}
				},
				son:{
					a:{
						b:{
							c:{
								d:"1123"
							}
						}
					}
				}
			}
		})
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看rEADME.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看rEADME.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通;、 3本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看ReAdmE.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值