// 遍历data里面的数据
function observe(obj, vm) {
Object.keys(obj).forEach(function (key) {
// console.log(vm);// 实例
// console.log(obj);//data对象
// console.log(key);// 里面的key值
//给函数传入 这三个
defineReactive(vm, key, obj[key]);
});
}
function defineReactive(obj, key, val) {
// 实例 data对象 key值
var dep = new Dep();
// 响应式的数据绑定 通过对象方法访问 text 这个属性
Object.defineProperty(obj, key, {
// 读取属性时调用
get: function () {
// 添加订阅者watcher到主题对象Dep
if (Dep.target) {
// 获取属性的时候就 触发把他添加进去
console.log(Dep.target);
dep.addSub(Dep.target);
}
return val;
},
// 写入属性时调用
set: function (newVal) {
if (newVal === val) {
return;
} else {
val = newVal;
// 作为发布者发出通知
// 写入的时候
dep.notify()
}
}
});
}
function nodeToFragment(node, vm) {
// node => 挂载点 vm => 调用对象Vue
// 创建fragment 虚拟节点 这个也是虚拟dom的雏形
var flag = document.createDocumentFragment();
var child;
// node.firstChild 挂载点下面所有节点
while (child = node.firstChild) {
// 执行函数 判断 是什么类型的
compile(child, vm);
flag.appendChild(child); // 将子节点劫持到文档片段中
}
return flag;
}
function compile(node, vm) {
// node => 虚拟节点 vm => 调用对象Vue
var reg = /\{\{(.*)\}\}/;
// 节点类型为元素
if (node.nodeType === 1) {
//获取这些元素的属性 v-model
var attr = node.attributes;
// 解析属性
for (var i = 0; i < attr.length; i++) {
if (attr[i].nodeName == 'v-model') {
// 获取v-model绑定的属性名
var name = attr[i].nodeValue;
console.log(vm[name])
node.addEventListener('input', function (e) {
// 给相应的data属性赋值,进而触发属性的set方法
vm[name] = e.target.value;
})
// 属性名 和data里面绑定的key相同 就把 data对象里面的值 赋值给input
node.value = vm[name];
node.removeAttribute('v-model');
}
}
}
// 节点类型为text
if (node.nodeType === 3) {
if (reg.test(node.nodeValue)) {
var name = RegExp.$1; // 获取匹配到的字符串
name = name.trim();// 去头尾空格
// console.log(vm);// Vue 对象
// console.log(node);// 文本内容
// console.log(name);// {{ 里面的东西 }}
node.nodeValue = vm[name]; // 将data的值赋值给该node
new Watcher(vm, node, name);
// 遍历了 虚拟dom里面的文本节点 如果 和Vue data里面的 就给他赋值
}
}
}
function Watcher(vm, node, name) {
// console.log(vm);// Vue 对象
// console.log(node);// 文本内容
// console.log(name);// {{ 里面的东西 }}
Dep.target = this;
this.name = name;
this.node = node;
this.vm = vm;
// 调用方法
this.update();
Dep.target = null;
}
Watcher.prototype = {
update: function () {
//提交一个update时间
this.get();
console.log(this.node.nodeValue);
this.node.nodeValue = this.value;
},
// 获取data中的属性值
get: function () {
console.log(this.vm[this.name]); // data[text] {{ text }}
this.value = this.vm[this.name]; // 触发相应属性的get
}
}
// 创建一个发布者 连接他们两个
function Dep () {
this.subs = [];
}
//
Dep.prototype = {
addSub: function (sub) {
this.subs.push(sub);
},
notify: function () {
this.subs.forEach(function (sub) {
sub.update();
});
}
}
function Vue(options) {
this.data = options.data;
var data = this.data;
//调用 出穿入实参 data 和当前这个调用对象
observe(data, this);
// 传入挂载点
var id = options.el;
var dom = nodeToFragment(document.getElementById(id), this);
// 编译完成后,将dom返回到app中。
document.getElementById(id).appendChild(dom);
}
//实例
var vm = new Vue({
el: 'app',
data: {
text: 'hello world',
a:'nishi'
}
});