vue mvvm原理

效果图:

 页面代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <h2>{{title}}</h2>
        <input v-model="name">
        <h1>{{name}}</h1>
        <button v-on:click="clickMe">click me!</button>
        <p>aaaa{{xxx}}zzzz</p>
    </div>
	
	<script type="text/javascript" src="./vue.js"></script>
	<script type="text/javascript">
		var selfVue = new Vue({
			el: '#app',
			data: {
				title: 'hello world',
				name: 'null',
				xxx: 'cjh'
			},
			methods: {
				clickMe: function() {
					this.title = 'hello world';
				}
			},
			mounted: function() {
				window.setTimeout(() => {
					this.title = '你好';
				}, 2000);
			}
		});
		
	</script>
    <!-- <h1 id="name">{{name}}</h1> -->
</body>

</html>
<script>

vue.js 代码

//劫持监听数据
function observe(data) {
	if (typeof data !== 'object') {
		throw '参数错误'
	}
	Object.keys(data).forEach(key => {
		defineReactive(data, key, data[key])
	})
}
//监听所有属性
function defineReactive(data, key, value) {
	if (typeof value == "object") {
		observe(value)
	}
	let dep = new Dep()
	Object.defineProperty(data, key, {
		enumerable: true, // 可枚举
		configurable: false, // 可配置
		get: function() {
			if (Dep.target) {
				dep.add(Dep.target)
			}
			return value
		},
		set: function(target) {
			value = target;
			dep.notify()
		},
	})
}
//订阅器容器
class Dep {
	static targer = null
	constructor() {
		this.sub = []
	}
	add(data) {
		this.sub.push(data)
	}
	notify() {
		this.sub.forEach(e => {
			e.updata()
		})
	}
}
class Watcher{
	constructor(vm,exp,cb) {
	    this.vm=vm
		this.exp=exp
		this.cb=cb
		this.value=this.get()
	}
	updata(){
		this.run()
	}
	run(){
		let oldValue=this.value
		let value=this.vm[this.exp]
		if(value!==oldValue){
			this.value=value
			this.cb.call(this.vm,value,oldValue)
		}
	}
	get(){
		Dep.target=this
		let value=this.vm.data[this.exp]
		Dep.target=null
		return value
	}
}
class Compile{
	constructor(el,vm){
		this.vm=vm
		this.el=document.querySelector(el)
		this.fragment = null;
		this.init()
	}
	init(){
		if (this.el) {
			this.fragment=this.nodeToFragment(this.el)
			this.compileElement(this.fragment);
			this.el.appendChild(this.fragment)
		} else {
			console.log('Dom元素不存在');
		}
	}
	nodeToFragment(el){
		let fragment=document.createDocumentFragment()
		let child=el.firstChild
		while(child){
			fragment.appendChild(child)
			child=el.firstChild
		}
		return fragment
	}
	compileElement(el){
		var childNodes = el.childNodes;
		var self = this;
		Array.prototype.slice.call(childNodes,0).forEach(node=>{
			const reg=/\{\{(.*)\}\}/
			let text=node.textContent
			if(self.isElementNode(node)){
				self.compile(node);
			}else if(self.isTextNode(node)&&reg.test(text)){
				self.compileText(node,reg.exec(text)[1])
			}
			if(node.childNodes&&node.childNodes.length){
				self.compileElement(node)
			}
		})
	}
	compile(node,exp){
		let attrs=node.attributes
		Array.prototype.map.call(attrs,attr=>{
			var attrName = attr.name;
			if(this.isDirective(attrName)){
				let exp=attr.value
				let dir=attr.name.substring(2)
				if(this.isEventDirective(attrName)){
					this.compileEvent(node, this.vm, exp, dir);
				} else { // v-model 指令
					this.compileModel(node, this.vm, exp, dir);
				}
			}
		})
	}
	compileEvent(node, vm, exp, dir){
		let cb=vm.methods&&vm.methods[exp]
		node.addEventListener(dir,cb.bind(vm),false)
	}
	compileModel(node, vm, exp, dir){
		let val=this.vm[exp];
		this.modelUpdatar(node,val)
		new Watcher(vm,exp,(value)=>{
			this.modelUpdatar(node,value)
		})
		node.addEventListener('input',(e)=>{
			let newValue=e.target.value
			if(newValue!==val){
				val=newValue
				this.vm[exp]=newValue
			}
		})
	}
	compileText(node,exp){
		let self=this
		var initText = this.vm[exp];
		this.updataText(node, initText); // 将初始化的数据初始化到视图中
		new Watcher(this.vm,exp,(value)=>{
			this.updataText(node, value); // 将初始化的数据初始化到视图中
		})
	}
	//更新文本
	updataText(node, value) {
		node.textContent = typeof value == 'undefined' ? '' : value;
	}
	//更新模块
	modelUpdatar(node, value, oldValue) {
		node.value = typeof value == 'undefined' ? '' : value;
	}
	// 判断是是不是v-指令
	isDirective(attr) {
		return attr.indexOf('v-') == 0;
	}
	// 判断是是不是on:事件指令
	isEventDirective(dir) {
		return dir.indexOf('on:') === 0;
	}
	isTextNode(node){
		return node.nodeType===3
	}
	isElementNode(node){
		return node.nodeType===1
	}
}
//ANGLE_instanced_arrays
class Vue {
	constructor(data) {
		let self = this
		this.data = data.data
		this.vm=this
		this.methods = data.methods
		//赋值时,属性的绑定做一层封装
		Object.keys(this.data).forEach(function(key) {
			self.proxyKeys(key); // 绑定代理属性
		});
		observe(this.data)
		new Compile(data.el, this.vm) //挂载点,实例对象
		data.mounted.call(this); // 所有事情处理好后执行mounted函数
		return this;
	}
	proxyKeys(key){
		let self = this
		Object.defineProperty(this, key, {
			enumerable: false,
			configurable: true,
			get: function proxyGetter() {
				return self.data[key];
			},
			set: function proxySetter(newVal) {
				self.data[key] = newVal;
			}
		});
	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值