深入了解Vue响应式数据,剖析diff算法 并手写简单diff算法达到Dom响应式编程

27 篇文章 0 订阅
4 篇文章 0 订阅

深入了解Vue响应式数据,剖析diff算法 并手写简单diff算法达到Dom响应式编程

Vue响应数据模式

Vue设计理念

vue是渐进式的JavaScript;
如下代码1

// a.html
<div id="app">
			<h3>我是标题</h3>
		</div>

如果我要改变Dom我们需要这样做:代码2

// 
const title = "我是改变后的标题"
		const h3 = document.createElement('h3');
		h3.textContent = title;
		  
		const dom = document.getElementById('app');
		
		setTimeout(res=>{ //延时效果
			dom.innerHTML = '';
			dom.appendChild(h3);
		},2000)

结果是修改一次dom需要10行代码 如果量大 整个html会非常的冗杂 ,如果我改变的只有数据 而dom中可以依据数据来改变 那我们的页面会省略对于dom的操作 如下(使用vue);代码3

// b.html
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
	<body>
		<div id="app">
			<h3>{{title}}</h3>
		</div>
	</body>
	<script type="text/javascript">
		// const title = "我是改变后的标题"
		// const h3 = document.createElement('h3');
		// h3.textContent = title;

		// const dom = document.getElementById('app');

		// setTimeout(res=>{ //延时效果
		// 	dom.innerHTML = '';
		// 	dom.appendChild(h3);
		// },2000)
		var em = new Vue({
			data(){
				return {
				title: '我是标题'
				}
			},
			mounted() {
				setTimeout(res => {
					this.title = "我是改变后的标题"
				}, 2000)
			}
		}).$mount('#app')
	</script>

当2秒后 我们可以看到 titile数据改变 dom中的title随着改变,这就是响应式数据;我们使用响应式数据模式后,我们只用去思考对于逻辑和数据的书写 ,不用在过多的时间考虑dom的更改,提高编写效率,(为数据驱动!),
接下来我们开始尝试实现一下;

模拟Vue响应式数据 实现

我们可以看到 在2秒后 属于app中的h3标签下的title产生了改变,万变不离根本,(再深入的框架 ,也是由最基础的原生js来编写)当data中的title改变的时候,他的最终操作dom的方式也是如代码2所示,建立dom 获取dom 覆盖dom;这个流程不可少;
所以我们要思考 改变他的原因是什么;改变如下 代码4

// c.html
var em = new Vue({
			data(){
				return {
				title: '我是标题'
				}
			},
			mounted() {
				setTimeout(res => {
					this.title = "我是改变后的标题"
				}, 2000)
			}
		}).$mount('#app');

我们看到 如果data中的数据改变 html必须是要改变 所以整个data都必须是响应式:代码5

//构造函数Vue
function Vue(option) {
			this.$options = option;
			this.$data = this.$options.data();
			this.isMounted = false;
			observe(this.$data);
			this.$methods = this.$options.mounted;
			// console.log(this)

			return this;
		}
		Vue.prototype.$mount = (el, n) => { // 获取dom结构  追加元素
			var that = this[n];//this指向window,这里改成em实例
			const parent = document.querySelector(el);
			//创建更新函数 
			console.log(that);
			that.update = function() {
				console.log('update');
				// 首次挂载,次更新
				if (!that.isMounted) {
					that.isMounted = true;
					if (that.$options.mounted) {
						that.$options.mounted.call(that.$data);
					}
				} else {}
			}
			that.update();
		}
//拿到传入的data 就可以做拦截;
// 拦截对象
		function observe(obj) { 
			//遍历obj 每一个key 定义拦截
			Object.keys(obj).forEach(key => defineReacitv(obj, key, obj[key]));
		}
		// 定义响应式函数
		function defineReacitv(obj, key, val){  //val形成闭包
			Object.defineProperty(obj,key,{
				get(){//获取数据
					console.log('get',key);
					return val;
				},
				set(newVal){//更新数据
					console.log('set',key);
					if(newVal !== val){
						val = newVal;
					}
				},
			})
		}

(闭包:一个函数作用域内的一个局部变量,通过内部函数,给外界去暴露,形成闭包,在内存中保存;)
通过控制台我们可以看到在这里插入图片描述
经过两秒后 更新了title已经显示
当每次更新完 则生成一个dom结构去替换原有的结构 就需要编译器

// dom编辑器 render
//dom编译器
		function render(html, val){
			html = document.createElement(html);
			html.textContent = val;
			return html;
		}
//prototype 更改如下
Vue.prototype.$mount = (el, n) => { // 获取dom结构  追加元素
			var that = this[n]; //this指向window,这里改成em实例
			const parent = document.querySelector(el);
			//创建更新函数 
			// console.log(that);
			that.update = function(key,val) {
				console.log('update');
				// const child = that.$options.render.call(this);
				const child = render('h3',that.$data[key]);
				console.log(render('h3',key));

				// 首次挂载,次更新
				if (!that.isMounted) {
					that.isMounted = true;
					parent.appendChild(child);
					if (that.$options.mounted) {
						that.$options.mounted.call(that.$data);
					}
				} else {
					parent.innerHTML = '';
					parent.appendChild(child);
				}
			}
			that.update('title');
		}
//更改响应函数defineReacitv
// 定义响应式函数
		function defineReacitv(obj, key, val) {
			Object.defineProperty(obj, key, {
				get() {
					console.log('get', key);
					return val;
				},
				set(newVal) {
					console.log('set', key);
					if (newVal !== val) {
						val = newVal;
						//update
						em.update(key);
					}
				},
			})
		}

得到如图在这里插入图片描述
目前只要title更改 页面就可以随title更改。。。响应式完成;

虚拟dom,diff算法

当dom开始随数据变化而变化 无需每次手写dom的更新,友好的模式已经实现,但我们思考一个问题,如上代码都是基于#app节点去更新,也就是说每次更新都是把整个#app去做替换,这样不必要的消耗是很大的,所以Vue和React 便研究出diff算法 把改变了数据的dom进行准确的替换

实现

发现太长了 ····分页发布

ps: 献给每个从零开始自学编程的小伙伴们(包括我)!.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

轻动琴弦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值