index.html
<!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">
<h1>{{message}}</h1>
<h2>{{message}}</h2>
<p>{{foo}}</p>
<input type="text" v-model="message">
<input type="checkbox" v-model="completed">
<h3>{{completed}}</h3>
</div>
</body>
<script src="./02-event-watch.js"></script>
<script src="./03-vm.js"></script>
<script>
var app=new Vue({
el:'#app',
data:{
message:'hahaha',
foo:'123',
completed:true
}
})
</script>
</html>
02-event-watch.js
//myEvent.on('自定义事件名称meow',事件处理函数)
//myEvent.emit('meow')
function EventEmiter(){
this.callbacks={};
}
EventEmiter.prototype.on=function(eventName,eventHandler){
if(!this.callbacks[eventName]){
this.callbacks[eventName]=[];
}
this.callbacks[eventName].push(eventHandler);
};
EventEmiter.prototype.emit=function(eventName){
if(!this.callbacks[eventName]){
return ;
}
var args=[].slice.call(arguments,1);
this.callbacks[eventName].forEach(function(handler){
handler.apply(null,args);
})
};
03-vm.js
var vueEvent = new EventEmiter();
function Vue(options) {
var { el, data } = options;
var rootEl = document.querySelector(el);
//接下来就要手动遍历DOM树
var childNodes = rootEl.childNodes;
subscribeEvents(childNodes);
//遍历DOM树 订阅事件
function subscribeEvents(childNodes) {
for (var i = 0, len = childNodes.length; i < len; i++) {
//判断节点类型
//如果是文本节点,则验证内容是否包含{{}}
// 如果是{{xxx}} 则提取xxx
// 然后注册:xxx事件
// 然后在事件订阅处理函数中,修改这个节点的textContent
//如果不是文本节点,则继续递归遍历标签节点的childNodes
const node = childNodes[i];
var nodeType = childNodes[i].nodeType;
//标签节点
if (nodeType === 1) {
if(node.nodeName==='INPUT'){
if(node.type==='text'){
var dataKey=node.attributes['v-model'].value;
node.oninput=function(){
data[dataKey]=node.value;
console.log(data[dataKey]);
vueEvent.emit(dataKey);
}
vueEvent.on(dataKey,function(){
node.value=data[dataKey];
})
}else if(node.type==='checkbox'){
var dataKey=node.attributes['v-model'].value;
node.onchange=function(){
data[dataKey]=node.checked?true:false;
vueEvent.emit(dataKey);
}
vueEvent.on(dataKey,function(){
node.checked=data[dataKey];
})
}
}
//递归遍历所有标签节点
subscribeEvents(node.childNodes);
//文本节点
} else if (nodeType === 3) {
var reg = /{{(.+)}}/;
var matches = reg.exec(node.textContent);
if (matches) {
var dataKey = matches[1].trim();
vueEvent.on(dataKey, function () {
node.textContent = data[dataKey];
})
}
}
}
}
//数据观测,当数据发生改变的时候,发布这个数据改变对应的事件
for (let key in data) {
Object.defineProperty(this, key, {
get: function () {
return data.key;
},
set: function (value) {
//改变数据
//发布一个事件,告诉所有监听了message事件的DOM都去执行自己的处理函数
data[key] = value;
vueEvent.emit(key);
}
})
}
}