vue实现原理,原生代码

vue实现原理,实现数据的双向绑定

<!DOCTYPE html>
<!-- 数据的双向绑定 -->
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
	</head>
	<body>
		<div id="app">
			<input type="text" v-model="msg">
			<h1>{{msg}}</h1>
			<!-- v-html绑定的时h1对象上的innerhtml-->
			<h1 v-html="msg"></h1>
			<button type="button" @click="changeEvent">修改MSG</button>
		</div>
		
		<script type="text/javascript">
			class Vue{
				constructor(options) {
					//通过选择获取根对象
				    this.$el = document.querySelector(options.el);
					
					
					
					//数据创造之前
					if(typeof options.beforeCreate == 'function'){
						options.beforeCreate.bind(this)()
					}
					
					this.$options= options
					
					
					this.$watchEvent = {}
					//this.$watchEvent[key] = [event,event,event]
					//设置1个对象专门保存修改更新的事件
					//代理options的data数据
					
					this.proxyData()
					
					//劫持设置事件
					
					this.observe()
					
					
					
					//数据创造之后
					if(typeof options.createcd == 'function'){
						options.createcd .bind(this)()
					}
					
					
					//console.log(options.data)
					//挂载前
					if(typeof options.beforeMount == 'function'){
						options.beforeMount .bind(this)()
					}
					
					//把view的数据喝事件进行绑定
					this.compile(this.$el)
					
					//挂载后
					if(typeof options.mounted == 'function'){
						options.mounted.bind(this)()
					}
					
					}
					proxyData(){
						//循环通过set,get方法来实现代理数据
						for(let key in this.$options.data){
							//console.log(key)
							Object.defineProperty(this,key,{
								configurable:false,
								enumerable:true,//迭代,默认false
								//value:"定义值"
								//writeable:true,false"是否能够更改"
								get(){
									//获取this[key]时,即返回options的data[]
									return this.$options.data[key]
								},
								set(val){
									
									this.$options.data[key] = val
								},
							})
							
						}
					}
					observe(){
						//劫持事件
						for(let key in this.$options.data){
							//获取此处value保存
							let value = this.$options.data[key]
							let that = this
							Object.defineProperty(this.$options.data,key,{
								configurable:false,
								enumerable:true,//迭代,默认false
								//value:"定义值"
								//writeable:true,false"是否能够更改"
								get(){
									//获取this[key]时,即返回options的data[]
									//console.log("触发获取内容事件")
									return value
								},
								set(val){
									value = val
									//console.log("触发设置事件")
									//触发以这个key值的更新事件
									if(that.$watchEvent[key]){
										//console/log(that.$watchEvent[key])
										that.$watchEvent[key].forEach((item,index)=>{
											item.updata()//通过updata更新
										})
									}
								},
							})
						}
					}
					compile(cNode){
						//console.log([this.$el])
						cNode.childNodes.forEach((node,index)=>{
							if(node.nodeType == 1){
								//元素类型,getAttribute,hasAttribute
								if(node.hasAttribute('v-html')){
									//console.log(vmKey)
									let vmKey = node.getAttribute('v-html').trim();
									if(this.hasOwnProperty(vmKey)){
										node.innerHTML = this[vmKey]
										let watcher = new Watch(this,vmKey,node,'innerHTML')
										if(this.$watchEvent[vmKey]){
											this.$watchEvent[vmKey].push(watcher)
										}else{
											this.$watchEvent[vmKey] = [];
											this.$watchEvent[vmKey].push(watcher)
										}
										//删除属性
										node.removeAttribute('v-html')
									}
									
								}
								
								//判断是否由v-model属性
								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')v
										if(this.$watchEvent[vmKey]){
											this.$watchEvent[vmKey].push(watcher)
										}else{
											this.$watchEvent[vmKey] = [];
											this.$watchEvent[vmKey].push(watcher)
										}
										
									}
									//节点input事件监听
									node.addEventListener('input',(event)=>{
										this[vmKey] = node.value;
										
									})
									//删除属性
									node.removeAttribute('v-model')
								}
								
								//判断是否有数据绑定@click属性
								if(node.hasAttribute('@click')){
									let vmKey = node.getAttribute('@click').trim();
									node.addEventListener('click',(event)=>{
										this.eventFn= this.$options.methods[vmKey].bind(this)
										this.eventFn(event)
									})
								}
								
								if(node.childNodes.length>0){
									this.compile(node)//将节点放进去继续编译
								}
							}
							if(node.nodeType == 3){
								//文本类型
								let reg = /\{\{(.*?)\}\}/g;  //.*?就是需要匹配的内容,g全局配置
								//console.log()
								let text = node.textConent;
								//console.log('xxxxx')
								node.textContent = node.textContent.replace(reg,(match,vmKey)=>{
									//console.log(match)
									//console.log(vmKey)
									//去除空格
									vmKey = vmKey.trim()
									if(this.hasOwnProperty(vmKey)){
										node.value = this[vmKey];
										let watcher = new Watch(this,vmKey,node,'textConent')
										if(this.$watchEvent[vmKey]){
											this.$watchEvent[vmKey].push(watcher)
										}else{
											this.$watchEvent[vmKey] = [];
											this.$watchEvent[vmKey].push(watcher)
										}
										
									}
									
									return this[vmKey]
									
									
								}) //返回替换的字符串
							}
						})
					}
				}
			
			
			
				class Watch{
					constructor(vm,Key,node,attr,nType){
						this.vm = vm;
						//vm实例化的app对象
						this.key = Key;
						//key即绑定的vm触发的属性
						this.node = node;
						//node即,此vm[key]数据绑定的html节点
						//this.property = property;
						//property即vm数据所绑定的属性的名称
						this.attr = attr;
					}
					updata(){
						//更新之前
						if(typeof options.beforeUpdata == 'function'){
							options.beforeUpdata.bind(this)()
						}
						this.node[this.attr] = this.vm[this.key];
						//数据更新之后
						if(typeof options.updatad == 'function'){
							options.updatad.bind(this)()
						}
					}
				}
		</script>
		
		<script type="text/javascript">
			let options = {
				el:"#app",
				data:{
					msg:"hello vue",
					username:"小明",
				},
				methods:{
					changeEvent:function(){
						this.msg="hello laoli"
					}
				},
				beforeMount(){
					//挂载前
					console.log("挂载前")
				},
				mounted(){
					console.log('挂载后')
				}
				
			}
			let app = new Vue(options)
			//app.msg == options.data
			//app.msg = 'abc'
			//options.data.msg = 'abc'
			console.log(app)
		</script>
	</body>
	
</html>

实现代码视频链接:https://www.bilibili.com/video/BV1m741137Q5?p=32

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值