https://cn.vuejs.org/v2/guide/reactivity.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<!-- 生产环境版本,优化了尺寸和速度 -->
<!-- <script src="https://cdn.jsdelivr.net/npm/vue@2"></script> -->
</head>
<body>
<div id="app">
<input type="text" v-model="msg" name="" id="">
<h1>{{msg}}</h1>
<h1 v-html="msg"></h1>
<button type="button" @click="changeEvent">修改msg <span></span></button>
</div>
<script>
class Vue{
constructor(options){
this.$el = document.querySelector(options.el);
//数据创造前
if(typeof options.beforeCreate == 'function'){
options.beforeCreate.bind(this)();
}
this.$options = options;
//设置一个对象专门保存修改更新的事件
this.$watchEvent = {};
//代理options的data数据
this.proxyData();
//观察者,劫持设置事件
this.watchData();
//数据创造后
if(typeof options.created == 'function'){
options.created.bind(this)();
}
//挂载前
if(typeof options.beforeMount == 'function'){
options.beforeMount.bind(this)();
}
//dom处理,把view的数据和事件进行绑定
this.compile(this.$el);
//挂载后
if(typeof options.mounted == 'function'){
options.mounted.bind(this)();
}
}
compile(cNode){
console.log([this.$el]);
cNode.childNodes.forEach((element,index) => {
if(element.nodeType == 1){//元素
if(element.hasAttribute('v-html')){
let mkey = element.getAttribute('v-html').trim();
// console.log(element.innerHTML);
// console.log(this[mkey]);
if(this.hasOwnProperty(mkey)){
element.innerHTML = this[mkey];
let watch = new Watch(this,mkey,element,'innerHTML',element.nodeType);
if(this.$watchEvent[mkey]){
this.$watchEvent[mkey].push(watch);
}else{
this.$watchEvent[mkey] = [];
this.$watchEvent[mkey].push(watch);
}
element.removeAttribute('v-html');
}
}
if(element.hasAttribute('v-model')){
let mkey = element.getAttribute('v-model').trim();
if(this.hasOwnProperty(mkey)){
element.value = this[mkey];
let watch = new Watch(this,mkey,element,'value',element.nodeType);
if(this.$watchEvent[mkey]){
this.$watchEvent[mkey].push(watch);
}else{
this.$watchEvent[mkey] = [];
this.$watchEvent[mkey].push(watch);
}
element.removeAttribute('v-model');
}
element.addEventListener('input',(event)=>{
this[mkey] = element.value;
})
}
if(element.hasAttribute('@click')){
let mkey = element.getAttribute('@click').trim();
if(this.$options.methods.hasOwnProperty(mkey)){
element.addEventListener('click',(event)=>{
// ???????????????????????这里的bing要多了解下。
// this.$options.methods[mkey](event);
this.eventTmp = this.$options.methods[mkey].bind(this);
// this[mkey]();
this.eventTmp(event);
})
}
}
if(element.childNodes.length>0){
this.compile(element);
}
}else if(element.nodeType == 3){//文本
// console.log('3',[element]);
let reg = /\{\{(.*)\}\}/
let text = element.textContent;
// console.log(text);
element.textContent = text.replace(reg,(mvalue,mkey)=>{
mkey = mkey.trim();
if(this.hasOwnProperty(mkey)){
// element.value = this[mkey];
let watch = new Watch(this,mkey,element,'textContent',element.nodeType);
if(this.$watchEvent[mkey]){
this.$watchEvent[mkey].push(watch);
}else{
this.$watchEvent[mkey] = [];
this.$watchEvent[mkey].push(watch);
}
// element.removeAttribute('v-model');
}
return this[mkey];
});
}
});
}
//劫持
watchData(){
for(let key in this.$options.data){
let value = this.$options.data[key];
let that = this;
Object.defineProperty(this.$options.data,key,{
configurable:false,
enumerable:true,
get(){
return value;
},
set(val){
value = val;
if(that.$watchEvent.hasOwnProperty(key)){
//更新前
if(typeof options.beforeUpdate == 'function'){
options.beforeUpdate.bind(this)();
}
for(let wkey in that.$watchEvent[key]){
that.$watchEvent[key][wkey].update();
}
//更新后
if(typeof options.updated == 'function'){
options.updated.bind(this)();
}
}
}
});
}
}
//代理
proxyData(){
for(let key in this.$options.data){
Object.defineProperty(this,key,{
configurable:false,
enumerable:true,
get(){
return this.$options.data[key];
},
set(val){
this.$options.data[key] = val;
}
});
}
}
}
class Watch{
constructor(vm,mKey,mNode,attr,type){
//vm 实例化的app对象
this.vm = vm;
//绑定触发的属性
this.mKey = mKey;
//vm[key]数据绑定的html节点
this.mNode = mNode;
//html节点的属性名称
this.attr = attr;
//节点类型
this.type = type;
}
update(){
// console.log(this.mNode,this.attr,this.vm,this.mKey);
this.mNode[this.attr] = this.vm[this.mKey];
}
}
</script>
<script>
let options = {
el:"#app",
data:{
msg:"hello 111",
username:"小刘",
},
methods:{
changeEvent:function(){
console.log("changeEventchangeEvent");
this.msg = "fjdsklf";
}
},
beforeCreate(){
console.log('创建前');
},
created(){
console.log('创建后');
},
beforeMount(){
console.log('——————挂载前');
},
mounted(){
console.log('——————挂载后');
},
beforeUpdate(){
console.log('——————————————更新前');
},
updated(){
console.log('——————————————更新后');
},
}
let app = new Vue(options);
console.log(app);
// var app = new Vue({
// el:"#app",
// data:{
// msg:"hello 111",
// username:"小刘",
// },
// methods:{
// changeEvent:function(){
// this.msg = "fjdsklf";
// }
// }
// })
</script>
</body>
</html>