模拟 Vue 的构造函数——el作为 Vue 实例的挂载目标 & 数据劫持,就是把data中的成员设置为setter/getter,作为响应式数据-数据驱动视图
el——https://cn.vuejs.org/v2/api/#el
el 提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标。可以是 CSS 选择器,也可以是一个 HTMLElement 实例。
在实例挂载之后,元素可以用 vm.$el
访问。
为了模拟 Vue 的构造函数:
-
创建了Vue的构造函数Vue() ,新建文件
vue.js
中,是为了让vue访问数据更方便 -
接收一个参数,把参数存储起来 this.$options = options
-
将来处理数据和模板的关系,把data和模板$el分别存储起来
接下来:
**第一件事:**把data中的成员挂载到vue实例上 this.proxyData()
1.在proxyData()方法中,遍历所有属性
2.把每一个属性通过defineProperty()方法都挂载到vue实例上
3.给每一个属性设置get和set;使vue实例中的数据变成响应式数据
第二件事:是为了测试vue构造函数
在index.html中,
1.把之前引入的vue文件注释,引入自己写的vue.js文件,别的代码不改
<!-- <script src="./node_modules/vue/dist/vue.js"></script> -->
<script src="./MVVM/vue.js"></script>
2.打开index.html文件,在控制台打印vue实例
数据劫持,就是把data中的成员设置为setter/getter
模拟vue实例——注入
vue.js
中
// options ===> { el: '', data: {} }
function Vue(options) {
this.$options = options
this.$data = options.data || {}
// 判断el是否是字符串 选择器,否则就是dom对象
const el = options.el
// document.querySelector(el) 找到选择器 ,否则就是 DOM对象el
this.$el = typeof el === 'string' ? document.querySelector(el) : el
// 注入:就是为了把data中的成员挂载到vue实例上,并设置setter/getter
this.proxyData()
// 数据劫持,就是把data中的成员设置为setter/getter
new Observer(this.$data)
// 编译模板,就是编译模板中的差值表达式和指令
new Compiler(this)
}
//把data中的成员挂载到vue实例上
Vue.prototype.proxyData = function() {
// 1.遍历data中的所有属性 this.$data-所有属性,数组遍历-for each , 对象遍历- Object.keys(遍历目标)
Object.keys(this.$data).forEach(key => {
// 2.调用defineProperty把属性转换为getter/setter 设置到 Vue实例上 ,参数——1.this就是vue实例 2.属性-key 3.{}-设置属性的修饰符
Object.defineProperty(this, key, {
// 可遍历枚举
enumerable: true,
// 不可配置 不可删除
configurable: false,
//获取数据
get() {
console.log('vue get', key)
//属性用变量代替,取值要用[]
return this.$data[key]
},
//设置数据 value-传过来的新的值
set(value) {
//1.新旧值一样 直接return,不进行其他操作
if (value === this.$data[key]) {
return
}
//2.新旧值不一样 把传过来的新值value存起来
this.$data[key] = value
}
})
})
}
index.html
中
<body>
<!-- View -->
<div id="app">
<h1>{{ name }}</h1>
<h1>{{ age }}</h1>
<div>
<input type="text" v-model="name">
</div>
<span v-text="name"></span>
<input type="text" v-model="age">
</div>
<!-- <script src="./node_modules/vue/dist/vue.js"></script> -->
<script src="./MVVM/eventEmitter.js"></script>
<script src="./MVVM/compiler.js"></script>
<script src="./MVVM/observer.js"></script>
<script src="./MVVM/vue.js"></script>
<script>
// ViewModel
const vm = new Vue({
el: '#app',
// Model
data: {
name: 'zs',
age: 18
}
})
</script>
</body>
示例:
function Vue (options) {
// options基本结构有 ===>{el:'",data:{}}
this.$el = options.el
this.$data = options.data || {}
// 1. 数据劫持
// 当数据改变的时候,通知模板编译
for (let key in this.$data) {
Object.defineProperty(this, key, {
get () {
return this.$data[key]
},
set (value) {
if (value != this.$data[key]) {
this.$data[key] = value
// 当 set 触发,需要对外发布一个事件
}
}
})
}
// 2. 模板编译
// 订阅数据的改变,当数据改变更细 DOM
}