首页 > 其他分享 >2.2、MVVM及数据代理

2.2、MVVM及数据代理

时间:2024-12-10 19:57:27浏览次数:5  
标签:Vue name MVVM vm 代理 2.2 setter data 属性

2.3.1 MVVM分层思想

1. MVVM是什么?

M:Model(模型/数据)

V:View(视图)

VM:ViewModel(视图模型):VM是MVVM中的核心部分。(它起到一个核心的非常重要的作用。)

MVVM是目前前端开发领域当中非常流行的开发思想。(一种架构模式。)

目前前端的大部分主流框架都实现了这个MVVM思想,例如Vue,React等。

2. Vue框架遵循MVVM吗?

虽然没有完全遵循 MVVM 模型,但是 Vue 的设计也受到了它的启发。

Vue框架基本上也是符合MVVM思想的。

3. MVVM模型当中倡导了Model和View进行了分离,为什么要分离?

假如Model和View不分离,使用最原始的原生的javascript代码写项目:

如果数据发生任意的改动,接下来我们需要编写大篇幅的操作DOM元素的JS代码。

将Model和View分离之后,出现了一个VM核心,这个VM把所有的脏活累活给做了,

也就是说,当Model发生改变之后,VM自动去更新View。当View发生改动之后,

VM自动去更新Model。我们再也不需要编写操作DOM的JS代码了。开发效率提高了很多。

<body>
  <!-- 准备容器 -->
  <!-- View V-->
  <div id="app">
    姓名:<input type="text" v-model="name">
  </div>

  <!-- vue程序 -->
  <script>
    // ViewModel  VM
    const vm = new Vue({
      el : '#app',
      // Model  M
      data : {
        name : 'zhangsan'
      }
    })
  </script>
</body>

2.3.2、vm可以访问哪些属性

通过Vue实例都可以访问哪些属性?(通过vm都可以vm. 什么。)

  1. Vue实例中的属性很多,有的以 $ 开始,有的以 _ 开始。
    1. 所有以 $ 开始的属性,可以看做是公开的属性,这些属性是供程序员使用的。
    2. 所有以 _ 开始的属性,可以看做是私有的属性,这些属性是Vue框架底层使用的。一般我们程序员很少使用。
  1. 通过vm也可以访问Vue实例对象的原型对象上的属性,例如:vm.$delete...
  <body>
    <div id="app">
      <h1>{{msg}}</h1>
    </div>
    <script>
      let dataObj = {
        msg: "Hello Vue!",
      };

      const vm = new Vue({
        el: "#app",
        data: dataObj,
      });

      // 按说msg是dataObj对象的属性。
      console.log("dataObj的msg", dataObj.msg);

      // msg属性也可以通过vm来访问呢?
      // 这是因为Vue框架底层使用了数据代理机制。
      // 要想搞明白数据代理机制,必须有一个基础知识点要学会:Object.defineProperty()。
      // console.log("vm的msg", vm.msg);

      // 模拟Vue构造函数,无法直接用newVm.msg打印出
      // function myVue(obj) {
      //   return obj
      // }
      // let newVm = new myVue({
      //   el: "#app",
      //   data: dataObj,
      // });
      // console.log(newVm.data.msg);
    </script>
  </body>

2.3.3、object.defineProperty()

1. 这个方法是ES5新增的。

2. 这个方法的作用是:给对象新增属性,或者设置对象原有的属性。

3. 怎么用?

Object.defineProperty(给哪个对象新增属性, '新增的这个属性名叫啥', {给新增的属性设置相关的配置项key:value对})

4. 第三个参数是属性相关的配置项,配置项都有哪些?每个配置项的作用是啥?

  • value 配置项:给属性指定值
  • writable 配置项:设置该属性的值是否可以被修改。true表示可以修改。false表示不能修改。
  • enumerable 配置项:设置该属性是否可以被遍历。
    • true表示该属性是可以遍历的。(可枚举的,可迭代的。)
    • false表示该属性是不可遍历的。
  • configurable 配置项:设置该属性是否被删除。
    • true表示该属性是可以被删除的。
    • false表示该属性不可以被删除
  • getter方法 配置项:不需要我们手动调用的。当读取属性值的时候,getter方法被自动调用。

getter方法的返回值非常重要,这个返回值就代表读取的这个属性它的值。

  • setter方法 配置项:不需要我们手动调用的。当修改属性值的时候,setter方法被自动调用。

setter方法上是有一个参数的,这个参数可以接收传过来的值。

注意:当配置项当中有setter和getter的时候,value和writable配置项都不能存在。

 <body>
    <script>
      // 这是一个普通的对象
      let person = {};
      // 临时变量   
      let temp;
      // 给上面的phone对象新增一个color属性
      Object.defineProperty(person, "name", {
        //value : '章三',
        //writable : true,
        enumerable: false,
        // true表示该属性是可以遍历的。(可枚举的,可迭代的。)
        // false表示该属性是不可遍历的。

        configurable: false,
        // true表示该属性是可以被删除的。
        // false表示该属性是不可以被删除的。
        
        // getter方法配置项
        get: function () {
          console.log("getter方法执行了@@@");
          //return '动态'
          //return this.name  //递归,死循环
          return temp;
        },
        // setter方法配置项
        set: function (val) {
          console.log("setter方法执行了@@@", val);
          //this.name = val  //递归,死循环
          temp = val;
        },
      });
    </script>
  </body>

2.3.4、数据代理机制

通过访问 代理对象的属性 来间接访问 目标对象的属性。数据代理机制的实现需要依靠:Object.defineProperty()方法。

注意:代理对象新增的这个属性的名字 和 目标对象的属性名要一致,这样我们访问代理对象属性,就像在访问目标对象的属性一样

  <script>
      // 目标对象
      let target = {
        name: "zhangsan",
      };
      // 代理对象
      let proxy = {};
      // 如果要实现数据代理机制的话,就需要给proxy新增一个name属性。
      Object.defineProperty(proxy, "name", {
        get() {
          console.log("getter方法执行了@@@@");
          // 间接访问目标对象的属性
          return target.name;
        },
        set(val) {
          target.name = val;
        },
      });
    </script>

2.3.5、数据代理时对属性名的要求

1. Vue实例不会给以_和$开始的属性名做数据代理。

2. 为什么?

如果允许给_或$开始的属性名做数据代理的话。 vm这个Vue实例上可能会出现_xxx或$xxx属性, 而这个属性名可能会和Vue框架自身的属性名冲突。

3. 在Vue当中,给data对象的属性名命名的时候,不能以_或$开始。

<body>
    <!-- 容器 -->
    <div id="app">
      <h1>{{msg}}</h1>
    </div>
    <!-- vue程序 -->
    <script>
      const vm = new Vue({
        el: "#app",
        data: {
          msg: "Hello Vue!",
          _name: "zhangsan", //不会做数据代码,vm上看不到
          $age: 20,//不会做数据代码,vm上看不到
        },
      });
    </script>
  </body>

2.3.6、模拟实现数据代理

简单实现myvm.name==options.data.name

  <script>
      const myvm = new MyVue({
        data: {
          msg: "Hello Vue!",
          name: "jackson",
          age: 30,
        },
      });
    </script>

数据代理js

// 实现数据代理,目的是读取  myvm.name == options.data.name
// 定义一个Vue类
class MyVue {
  // 定义构造函数
  // options 是一个对象{}
  // options对象中有一个data配置项
  constructor(options) {
    Object.keys(options.data).forEach((propertyName, index) => {
      Object.defineProperty(this, propertyName, {
        get() {
          // 读取对象的属性值 对象[变量]
          return options.data[propertyName];
        },
        set(val) {
          options.data[propertyName] = val;
        },
      });
    });
  }
}

2.3.7、Vue中的数据代理与数据劫持

在vm身上,有两个属性$data,_data,这两个属性都指向Vue底层的真实的data对象,

通过$data,_data获取各属性值,是不会走数据代理机制的

其中:_data是框架内部使用的,可以看做是私有的

$data,这是Vue框架对外公开的一个属性

也就是说Vue框架会将data中的数据实时通过Object.defineProperty拷贝一份放在$data以及_data身上,供vm去使用

1、Vue的数据代理
(1)、基本阐述

vue将_data中的所有数据属性通过Object.defineProperty添加到vm实例上,并且提供了getter和setter方法,于是通过vm直接获取数据的时候就调用getter,获取_data中的值,当修改的时候调用setter修改_data中的值

(2)数据代理有什么用呢?

既然vm上挂的属性就是_data中的数据代理,那么{{vm._data.name}}和{{name}}是等价的,{{vm_data.name='szk2'}}和{{name='szk2'}}也是等价的

所以就是为了写代码的方便,在{{}}直接写数据,或者直接修改就能操作到_data中

2、数据劫持

数据劫持就是将vue代码里我们写的data加工了一下,变成_data,让每个属性有了getter和setter

vue通过监听者observer来监听data中的数据,这个getter和setter就是监听者里面的方法,getter就是监听者获取data中数据的,setter则是监听当数据发生变化的时候执行操作的,当修改属性的时候,setter被调用,在setter方法中就会让订阅者执行重新解析模板的操作,从而改变了页面

先看看我们写的data和加工之后的data有什么区别

代码实现

劫持一层数据结构的数据

//创建一个监视的实例对象,用于监视data中属性的变化
const obs = new Observer(data)		
console.log(obs)	

//准备一个vm实例对象
let vm = {}
vm._data = data = obs
//下面的方法只能解析一层解构,多层数据结构需要用到递归
function Observer(obj){
  //汇总对象中所有的属性形成一个数组
  const keys = Object.keys(obj)
  //遍历
  keys.forEach((k)=>{
    Object.defineProperty(this,k,{
      get(){
        return obj[k]
      },
      set(val){
        console.log(`${k}被改了,我要去解析模板,生成虚拟DOM.....我要开始忙了`)
        obj[k] = val
      }
    })
  })
}

劫持多层数据结构的数据


observer(data)

function observer(target) {
   if (typeof target !== 'object' || !target) {
       return target
   }
   for (const key in target) {
       if (target.hasOwnProperty(key)) {
           const value = target[key]
           observerObject(target, key, value)
       }
   }
}

function observerObject(target, name, value) {
   if (typeof value === 'object' || Array.isArray(target)) {
       observer(value);
   }
   Object.defineProperty(target, name, {
       get() {
           return value
       },
       set(newVal) {
           if (newVal !== value) {
               if (typeof value === 'object' || Array.isArray(value)) {
                   observer(value)
               }
               value = newVal
           }
           renderView() //模拟视图渲染操作
       }
   })
}

3、总结
数据劫持:
创建Vue实例vm,vm身上会有_data属性,_data通过劫持data配置项,再通过defineProperty的getter和setter,得到的响应式的数据。把vue中的data数据拦截改写成具有getter和setter形式的_data,就是数据劫持。
数据代理
vm中_data中的数据又通过数据代理(也是通过defineProperty的getter和setter实现),放置到vm身上,vm可以通过getter方法,setter方法直接使用_data中的数据,方便书写数据
步骤:
1-把vue实例中的data,通过Object.defineProperty的setter和getter进行数据劫持,使得data改写为到_data(使得数据改写为响应式的数据,具有getter和setter);
2-通过vm进行数据代理,代理_data

标签:Vue,name,MVVM,vm,代理,2.2,setter,data,属性
From: https://blog.csdn.net/qq_60060362/article/details/144369935

相关文章

  • TikTok代理IP:如何帮助解决限流、封号问题?
    在当今的社交媒体领域,TikTok仍然是“当红”平台。然而,许多用户在使用TikTok的过程中,常常会遇到限流和封号的问题,比如视频零播放,带来了极大的困扰。这些限流和封号问题的出现,引发了用户对解决方法的强烈关注。那么可以通过哪些有效的途径,来恢复账号的正常状态呢?一、TikTok......
  • 做了反向代理和负载均衡的nginx配置文件简单示例(nginx.conf) HTTP负载均衡/TCP负载均
    在默认配置的基础上,启用http反向代理和负载均衡。同时配置了TCP反向代理和负载均衡。另外,能够实现每天生成一个日志文件,日志用json格式,日志中的日期重新格式化成yyyy-MM-ddTHH:mm:ss.ZZZ这样子。nginx.conf#usernobody;worker_processes1;#error_loglogs/error......
  • Linux下Mosquitto MQTT代理的安装与配置指南
    1.引言MQTT(MessageQueuingTelemetryTransport)是一种轻量级的、基于发布/订阅模式的消息传输协议,广泛应用于物联网(IoT)领域。Mosquitto是一个开源的MQTT代理,它支持MQTT协议3.1和3.1.1,适用于各种设备和平台。本文将详细介绍如何在Linux系统下安装和配置MosquittoMQTT代理。......
  • 使用Squid作为反向代理,并进行流量限制
    前言Squid是一个比较老的网络转发工具,功能类似于Nginx或者HAProxy(个人理解)。之所以尝试了Squid是因为Squid原生支持delay_pools可以用来做流控。正文目的有一个后端服务部署在本机http://localhost:10000,需要对该服务做一个带宽限制,所有用户访问的带宽总和为1MB/s。Squid安......
  • 动态代理详解
    动态代理详解1、什么是代理模式  代理模式引用官方原文话来讲:代理模式通过引入一个代理对象来控制对原对象的访问。代理对象在客户端和目标对象之间充当中介,负责将客户端的请求转发给目标对象,同时可以在转发请求前后进行额外的处理。转化为生活中例子来讲(代购/秘书等),我们需要......
  • ubuntu24.04挂载2.2T以上硬盘,实现开启挂载
    1、su进入root用户,输入密码。2、查看现有硬盘使用情况,可以发现数据硬盘暂未挂载到目录。df-hFilesystemSizeUsedAvailUse%Mountedonudev63G063G0%/devtmpfs13G1.2M13G1%/run/dev/vda140G5.3G32G......
  • 什么是反向代理?作用、原理和实例详解
    ......
  • 【Basic Abstract Algebra】Exercises for Section 2.2 — Subgroups
    Let\(H\)beasubgroupof\(G\),if\(g\inG\),showtha\[gHg^{-1}=\{g^{-1}hg\midh\inH\}\]isalsoasubgroupof\(G\).Proof:Since\(e~(\text{identity})\ingHg^{-1}\subseteqG\),\(gHg^{-1}\)isnonempty.Forany\(g^{-1}h_1g,......
  • 上周热点回顾(12.2-12.8)
    热点随笔:· 网站刚上线,就被DDoS攻击炸了! (程序员鱼皮)· 终于解决了.net在线客服系统总是被360误报的问题(对软件进行数字签名) (升讯威在线客服系统)· 翻到了我2016年的面试经历,那是一个互联网的黄金时代。 (why技术)· 瞧瞧别人家的参数校验,那叫一个优雅! (苏三说技术)......
  • 搭建最新 ELK 日志分析系统 8.2.2版
    前言大家好,我是无名小歌。今天给大家分享一个centos7系统搭建2022年最新ELK日志分析系统,目前版本是8.2.2。值得注意的是安装ELK时,您必须在整个ELK中使用相同的版本,如:Elasticsearch8.2.2,则安装Kibana8.2.2和Logstash8.2.2,如果出现不对应的情况,如:Elasticsearch是8.2.2版本......