目录
一、data数据响应
Vue2
data数据监听 使用规则
1. 可以是任意类型
2. 对象和数组类型与js取值一致
3. 数据驱动页面 对象可以直接进行修改
4. 数组 =>
A. 直接进行修改arr[下标]进行赋值 => 并不能更新页面
B. 数组想要进行更新 需要修改原数组
c. 修改原数组js的API 都可以进行更新页面
1. 直接修改原数组 => 高级数组放 map filter
2. pop unshift shift push
3. splice reverse sort
代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.red{
height: 100px;
background: red;
}
</style>
</head>
<body>
<div id="app" >
{{name}}--{{obj.ss}}--{{arr}}
</div>
<script src="../vue.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
name:"pxr",
age:18,
bol:true,
obj:{
ss:"对象"
},
arr:[1,2,4,65]
},
})
</script>
</body>
</html>
二、监听data
vue2 响应原理
1. Vue 将遍历此对象所有的 属性
2. 并使用 Object.defineProperty 把这些 属性 全部转为 getter/setter。
补充
1. Object.defineProperty(监听对象,"对象属性",配置对象)
2. 配置对象
A. get 当你获取 监听对象属性的时候触发get函数
B. set 当你设置 监听对象属性的时候触发set函数
代码示例:
<script>
let obj = {
name:"pxr"
}
// 监听对象的变化
Object.defineProperty(obj,"name",{
get(){
console.log("获取");
},
set(){
console.log("设置");
}
})
</script>
三、代理对象
补充
1. Object.defineProperty(监听对象,"对象属性",配置对象)
2. 配置对象
A. get 当你获取 监听对象属性的时候触发get函数
B. set 当你设置 监听对象属性的时候触发set函数
3. 通过 Object.defineProperty 监听使用两个对象进行关联起来
A. 通过 Object.defineProperty 监听的对象 会为它创建对应的对象属性
B. _data.name 获取时触发get函数返回源对象数据data.name
C. _data.name 获取时触发set函数 修改了源对象的数据 data.name数据
D. _data代理对象与 data源对象 进行关联数据
总结:
vue2数据代理: 通过一个对象D:\中职通\框架进阶\vue\08-脚手架代理另外一个对象进行属性的(读写)操作
代码示例:
<script>
// 源数据
let data = { name:"pxr" }
// 代理对象
let _data = { }
// 监听对象的变化
Object.defineProperty(_data,"name",{ // 这个位置相当于给_data添加了一个name属性
get(){
//
return data.name
},
set(val){
data.name = val
}
})
</script>
四、循环代理
代码示例:
<script>
// 源数据
let data = { name: "pxr", age: 18, sex: "未知" }
// 代理对象
let _data = {}
// 监听对象的变化
function collect(_data, key, val) {
// val是一个新的变量 已经与元数据进行断开了
Object.defineProperty(_data, key, {
get() {
return val
},
set(value) {
// 设置的时候 修改的是 val
val = value
}
})
}
// 处理对象结构转化数组 通过forEach迭代 在回调函数中进行解构
Object.entries(data).forEach(([key, val]) => {
// 调用监听函数 传入代理对象 代理对象属性名 与 属性值
collect(_data, key, val)
})
// 函数形参默认是创建一个新的变量
</script>
五、数据代理完整版代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>插值符</title>
</head>
<body>
<div id="app">
{{name}}--插值符
<p >{{age}}</p>
{{sex}}
<input type="text" v-model="name">
</div>
<script>
// 监听对象的变化
function collect(_data, key, val) {
// 启动订阅者
let dev = new Dep()
Object.defineProperty(_data, key, {
get() {
if(Dep.target){
dev.addSub(Dep.target)
}
return val
},
set(value) {
if(val == value)return;
val = value
dev.notify()
}
})
}
function handlercon(data,_data) {
Object.entries(data).forEach(([key, val]) => {
collect(_data, key, val)
})
}
// vue 底层写法 => 能懂更好,,,不懂了解即可 => 更加的了解vue
class Vue {
constructor(value) {
// 获取html节点
this.$el = document.querySelector(value.el);
// 将数据放置在_data上
this._data = value.data;
// 监听数据变化
handlercon(this._data,this._data)
// 初始化虚拟DOM
this.$el.append(this.init(this.$el))
}
// 初始化
init(node) {
// 创建文本代码片段 存储虚拟DOM(在程序的内存中比较) 虚拟DOM很小
let fram = document.createDocumentFragment();
let child;
// 第一个子节点
while (child = node.firstChild) {
this.renderDOM(child)
// 插入 剪切节点功能
fram.appendChild(child)
}
return fram
}
//渲染处理的
renderDOM(node) {
switch (node.nodeType) {
// 元素节点
case 1:
[...node.attributes].forEach(item=>{
// 执行v-bind指令
if(item.nodeName == "v-model"){
// 双向绑定是通过input事件完成的
node.oninput=(ev)=>{
this._data[item.nodeValue] = ev.target.value
}
// 设置值
node.value = this._data[item.nodeValue];
// 删除不应该存在的属性
node.removeAttribute(item.nodeName)
new watcher(this._data,item.nodeValue,node)
}
})
// 插入节点
node.append(this.init(node))
break;
// 文本节点
case 3:
// 正则 Reg 用于匹配 {{}}
let Reg = /\{\{(.*)\}\}/g
// Reg.test() 正则方法 判断是否符合正则规则
if (Reg.test(node.nodeValue)) {
// 获取正则匹配的数据
let name = RegExp.$1.trim();
node.nodeValue = node.nodeValue.replace(Reg, this._data[name])
//使用观察者存储对应的数据
new watcher(this._data,name,node)
}
break;
default:
break;
}
}
}
// 订阅者 =>
class Dep{
constructor(){
this.subs = []
}
addSub(value){
this.subs.push(value)
}
notify(){
this.subs.forEach((sub)=>{
sub.update()
})
}
}
// 观察者 => 存储数据 => 查看数据变化的 然后进行更新页面的方法
class watcher{
constructor(data,name,node){
//保存数据
Dep.target = this
this.data= data
this.name= name
this.node= node
this.init()
}
init(){
this.update()
// 清除上一个this
Dep.target = null
}
update(){
this.get()
// 赋值
this.node.value = this.node.nodeValue = this.value
}
get(){
// 二次赋值
this.value = this.data[this.name]
}
}
// 实例化
let vm = new Vue({
el: "#app",
data: {
name: "111",
age: 18,
sex: "女"
}
})
</script>
</body>
</html>
六、vue3代理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
{{name}}
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
// let vm = Vue.createApp({
// data() {
// return {
// name:"66"
// }
// }
// }).mount("#app")
const dinner = {
meal: 'tacos',
name: 666
}
const handler = {
get(target, property, receiver) {
return Reflect.get(...arguments)
},
set(target, property, value, receiver) {
return Reflect.set(...arguments)
}
}
// 代理对象new Proxy(代理对象) Proxy 对象用于创建一个对象的代理
const p = new Proxy(dinner, handler)
// 改变this的指向执行 反射 => 调用函数改变this指向
</script>
</body>
</html>
七、总结
1. 这一节的内容是帮你更加的了解vue
2. 数据代理, 观察者, 订阅发布
3. data数据响应data数据监听 使用规则
1. 可以是任意类型
2. 对象和数组类型与js取值一致
3. 数据驱动页面 对象可以直接进行修改
4. 数组 =>
A. 直接进行修改arr[下标]进行赋值 => 并不能更新页面
B. 数组想要进行更新 需要修改原数组
c. 修改原数组js的API 都可以进行更新页面
1. 直接修改原数组 => 高级数组放 map filter
2. pop unshift shift push
3. splice reverse sort