当前位置: 首页 > article >正文

前端面试题——Vue的双向绑定

前言

双向绑定机制是Vue中最重要的机制之一,甚至可以说是Vue框架的根基,它将数据与视图模板相分离,使得数据处理和页面渲染更为高效,同时它也是前端面试题中的常客,接下来让我们来了解什么是双向绑定以及其实现原理。

什么是双向绑定

vue的双向绑定,即数据与视图的响应式设计。具体表现为:View 的改变能实时让Model发生变化,而 Model 的变化也能实时更新 View。而单项数据绑定,所有数据只有一份,一旦数据变化,就去更新页面(只有data-->DOM,没有DOM-->data)。

总之,所谓双向绑定,指的是 Vue 实例中的 data 与其渲染的 DOM 元素的内容保持一致,无论谁被改变,另一方会相应的更新为相同的数据。

使用双向绑定(v-model)

Vue2

<template>
    <div id="app">
        <input type="text" v-model="message">
        <p>{{message}}</p>
    </div>
</template>
<script>
export default {
    data() {
      return {
        message: "Hello, Vue2!"
      };
    }
  };
</script>

Vue3

<template>
    <div id="app">
        <input type="text" v-model="message">
        <p>{{message}}</p>
    </div>
</template>
<script>
import { ref } from "vue";

  export default {
    setup() {
      const message= ref("Hello, Vue 3!");
      return { message};
    }
  };
</script>

注意,Vue双向绑定的对象一定要是响应式的。

双向绑定的原理

实现模式

Vue双向数据绑定是通过数据劫持+发布订阅者模式来实现的。Vue 采用的是 MVVM 架构,实现 MVVM 主要包含两个方面,一是数据变化更新视图,二是试图变化更新数据。 在实现过程上来说,主要有四个模块:

  • 监听器Observer:执行劫持监听的所有属性,如果属性发生变化了,就通知订阅者Watcher看是否需要更新。
  • 订阅者Watcher:可以受到属性的变化通知并执行相应的函数,从而更新视图。
  • 消息订阅器Dep:因为订阅者有很多个,所以需要一个消息订阅器Dep来专门收集这些订阅者,然后在监听器Observer和订阅者Watcher之间进行统一管理。
  • 解析器Compile:可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅器。

Vue2与Vue3绑定模式的实现差异

需要注意的是虽然Vue2与Vue3都采用了数据劫持+发布订阅者的模式,但二者的实现原理有所不同:

  • Vue2是通过 ES5 提供的 Object-defineProperty() 方法来劫持(监听)各属性的 getter、setter,并在当监听的属性发生变动时通知订阅者,是否需要更新,若更新就会执行对应的更新函数。
  • Vue3加入ES2015中新增的 Proxy() 代替了原本的 Object.defineProperty()。

Vue3为什么弃用了ObjectdefineProperty选择了Proxy

  • Proxy() 可以拦截数组和对象的变化。而 Object.defineProperty() 只能拦截对象属性的变化。
  • 相较于 Object.defineProperty() 劫持某个属性,Proxy() 则更彻底,不在局限某个属性,而是直接对整个对象进行代理。
  • Proxy能够监听到对象属性的增加、删除。
  • Object.defineProperty() 不能对 ES6 新产生的 Map 、Set 这样的数据结构进行监听。
  • Object.defineProperty() 无法监控到数组下标的变化,导致通过数组下标添加元素不能实时响应。

手写 Object.defineProperty() 双向数据绑定

<div>
    展示:<h1></h1>
    输入: <input type="text">
</div>

<script>
    // 创建definePropertyFn来挟持数据
    function definePropertyFn() {
        let obj = {}
        let val = null

        Object.defineProperties(obj, {
            val: {
                get() {
                    return val
                },
                set(newV) {
                    val = newV
                    // 数据控制视图 将更改的数据赋值给h1
                    document.querySelector('h1').innerText = newV
                    console.log('调用了set,获取:' + newV, val);
                }
            }
        })

        return obj
    }

    let newObj = definePropertyFn()
    document.querySelector('h1').innerText = newObj.val // 调用了get,执行数据渲染视图
    document.querySelector('input').value = newObj.val // 调用了get,执行数据渲染视图

    // 下面监听视图 input 标签,标签一变动,将最新数据获取调用set,赋值给val,并且赋值给h1
    document.querySelector('input').addEventListener('input', function () {
        newObj.val = document.querySelector('input').value
    })
</script>


http://www.kler.cn/a/228826.html

相关文章:

  • 数据结构入门
  • 三电平空间矢量详解
  • Spring Boot + Apache POI 实现 Excel 导出:BOM物料清单生成器(支持中文文件名、样式美化、数据合并)
  • 第22篇 基于ARM A9处理器用汇编语言实现中断<四>
  • hydra破解密码
  • 基于海思soc的智能产品开发(高、中、低soc、以及和fpga的搭配)
  • <网络安全>《16 网络安全隔离与信息单向导入系统》
  • 计算机视觉实战项目3(图像分类+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别+无人机检测+A*路径规划+单目测距与测速+行人车辆计数等)
  • 【HarmonyOS应用开发】Web组件的使用(十三)
  • 壹[1],Xamarin开发环境配置
  • linux的nginx安装
  • 复旦大学NLP团队发布86页大模型Agent综述
  • Git私服搭建
  • UML---用例图,类图
  • 前端如何预防CSRF
  • python的进程,线程、协程
  • 群晖NAS开启FTP服务结合内网穿透实现公网远程访问本地服务
  • Unity3D开发之鼠标单双击判断
  • 如何在PS5上使用金手指修改游戏
  • docker 离线安装镜像
  • Day05-Linux bash核心介绍及目录命令讲解
  • Day 17------C语言收尾之链表的删除、位运算、预处理、宏定义
  • 【ArcGIS微课1000例】0102:面状要素空洞填充
  • 如何构建TCN网络提取序列特征
  • NLP任务之Named Entity Recognition
  • 自然语言处理中所有任务的概括