Vue设计模式,发布订阅,响应式原理(简略版)

Vue

mvvm框架是什么?

mvvm框架(model-view-viewMode),本质是mvc框架的改进版,mvc框架一旦项目复杂度越来越高,代码量大,维护起来很难,尤其管理层,controller

就有了viewMOdel,有前端人员生成和维护的视图数据层,前端通过从后端获取到的model数据进行转换,封装成view层预期的数据,用来生成view层的视图数据模型

Vue设计模式

vue使用发布订阅者模式,在vue中使用observer和definereactive两个方法结合,对数据递归劫持,用watch这个类来进行监听订阅,dep用于解耦合,当数据变更后触发set方法,之后调用dep.notiify通知视图更新

发布订阅者模式

在这里插入图片描述

<!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>
    <script>
        /* 观察者 */
        class Watcher{
            constructor(){
                //用来存储事件类型和事件函数的一个对象
                // 进入超市首先推一个小推车
                this._message = {}
            }
            //消息订阅
            on(type,fn){
                // 想买方便面,我去方便面区域看看有没有想要买的牌子
                //往消息盒子当中存储事件类型与事件函数
                // 找到方便面区域了
                if(this._message[type]){
                    //第二次往后存储事件类型和事件函数
                    // 把康师傅放进小推车里
                    this._message[type].push(fn)
                }else{
                    //第一次存储事件类型与事件函数
                    this._message[type] = [fn]
                }
            }
            //发布消息
            // 结账
            emit(type,...rest){
                /* 
                    1. 先看消息盒子里面有没有事件类型,没有就弹出一句话,请先订阅
                */
               // 如果不买东西请你出去
                if(!this._message[type]) return alert("请先订阅消息")
                //遍历消息盒子,看事件类型对应的函数有没有相同的,有相同的,那么就触发
                // 收营员先把小推车里的东西一个一个倒出来
                this._message[type].forEach(item=>{
                    //如果消息盒子里面的函数与我们传入进来的函数有一样的,那么触发这个函数
                    // 倒出来的同时我们可以看看有没有不想买的,有没有想买的
                    for(let i = 0 ; i < rest.length ; i++){
                        // 我们传入进来的函数有一样的,那么触发这个函数
                        // 如果是想买的就付款这个东西
                        if(rest[i] === item){
                            //触发这个函数
                            item(i);
                        }
                    }
                })
                
            }
            //取消订阅
            // 从收银台装入自己的购物袋中
            off(type,fn){
                /* 
                    1. 先看消息盒子里面有没有事件类型,没有就弹出一句话,请先订阅
                */
               // 如果不买东西请出去
                if(!this._message[type]) return alert("请先订阅消息")
                //遍历所有的消息盒子得到的是消息盒子里面的对象的value就是每一个函数,如果其中有函数与我们传入进行的函数是一样的,那么删除这个函数
                // 还是一件一件看我们挑选好了的东西
                for(let i= 0 ; i< this._message[type].length ; i++){
                    // item函数与我们传入进行的函数是一样的,那么删除这个函数
                    // 如果这个东西是我已经付钱了,我就拿走
                    if(this._message[type][i] === fn){
                        this._message[type].splice(i,1)
                        //解决数组塌陷
                        i--
                    }
                }
            }
            //清除订阅
            // 归还购物车
            clear(type){
                /* 
                1. 先看消息盒子里面有没有事件类型,没有就弹出一句话,请先订阅
                */
               // 保安对你说 要是不买东西就出去
               if(!this._message[type]) return alert("请先订阅消息")
               //清除消息盒子里面的事件类型
               // 扔掉购物车
                delete this._message[type]
            }
        }

        //先建立两个函数
        function fn1(){
            console.log("我是函数1");
        }
        function fn2(){
            console.log("我是函数2");
        }

        let w = new Watcher();
        //消息订阅
        w.on("buy",fn1)
        w.on("buy",fn2)
        //发布消息
        w.emit("buy",fn1,fn2)
        //删除订阅
        w.off("buy",fn1)
        w.off("buy",fn2)

        //清除订阅
        w.clear("buy");
        console.log(w);
    </script>
</body>
</html>

Vue响应式原理:

数据劫持 Object.defineProperty(): 1. 只能监听对象(Object)的属性,不能监听数组的变化,无法触发push, pop, shift, unshift,splice, sort, reverse。 2. 必须遍历对象的每个属性。3. 只能劫持当前对象属性,如果想深度劫持,必须深层遍历嵌套的对象。
数据劫持 Proxy: 1. Proxy 可以直接监听对象而非属性。2. Proxy 可以直接监听数组的变化。3. Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是Object.defineProperty 不具备的。4. Proxy 返回的是一个新对象,我们可以只操作新的对象达到目的,而 Object.defineProperty 只能遍历对象属性直接修改。5. Proxy 作为新标准将受到浏览器厂商重点持续的性能优化,也就是传说中的新标准的性能红利。

请添加图片描述

<!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">
    <input id="ipt" type="text">
    <h1 id="h1"></h1>
  </div>
</body>
<script>
  // app理解成vue组件实例this
  var app = {}
  // 理解成你手动放在data选项上的数据
  var c = 0
  var name = '杨'

  // var data = {
  //   c : 0,
  //   name : '杨'
  // } 下面的逻辑就用for of 遍历

  Object.defineProperty(app, 'count', {
    get() {
      console.log('有人访问了count');
      return c
    },
    set(newVal) {
      c = newVal
      console.log('有人修改了count');
    }
  })

// 实现响应式底层原理,劫持name普通属性,将其变成一个响应式变量
  Object.defineProperty(app, 'name', {
    get() {
      console.log('有人访问了name');
      return name
    },
    set(newVal) {
      name = newVal
      console.log('有人修改了name');
      // 当有人修改响应式变量时,我们通知Watcher去操作真实DOM更新视图
      Watcher('name')
    }
  })

  // 页面初始化操作
  (function init() {
    Watcher('name')
    // 初始化事件绑定
    document.getElementById('ipt').addEventListener('input', function(e) {
      // 给input表单绑定事件
      // 当表单的值发生变化
      app.name = e.target.value
    })
  })() // 初始化自执行

  // 依赖收集(用于记录DOM结构和响应式变量之间的一对一的关系):vue源码map结构
  var deepObj = {
    // h1: 'name',
    name: ['h1','ipt'],// name: []可以是数组,在多个dom节点
  }

  // 用于更新视图(背后是DOM操作) 根据依赖收集的记录,进行更新视图
  function Watcher(key) { // key 可以换成reactive
    // 把name这个响应式变量渲染到视图结构中去
    var idArr = deepObj[key]
    document.getElementById(idArr[0]).innerText = app[key]
    document.getElementById(idArr[1]).value = app[key]
  }
  init()

</script>
</html>
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

抬头第一眼,是天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值