class Vue {
constructor(options) {
/* 视图的驱动 */
this.$el = options.el
this._data = options.data
this.$options = options
this.$watchEvent = {}
console.log(document.querySelector(this.$el),this._data,this.$options);
const node = document.querySelector(this.$el)
this.observe();
this.proxyData();
this.compile(node)
}
/* 渲染视图 */
observe() {
for (let key in this._data) {
let value = this._data[key]
let that = this;
Object.defineProperty(this._data, key, {
get() {
return value
},
set(val) {
value = val;
if (that.$watchEvent[key]) {
that.$watchEvent[key].forEach(item => {
item.update();
})
}
}
})
}
}
/* 数据劫持的原理就是对data当中的每一个属性都使用Object.defineProperty绑定get/set方法 */
proxyData() {
for (let key in this._data) {
Object.defineProperty(this, key, {
get() {
return this._data[key]
},
set(val) {
return this._data[key] = val
}
})
}
}
/* 模板解析:
将data数据渲染到模板当中
*/
compile(node) {
node.childNodes.forEach((item, index) => {
if (item.nodeType === 1) {
if (item.hasAttribute("@click")) {
let vmKey = item.getAttribute("@click").trim();
item.addEventListener("click", (e) => {
this.$options.methods[vmKey].bind(this)(e)
console.log(this);
})
}
if (item.hasAttribute("v-model")) {
console.log(111+item.getAttribute("v-model"));
let vmKey = item.getAttribute("v-model").trim();
if (this.hasOwnProperty(vmKey)) {
// console.log(item,this[vmKey]);
item.value = this[vmKey]
}
item.addEventListener('input', (event) => {
this[vmKey] = item.value
})
}
if (item.childNodes.length > 0) {
this.compile(item)
}
}
// console.log(item, item.nodeType);
if (item.nodeType === 3) {
// console.log(item, item.textContent);
const reg = /\{\{(.*?)\}\}/g
let text = item.textContent;
console.log(text+222);
item.textContent = text.replace(reg, (match, vmKey) => {
vmKey = vmKey.trim();
console.log(vmKey+111);
/* 渲染视图 */
// console.log(this, vmKey, item, 'textContent');
if (this.hasOwnProperty(vmKey)) {
let watch = new Watch(this, vmKey, item, 'textContent')
if (this.$watchEvent[vmKey]) {
this.$watchEvent[vmKey].push(watch)
} else {
this.$watchEvent[vmKey] = []
this.$watchEvent[vmKey].push(watch)
}
}
return this._data[vmKey]
})
}
});
}
}
class Watch {
constructor(vm, key, node, attr) {
this.vm = vm;
this.node = node;
this.key = key;
this.attr = attr;
}
//执行改变
update() {
this.node[this.attr] = this.vm[this.key]
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
{{msg}}
<p>{{ msg }}</p>
<h1>{{msg}}</h1>
<h4>{{msg}}</h4>
<h2>msg</h2>
<button @click="btn">点我试试</button>
<p @click="pppp">pppbiaoqian </p>
<input type="text" v-model="msg">
</div>
<script src="./vue.js"></script>
<script>
const vm = new Vue({
el: "#app",
data: {
msg: "Hello World",
message: "abcd"
},
methods: {
btn(e) {
this.msg = "世上只有妈妈好!"
console.log(e, 333333);
},
pppp() {
console.log("abcddddd");
}
}
})
console.log(vm);
</script>
</body>
</html>