实现乞丐版vue
由于工作中经常使用vue,所以对它的内部构造非常着迷,一直想探究其究竟。也看了不少文章,无奈水平所限并不能吃透、看透。所以运用目前自己所学,写了demo,本demo总共100行左右,实现v-model,v-bind,v-click等功能。
由于水平所限,本demo写的不是很规范,考虑的不是很周全,程序设计不太合理。只能实现基本的功能,作为学习的一个记录。还希望大神勿喷,欢迎批评指正。
第一次写博客,语言组织能力有待加强。
1、HTML部分
<div id="app"> <span style="display: inline-block" v-bind="num"></span> <span style="display: block" v-bind="input"></span> <span style="display: block" v-bind="test"></span> <span style="display: block" v-bind="input2"></span> <input style="display: block" type="text" v-model="input"> <input style="display: block" type="text" v-model="test"> <input style="display: block" type="text" v-model="input2"> <button @click="handleClick">click</button> </div>
2、javascript部分
<script>
function Vue (options) {
this.initValue = Object.assign({},options.data)
this.data = options.data
this.methods = options.methods
this.el = document.getElementById(options.el)
this.bindList = []
this._init(this.el)
}
Vue.prototype._init = function (d) {
this.render(d.children)
this.definedProprtyInt (this.data)
}
//遍历dom树
Vue.prototype.render =function (nodeList) {
Array.prototype.forEach.call(nodeList,(item) => {
let childNode = item.children
let len = childNode.length
//匹配v-model或者@model
let model = item.getAttribute('v-model')||item.getAttribute('@model')
let type = item.tagName.toLocaleLowerCase()
if (model) {
item.value = this.initValue[model]
this.data[model] = ""
if (type === 'input') {
item.onkeyup = function (e) {
this.data[model] = e.target.value
}.bind(this)
}
}
//匹配v-bind 并绑定相应的值
let bind = item.getAttribute('v-bind')||item.getAttribute('@bind')
if(bind && (bind in this.data)) {
//收集依赖
item.innerHTML = this.initValue[bind]
this.bindList.push({
key:bind,
d:item
})
}
//匹配v-click或者@click
let eventName = item.getAttribute('v-click')||item.getAttribute('@click')
if(eventName) {
item.onclick = function (e) {
this.methods[eventName].bind(this.data)(e)
}.bind(this)
}
if(len>0) {
this.render(childNode)
}
},this)
}
Vue.prototype.definedProprtyInt = function (o){
let _this = this
for(let key in o) {
Object.defineProperty(o,key,{
set:function (v) {
//在data中找到相应的key渲染到对应的页面上
this.bindList.forEach((item) => {
if(key == item.key) {
item.d.innerHTML = v
}
})
_this.initValue[key] = v
}.bind(this),
get:function (v) {
// console.log(_this.initValue[key])
return _this.initValue[key]
},
})
}
}
new Vue({
el:"app",
data:{
input:"input",
test:"test",
input2:"input2",
num:1
},
methods:{
handleClick:function (e) {
this.num ++
}
}
})
</script>