VUE---5.数据代理

目录

一、data数据响应

二、监听data

三、代理对象

四、循环代理

五、数据代理完整版代码示例

六、vue3代理

七、总结


一、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

       

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值