欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

自己封装Vue实例

程序员文章站 2022-06-24 16:50:06
大家好,我是热狗得小舔狗!给大家分享一下,如何自己封装一个Vue实例。看图!!!
  • {{count}}
  • {{count}}
  • {{count}}
  • ...

大家好,我是热狗得小舔狗!
给大家分享一下,如何自己封装一个Vue实例
看图!!!

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>new vue</title>
	</head>
	<body>
		<div id="app">
			<input type="text" name="in" v-model="count">
			<ul>
				<li><div><p><ul>{{message}}</ul></p></div></li>
				<li>{{count}}</li>
				<li>--------------</li>
			</ul>
			{{message}}
		</div>
	</body>
	
	
	<script src="js/compile.js"></script>
	<script src="js/mvvm.js"></script>
	<script type="text/javascript">
		let app = new Mvvm({
			el: '#app',
			data: {
				message: 'hello',
				count: 1
			}
		})
	</script>
</html>

自己封装Vue实例

那么它是如何实现的呢。
自己封装Vue实例
我们都知道在vue中实现双向绑定需要
1 模板的编译
2 数据劫持
3 Watcher

这篇主要实现简单模板的编译。
大致思想:使用类的概念,创建实例时new MVVM({…})对里的对象当参数处理。
input等标签通过js获取v-model属性和值,节点,然后把传来的对应data参数渲染出去。
{{message}}通过匹配 获取{{}}里字符,在把传来的对应data参数渲染出去。

  1. 首先 index.html文件
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>new vue</title>
	</head>
	<body>
		<div id="app">
			<input type="text" name="in" v-model="count">
			<ul>
				<li><div><p><ul>{{message}}</ul></p></div></li>
				<li>{{count}}</li>
				<li>--------------</li>
			</ul>
			{{message}}
		</div>
	</body>
	
	
	<script src="js/compile.js"></script>
	<script src="js/mvvm.js"></script>
	<script type="text/javascript">
		let app = new Mvvm({
			el: '#app',
			data: {
				message: 'hello',
				count: 1
			}
		})
	</script>
</html>

上面代码大家也可以看到,还需要两个js文件。
MVVM.js文件

class Mvvm {
	constructor(obj) {
	    this.$el = obj.el;
		this.$data = obj.data;
		
		if(this.$el) {
			// 渲染
			new Compile(this);
		}
	}
}

这里就是写一个MVVM类。这里constructor函数有点python的__init__()的味道,在new MVVM()的创建实例时候,会自动调用该函数。options为传入参数{ el: “app”, data: {count: 2} }。

Compile.js

class Compile {
	constructor(app) {
		// 判断传入是dom整体元素  还是dom的id
		// this.el使用dom整体元素
	    this.el = this.isElementNode(app.$el) ? app.$el : document.querySelector(app.$el);
		this.data = app.$data;
		this.app = app
		
		if(this.el) {
			// 返回内存dom对象
			let fragment = this.CreateFragment(this.el);
			
			// 编译内存dom
			this.compile(fragment);
			
			// 取出内存dom
			// 不然浏览器上就会没有显示
			this.el.appendChild(fragment)
		}
	}
	
	// 创建内存dom
	CreateFragment(el) {
		let fragment = document.createDocumentFragment();
		let firstChild;
		
		while(firstChild = el.firstChild) {
			fragment.appendChild(firstChild)
		}
		
		return fragment;
	}
	
	// 编译
	compile(fragment) {
		let childNodes = fragment.childNodes;
		
		Array.from(childNodes).forEach(node => {
			
			if(this.isElementNode(node)){
				// 元素节点
				this.compileElement(node);
				// 深度编译
				// 因为有标签嵌套
				this.compile(node);
			}else{
				// 文本节点
				this.compileText(node);
			}
		})
	}
	
	// 编译元素节点中指令 
	// ex: v-model 
	compileElement(node) {
		let attrs = node.attributes;
		Array.from(attrs).forEach(attr => {
			let attrName = attr.name;
			if(attrName.includes('v-')) {
				let [, type] = attrName.split('-');
				let attrValue = attr.value;
				CompileUtil[type](node, this.app, attrValue);
			}
		})
		
	}
	
	// 编译文本中指令
	// ex: {{...}}
	compileText(node) {
		let textContent = node.textContent;
		let reg = /\{\{([^}]+)\}\}/g;
		
		if(reg.test(textContent)) {
			CompileUtil['text'](node, this.app, textContent);
		}
	}
	
	

	isElementNode(node) {
		return node.nodeType === 1;
	}
}

/**
 * 编译工具类
 * 
 * 主要实现vue指令 最终渲染
 */

CompileUtil = {
	model(node, app, attrValue) {
		node.value = app.$data[attrValue];
	},
	
	
	text(node, app, textContent) {
		let value = textContent.replace(/\{\{([^}]+)\}\}/g, (...args) => args[1]).replace(/^\s+|\s+$/g,"");

		node.textContent = app.$data[value];
	}
}

大家可以直接copy运行一下,我的已经可以跑起来了。不过呢,注意文件路径!!!
下一篇文章将会写一下数据劫持和Watcher。实现最终的效果!

本文地址:https://blog.csdn.net/Nan_gao_0/article/details/111084910

相关标签: Vue Javascript