vue/compiler.jsclass Compiler {
constructor(vm) {
this.el = vm.$el
this.vm = vm
this.compile(this.el)
}
compile(el) {
let childNodes = el.childNodes
Array.from(childNodes).forEach(node => {
if (this.isTextNode(node)) {
this.compileText(node)
} else if (this.isElementNode(node)) {
this.compileElement(node)
}
if (node.childNodes && node.childNodes.length) {
this.compile(node)
}
})
}
compileElement(node) {
Array.from(node.attributes).forEach(attr => {
let attrName = attr.name
if (this.isDirective(attrName)) {
attrName = attrName.substr(2)
let key = attr.value
if (attrName.startsWith('on')) {
const event = attrName.replace('on:', '')
return this.eventUpdate(node, key, event)
}
this.update(node, key, attrName)
}
})
}
compileText(node) {
let reg = /\{\{(.+?)\}\}/
let value = node.textContent
if (reg.test(value)) {
let key = RegExp.$1.trim()
node.textContent = value.replace(reg, this.vm[key])
new Watcher(this.vm, key, (newValue) => {
node.textContent = newValue
})
}
}
update(node, key, attrName) {
let updateFn = this[attrName + 'Updater']
updateFn && updateFn.call(this, node, this.vm[key], key)
}
eventUpdate(node, key, event) {
this.onUpdater(node, key, event)
}
textUpdater(node, value, key) {
node.textContent = value
new Watcher(this.vm, key, (newValue) => {
node.textContent = newValue
})
}
htmlUpdater(node, value, key) {
node.innerHTML = value
new Watcher(this.vm, key, (newValue) => {
node.innerHTML = newValue
})
}
modelUpdater(node, value, key) {
node.value = value
new Watcher(this.vm, key, (newValue) => {
node.value = newValue
})
node.addEventListener('input', () => {
this.vm[key] = node.value
})
}
onUpdater(node, key, event) {
node.addEventListener(event, (e) => this.vm[key](e))
}
isDirective(attrName) {
return attrName.startsWith('v-')
}
isTextNode(node) {
return node.nodeType === 3
}
isElementNode(node) {
return node.nodeType === 1
}
}
vue/index.html<!DOCTYPE html>
<html lang="cn">
<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>Mini Vue</title>
<script src="./vue/dep.js"></script>
<script src="./vue/watcher.js"></script>
<script src="./vue/compiler.js"></script>
<script src="./vue/observer.js"></script>
<script src="./vue/vue.js"></script>
</head>
<body>
<div id="app">
<h1 v-on:click="myClick">点击事件</h1>
<h3>{{ msg }}</h3>
<h1>v-text</h1>
<div v-text="msg"></div>
<h1 v-html='html'></h1>
<input type="text" v-model="msg">
<input type="text" v-model="count">
<h1>{{dog.name}}</h1>
</div>
</body>
<script>
let vm = new Vue({
el: '#app',
data: {
msg: 'object1111',
dog: {
name: ''
},
html: '<button style="color: pink; font-size: 26px">v-html</button>'
},
methods: {
myClick() {
alert('点击事件')
},
clickHandler() {
this.dog
this.$set(dog, name, 'Trump')
}
}
})
</script>
</html>