Vue响应式原理第一篇

本文深入探讨了响应式编程的基本概念,包括数据驱动、数据响应式和双向绑定。通过ES5的Object.defineProperty实现数据劫持,展示了如何为单个属性设置getter和setter。接着扩展到为多个属性转换getter和setter,最后介绍了ES6中使用Proxy实现响应式。此外,还讲解了发布订阅模式及其与观察者模式的区别,帮助读者理解这两种模式在实际应用中的作用。
摘要由CSDN通过智能技术生成

在这里插入图片描述

工欲善其事,必先利其器
介绍几个关于响应式原理的名词

数据驱动:开发过程中只关心数据的本身,并不需要关心如何渲染到视图上

数据响应式:.数据模型仅仅是普通的JavaScript对象,而当我们修改数据时,
视图会进行更新,避免了繁琐的DOM操作,提高开发效率

双向绑定:.数据改变,视图改变;视图改变,数据也随之改变
我们可以使用v- model在表单元素上创建双向数据绑定
ES5实现响应式
<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
        <div id="app">

        </div>
</body>
<script>
    //模拟vue里面的data数据
    let data = {
        msg:"hello world",
    };
    //模拟vue实例
    let vm = {};

    //数据劫持,当访问或者设置vm里面成员的时候,做一些干预操作
    Object.defineProperty(vm,'msg',{
        //允许遍历操作
        enumerable:true,
        //允许修改配置操作
        configurable:true,
        //当获取值的时候自动调用get方法
        get(){
            console.log('get方法执行了',data.msg);
            //默认返回data里面msg
            return data.msg
        },
        //当设置值的时候,自动执行set方法
        set(newValue){
            //逻辑判断如果新的值等于原先值则不作任何操作
            if (newValue === data.msg) {
                return
            };
            //当代码走到此处,意味着新的值并不等于当前值,在这里重新赋值
          data.msg = newValue;
          //把修改过后的值,更新到dom上面
          document.querySelector('#app').textContent =    data.msg
        }

    });
    //打印当前vm.msg,会自动调用get方法
    console.log(vm.msg)

    //设置新的值,会自动调用set方法
    vm.msg = '123';
</script>
</html>
ES5转换多个属性转换getter和setter
上面的代码仅仅是演示了单个属性转换getter和setter,

接下来为大家演示ES5为多个属性转换getter和setter,希望可以帮助到大家

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
        <div id="app">
        </div>
</body>
<script>
    //模拟vue里面的data数据
    let data = {
        msg:"hello world",
        count:10
    };
    //模拟vue实例
    let vm = {};

    //设置新的值,会自动调用set方法
 
    proxyData(data)
    function proxyData(data){
      Object.keys(data).forEach(key=>{
          Object.defineProperty(vm,key,{
              enumerable:true,
              configurable:true,
              get(){
                  return data[key]
              },
              set(newValue){
                if (newValue === data[key]) {
                    return
                };
                data[key] = newValue;
                document.querySelector('#app').textContent = data[key]
              }
          })
      })
    };
    console.log(vm)
    vm.msg = 'Spring '
</script>
</html>
ES6实现响应式
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>  
    <div id="app"></div>
</body>
<script>
    //vue3.0的数据代理通过ES6的Proxy,
    //ES6的Proxy
    //1、直接监听对象并非属性 2、由于是ES6新增的方法IE不支持,性能有浏览器优化

    //设置需要代理的数据
    let data = {
        age:20,
        name:"Loki",
        sex:"female"
    };
    
//通过vm访问代理成员

//ES6的Proxy是一个构造函数,里面可以传递两个参数

//第一个是需要代理的对象,第二个参数是一个对象,第二个参数里面的成员是

//执行代理行为的函数,当我们访问vm的时候触发get函数

//当我们设置vm里面的值的时候触发set函数

   let vm =  new Proxy(data,{
       //get方法有两个参数,作用分别是,第一个参数是代表当前的代理对象
       //第二个参数是,代理对象的key值
       get(target,key) {
           //返回当前访问的key值
           return target[key]
       },

       //set有3个参数,前两个参数分别是代表当前的代理对象,第二个参数是,代理对象的key值
       //第三个参数是新的值
       set(target,key,newValue){
           //逻辑判断是当前值是否等于新的值
            if (target[key] === newValue) {
                return
            }
            //当前值等于新的值
            target[key] = newValue;
            //把新的值渲染到dom上面
            document.querySelector('#app').textContent = target[key]
       }
   });
   //测验代码
   vm.age = 100;
</script>
</html>
发布订阅模式
<!-- 这里模拟vue的自定义事件,实现发布订阅模式具体代码请看下面  -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>发布订阅模式实现</title>
</head>
<body>
    
</body>
<script>
    //通过构造函数实现发布订阅
    class EventCenter {
        constructor(){
            //定义空对象,这里不需要使用原型,所以通过下面这种方法创建对象
            this.subs = Object.create(null);
        }
        //注册事件函数,传入两个参数一个是事件类型一个是事件的回调函数
        $on(eventType,handler){

            //例如是click事件{ click : [fun1,fun2,fun3,fun4] }一个事件对应多个方法

            //对象的数据结构,可能是同类型的事件触发多次,所以click的值数组

            //逻辑判断this.subs[eventType]的事件是否存在,如果不存在值为数组

           this.subs[eventType] = this.subs[eventType] || [];

            //把时间添加到数组里面

           this.subs[eventType].push(handler);

        }
        //触发时间函数传入一个参数,事件类型
        $emit(eventType){
            //逻辑判断是否存在事件
            if (this.subs[eventType]) {
                //如果存在事件就遍历这个数组,并执行这个数组
                this.subs[eventType].forEach(handler => {
                    handler();
                });
            }
        }
    }
    //测试代码
    let ec = new EventCenter();

    ec.$on('click',()=>{
        console.log('click1');
    });

    ec.$on('click',()=>{
        console.log('click2');
    });

    ec.$emit("click");
    
    //result => click1
    //result => click2
</script>
</html>
观察者模式

发布订阅和观察者模式的区别
观察者模式: 是由具体目标调度,比如事件触发,Dep就会去触发观察者的方法,
所以观察者模式的订阅者和发布者是存在依赖的

发布订阅模式:有统一的调度中心,因此发布和订阅不需要知道对方的存在

谢谢观看,如有不足,敬请指教

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值