<div id="app">
<input type="text" id="origin" @change="changeInput" v-model="text">
<span id="output">{{text}}</span>
</div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data () {
return {
text: '333'
}
},
methods: {
changeInput (event) {
console.log(this, event, 'event')
}
}
})
</script>
vue.js
//收集依赖
class Dep {
static target = null
constructor() {
this.childDeps = []
}
add (childDep) {
const nodes = this.childDeps.map(child => child.node)
if (!nodes.includes(childDep.node)) {
this.childDeps.push(childDep)
}
}
notify () {
this.childDeps.map(child => {
child.update()
})
}
}
//订阅器
class Watcher {
constructor (vm, node, key) {
this.vm = vm
this.node = node
this.key = key
this.update()
}
get () {
Dep.target = this
this.value = this.vm._data[this.key]
Dep.target = null
}
update () {
this.get()
this.node.innerText = this.value
}
}
// vue
class Vue {
constructor(options) {
this.$options = options
//初始化data
if (this.$options.data) {
this._data = this.initData()
this.observe(this._data)
}
//初始化methods
if (this.$options.methods) {
this.$methods = this.$options.methods
this.proxyData(this.$methods)
}
if (this.$options.el) {
//获取dom节点并添加到文档碎片中
let domNode = document.querySelector(this.$options.el)
this.$el = this.createFragment(domNode)
//插入真实节点中
document.querySelector(this.$options.el).appendChild(this.$el)
}
}
//初始化获取data参数
initData () {
let data = {}
if (typeof this.$options.data === 'function') {
data = this.$options.data()
if (typeof data !== 'object') {
console.error('data must be a object')
}
}
return data
}
//将深层的数据代理到this上,可以用this.xx直接访问
proxyData (data) {
Object.keys(data).map(key => {
Object.defineProperty(this, key, {
get () {
return data[key]
},
set (newVal) {
data[key] = newVal
}
})
})
}
//创建一个文档碎片
createFragment (node) {
let fragment = document.createDocumentFragment()
let childNode
while (childNode = node.firstChild) {
this.compileNode(childNode)
fragment.appendChild(childNode)
childNode = node.firstChild
}
return fragment
}
//编译节点 将上面的属性解析
compileNode (node) {
const reg = /\{\{(\S*)\}\}/
const regEventType = /(@|v-bind:|v-on:)(\S+)/
//如果是元素节点
if (node.nodeType === 1) {
let attributes = [...node.attributes]
attributes.map(attr => {
if (attr.nodeName === 'v-model') {
const key = attr.nodeValue //获取双向绑定的值
node.addEventListener('keyup', (event) => {
this._data[key] = event.target.value
})
node.value = this._data[key]
node.removeAttribute('v-model')
}
if (regEventType.test(attr.nodeName)) {
const eventType = RegExp.$2
const eventName = attr.nodeValue
node.addEventListener(eventType, () => {
this[eventName].call(this, event)
})
}
})
if (reg.test(node.innerText)) {
const key = RegExp.$1 //获取双向绑定的值
//添加订阅
new Watcher(this, node, key)
}
} else if (node.nodeType === 3) { //文本节点
if (reg.test(node.nodeValue)) {
const key = RegExp.$1 //获取双向绑定的值
//添加订阅
new Watcher(this, node, key)
}
}
}
//给data内的属性添加响应式
observe (data) {
if (typeof data !== 'object' || data === null) {
return
}
Object.keys(data).map(key => {
this.defineReactive(data, key, data[key])
this.observe(data[key])
})
}
//动态监控对象
defineReactive (obj, key, value) {
let dep = new Dep()
Object.defineProperty(obj, key, {
get () {
//收集依赖
if (Dep.target) {
dep.add(Dep.target)
}
return value
},
set (newVal) {
if (newVal === value) return
value = newVal
//数据发生改变通知dom更新 发布
dep.notify()
}
})
}
}