class Vue {
constructor(options = {}) {
this.$el = document.querySelector(options.el)
let data = this.data = options.data
Object.keys(data).forEach(key => {
this.proxyData(key)
})
this.methods = options.methods
this.watcherTask = {}
this.instrList = {}
this.observer(data)
this.compile(this.$el)
}
proxyData(key) {
let that = this
Object.defineProperty(this, key, {
configurable: false,
enumerable: true,
get: () => {
return this.data[key]
},
set: (newValue) => {
return that.data[key] = newValue;
}
})
}
observer(data) {
let that = this
Object.keys(data).forEach(ele => {
let value = data[ele]
this.watcherTask[ele] = []
Object.defineProperty(data, ele, {
configurable: false,
enumerable: true,
get: () => {
return value
},
set: (newValue) => {
if (newValue !== value) {
value = newValue
that.watcherTask[ele].forEach(result => {
result.update()
})
}
}
})
})
}
compile(el) {
let nodes = el.childNodes
for (let i = 0; i < nodes.length; i++) {
let node = nodes[i]
if (node.nodeType === 3) {
let text = node.textContent.trim()
if (!text) continue
this.compileText(node, 'textContent')
} else if (node.nodeType === 1) {
if (node.childNodes.length > 0) {
this.compile(node)
}
if (node.hasAttribute('v-model') && node.tagName === "INPUT" || node.tagName === "TEXTARER") {
node.addEventListener('input', (() => {
let attrVal = node.getAttribute('v-model')
this.watcherTask[attrVal].push(new Watcher(node, this, attrVal, 'value'))
node.removeAttribute('v-model')
return () => {
this.data[attrVal] = node.value
}
})())
}
if (node.hasAttribute('v-html')) {
let attrNewVal = node.getAttribute('v-html')
this.watcherTask[attrNewVal].push(new Watcher(node, this, attrNewVal, 'innerHTML'))
node.removeAttribute('v-html')
}
this.compileText(node, 'innerHTML')
if (node.hasAttribute('@click')) {
let getbtnClick = node.getAttribute('@click')
node.removeAttribute('@click')
node.addEventListener('click', e => {
this.methods[getbtnClick] && this.methods[getbtnClick].bind(this)()
})
}
if (node.hasAttribute('v-if')) {
let newValue = this.data[node.getAttribute('v-if')]
if (!newValue) {
el.removeChild(node)
}
node.removeAttribute('v-if')
}
if (node.hasAttribute('v-show')) {
let newValue = this.data[node.getAttribute('v-show')]
if (!newValue) {
node.style.cssText = "display:none"
}
node.removeAttribute('v-show')
}
}
}
}
compileText(node, type) {
let reg = /\{\{(.*?)\}\}/g
let txt = node.textContent
if (reg.test(txt)) {
node.textContent = txt.replace(reg, (matched, value) => {
let newValue = value.trim()
let tlp = this.watcherTask[newValue] || []
tlp.push(new Watcher(node, this, newValue, type))
if (newValue.split('.').length > 0) {
let v = null
newValue.split('.').forEach((val, i) => {
v = !v ? this[val] : v[val]
})
return v
} else {
return this[val]
}
})
}
}
}
class Watcher {
constructor(el, vm, value, type) {
this.el = el
this.vm = vm
this.value = value
this.type = type
this.update()
}
update() {
this.el[this.type] = this.vm.data[this.value]
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
</style>
</head>
<body>
<div id="box">
<span>{{massage}}</span>
<input type="text" v-model="someText">
<button @click='btnClick'>点击事件</button>
<div>{{someText}}</div>
<div v-if="condition" class="class1">{{someText}}</div>
<div v-if="condition1" class="class2">
<span>{{someText}}</span>
<span>eqewe</span>
</div>
<div v-if="condition2" class="class3">{{someText}}</div>
<div v-if="condition3" class="class4">{{someText}}</div>
<div v-show="show">{{someText}}</div>
<div v-if="heddin">{{someText}}</div>
</div>
<script src="./index.js"></script>
<script>
new Vue({
el:'#box',
data:{
massage:"张三",
someText:'',
condition: false,
condition3:false,
condition2:true,
condition1:false,
show:false,
heddin:true
},
methods: {
btnClick(){
this.massage = 'qqqqqqqqqqqqqqqq'
}
},
})
</script>
</body>
</html>