1、建立一个vue类:
其constructor(options)包含
$el ---获取根对象
$option ---获取传递过来的options参数
$watchEvent --设置一个对象 保存修改更新事件
this.observe(); // 劫持事件(劫持属性-set(设置并触发watch的key更新事件) get(得值) 、 劫持方法)
this.compile(this.$el);//把view的数据和事件进行绑定(通过nodeType判断元素类型,建立Watch的实例,使用 $watchEvent 保存实该例)
2、建立一个wach类
其constructor(vm,key,node,attr,nType)包含
vm; --- vue 实例化对象 ,这里就是 app
key; --- key即绑定vm触发的属性
node; --- 绑定在某元素上的节点
attr; --- 某元素的节点上 绑定的属性名称--》如 v-html 绑定的h1对象的innerHtml
nType=nType --- 绑定的节点类型
2 、update()更新节点属性
information about Open Web technologies including HTML, CSS, and APIs for both
Web sites and HTML5 Apps. It also documents Mozilla products, like Firefox OS.">
v-model="msg">
class Vue{
constructor(options){
this.$el=document.querySelector(options.el);// 获取根对象
this.$options=options;
//this.$watchEvent[key]=[event,event,event]
this.$watchEvent={};// 设置一个对象保存修改更新事件
this.proxyData();//代理options的data
this.observe(); // 劫持事件
this.compile(this.$el);//把view的数据和事件进行绑定
}
proxyData(){// 作用 把options的data 绑定到 app实例上
for(let key in this.$options.data){
Object.defineProperty(this,key,{
configurable:false, //一般不能改, 会导致框架不稳定
enumerable:true, // 可枚举 ,框架默认为 false
// writable:true false, //属性是否可修改
// value:'设置的值',// 这里用get set 设置值
set(val){
this.$options.data[key]=val
},
get(){
return this.$options.data[key];//获取this[key]时,即返回option的data[key]
}
})
}
}
observe(){
// 劫持事件
for(let key in this.$options.data){// 1.劫持属性
let value = this.$options.data[key];//获取此处的value 保存
let that = this;
Object.defineProperty(this.$options.data,key,{
configurable:false, //一般不能改, 会导致框架不稳定
enumerable:true, // 可枚举 ,框架默认为 false
// writable:true false, //属性是否可修改
// value:'设置的值',// 这里用get set 设置值
set(val){
console.log("触发设置事件")
value=val;
if(that.$watchEvent[key]){ // 触发这个key值的更新事件
that.$watchEvent[key].forEach((watchItem,index) => {
watchItem.update();
});
}
},
get(){
console.log("触发获取内容事件")
return value;//获取this[key]时,即返回option的data[key]
}
})
}
/*
for(let key in this.$options.methods){//2.劫持方法
console.log('dddddfff',key)
let value = this.$options.methods[key];//获取此处的value 保存
console.log('dddddfff',value)
let that = this;
Object.defineProperty(this.$options.methods,key,{
configurable:false, //一般不能改, 会导致框架不稳定
enumerable:true, // 可枚举 ,框架默认为 false
// writable:true false, //属性是否可修改
// value:'设置的值',// 这里用get set 设置值
set(val){
console.log("触发设置方法 事件")
value=val;
if(that.$watchEvent[key]){ // 触发这个key值的更新事件
that.$watchEvent[key].forEach((watchItem,index) => {
watchItem.update();
});
}
},
get(){
console.log("触发获取方法 事件")
return value;//获取this[key]时,即返回option的data[key]
}
})
}
*/
}
compile(cNode){// 把view的数据和事件进行绑定
console.log([this.$el])
cNode.childNodes.forEach((node,index)=>{
if(node.nodeType==1){ //元素类型
if(node.hasAttribute('v-html')){
let vmKey=node.getAttribute('v-html').trim();
if(this.hasOwnProperty(vmKey)){
node.innerHTML=this[vmKey];
let watcher = new Watch(this,vmKey,node,'innerHTML')
if(this.$watchEvent[vmKey]){
this.$watchEvent[vmKey].push(watcher)
}else{
this.$watchEvent[vmKey]=[]
this.$watchEvent[vmKey].push(watcher)
}
// 删除节点事件
node.removeAttribute('v-html')
}
}
// 是否存在v-model
if(node.hasAttribute('v-model')){
let vmKey=node.getAttribute('v-model').trim();
console.log(vmKey)
if(this.hasOwnProperty(vmKey)){
node.value=this[vmKey];
let watcher = new Watch(this,vmKey,node,'value')
if(this.$watchEvent[vmKey]){
this.$watchEvent[vmKey].push(watcher)
}else{
this.$watchEvent[vmKey]=[]
this.$watchEvent[vmKey].push(watcher)
}
node.addEventListener('input',(event)=>{
this[vmKey]=node.value
})
// 删除节点事件
node.removeAttribute('v-model')
}
}
//是否存在@click
if(node.hasAttribute('@click')){
let vmKey=node.getAttribute('@click').trim();// 把方法拿到
node.addEventListener('click',(event)=>{
this.eventFn=this.$options.methods[vmKey].bind(this)
this.eventFn(event)
})
}
if(node.childNodes.length>0){
this.compile(node)
}
}
if(node.nodeType==3){//文本类型
let reg=/\{\{(.*?)\}\}/g;
let text = node.textContent;
node.textContent=text.replace(reg,(match,vmKey)=>{
vmKey=vmKey.trim();
if(this.hasOwnProperty(vmKey)){
node.value=this[vmKey];
let watcher = new Watch(this,vmKey,node,'textContent')
if(this.$watchEvent[vmKey]){
this.$watchEvent[vmKey].push(watcher)
}else{
this.$watchEvent[vmKey]=[]
this.$watchEvent[vmKey].push(watcher)
}
}
return this[vmKey]
})
}
})
}
}
class Watch{
constructor(vm,key,node,attr,nType){
this.vm=vm; // vue 实例化对象 ,这里就是 app
this.key=key; // key即绑定vm触发的属性
this.node=node; // 绑定在某元素上的节点
this.attr=attr; // 某元素的节点上 绑定的属性名称--》如 v-html 绑定的h1对象的innerHtml
// this.nType=nType // 绑定的节点类型
}
update(){
this.node[this.attr]=this.vm[this.key]
}
}
let options = {
el:'#app',
data:{
msg:'nihao',
username:"xiaowen"
},
methods: {
changeEvent() {
this.msg="hello ni"
},
changeEvent2() {
this.msg="hello niooooooo"
},
},
}
let app=new Vue(options);
// app.msg == options.data.msg;
// app.msg='abc'
// options.data.msg='abc'
console.log(app)