53 v-bind 和 v-model 的实现和区别

news2024/11/29 2:54:15

前言

这个主要的来源是 偶尔的情况下 出现的问题

就比如是 el-select 中选择组件之后, 视图不回显, 然后 model 不更新等等

这个 其实就是 vue 中 视图 -> 模型 的数据同步, 我们通常意义上的处理一般是通过 模型 -> 数据 的数据同步, 比如 我们代码里面更新了 model.sex 从 ”男” 更新为 ”女”, 然后 el-input 中对应的输入框的值也从 从 ”男” 更新为 ”女” 

然后 我们这里关注的问题是, 比如 我在 el-input 将 “男” 更新为 “女”, 传递到 model.sex 的问题

我们这里主要关注的就是 v-model 和 v-bind 的具体实现

 

 

然后 这个在 以前初学的情况下, 视图 -> 模型 的同步问题

这里 来看一下 这个问题的细节

主要的传递方式为 v-model 和 v-bind, “v-bind:value“ 可以简写为 “:value” 

v-model 是 视图 <-> 模型 数据双向同步的

v-bind 是 模型 -> 视图 数据单向同步的

然后 这种 视图 -> 模型 数据不同步的情况 一般是 v-bind 的情况

其他的一些情况 模型 -> 视图 数据不同步的情况, 可以参见

el-dialog 的 appendToBody 属性, 导致 vue 响应式失效

el-tree defaultCheckedKeys配置 和 树上面选中节点不同步问题

特定的操作之后响应式对象不“响应“了(一)

特定的操作之后响应式对象不“响应“了(二)

直接使用 dom api 更新了 #text节点, 之后响应式更新不生效了

 

 

 

测试用例

测试用例如下

<template>
  <div class="testParent" >
    <el-select :value="model.sex"  >
<!--    <el-select v-model="model.sex"  >-->
      <el-option v-for="item in sexList" :key="item.code" :label="item.name" :value="item.code"></el-option>
    </el-select>

<!--      <el-input :value="model.sex" ></el-input>-->
<!--      <el-input v-model="model.sex" ></el-input>-->
  </div>
</template>

<script>
  export default {
    name: 'App',
    components: {
    },
    data() {
      return {
        model: {
          sex: "1"
        },
        sexList: [
          {code: "1", name: "男"},
          {code: "2", name: "女"},
        ]
      };
    },
    computed: {},
    created() {
    },
    mounted() {
      let _this = this
      setInterval(function() {
        _this.model.sex = "2"
        console.log("--", _this.model)
      }, 3000)
    },
    methods: {
    }
  };
</script>

<style>

</style>

 

可以看到的是 通过 v-bind 绑定的数据, 操作了 界面, 但是 界面没有更新, 界面没有更新是因为 数据没有更新

9a111fdbaebd4f13a6d2e2fe941439c0.gif

 

 

v-mode 和 v-bind 的差异

当代码为 v-bind 的时候, 我们看一下 el-select 的 模部分的处理, 只是传入了一个 value 的值

784109ae527e42d886935f6afd39204a.png

 

绑定数据为 v-model 的时候, 除了注册 value 的绑定之外, 还注册了一个 callback 回调

这个 callback 回调, 就是 视图 -> 模型 数据同步的一个关键的地方

视图上有数据更新的话, 视图的处理回调链路上面会增加一个这个回调, 来更新 vm.model.sex 的数据, 使得模型拿到的是 视图的最新的数据

178b1d235a5a4318ab26c82268218b99.png

 

 

v-model 的数据绑定 和 视图->数据处理函数的绑定

在 v-model 的情况如下

这里将 model 中的配置提取到了 props 和 事件映射 中

v-model 如果配置属性名称, 默认取 value, 如果没有配置 事件名称, 默认取 input 事件

我们这里关注的属性, 这里 props 配置为 props[value] = “1” 

422e25c6244a4e10ab4ec24bc74d836c.png

 

接下来就是, 从 attrs, props 中提取需要传递给子组件的 props 数据

这里可以看到上面的 v-model 转换之后的结果, 传入给子组件的 value 为 “1”, 注册了一个 input 的处理函数, 其中包含了 _vm.$set(_vm.model, “sex”, $$v) 的回调处理

0a8a98f6f612468d9be2c36efc4bc168.png

 

从 attrs 和 props 中采集需要传递给子组件的属性列表, 优先从 props 中获取

756ab227360a44ccb1ddf4bcce2309aa.png

 

 

v-bind 的数据绑定

这边的数据绑定是通过 attrs 来进行交互的

app.vue 上面生成了创建 el-select 的时候, 需要传入 value = “1” 

这里从 attrs 中解析需要传递给子组件的 props 数据

注意 这里没有 input 的回调处理事件, 这个在 app.vue 变异之后的结果中也能看到

ef8613d1087a4ea8b4e507428380fa8e.png

 

 

数据 -> 视图 的初次绑定

是在 el-select 的 mounted 中, 这里获取 value 对应的 option

然后更新 选中的对象, 选中的 label 展示给用户

这里的 selectedLabel 为 el-select 这边展示给用户的选中的数据的标签, 这个具体可以参见 el-select 的实现

64d101be92cd49138d1b4accdaa0b0ef.png

 

el-select 中展示给用户的 输入框

a97773a95195443da7e3e0266b853c71.png

 

 

数据 -> 视图 的同步绑定

这个是基于 vue 本身的响应式机制, 响应式属性更新的时候回级联更新 属性, class, dom事件, dom属性, 样式 等等

 

这个就在 patchVNode 里面一看就好了

同步更新 属性, class, dom事件, dom属性, 样式 等等

属性主要是指的是 dom 元素的 set/getAttribute 读写的相关数据

dom属性主要是指的是 dom 元素 本身的各个字段  

c181fafcc4634fc7b0580e66ad1698d1.png

 

注意 v-bind 虽然没有 视图 -> 数据 的同步绑定, 但是 它的 数据 -> 视图 的绑定这部分是由 vue 本身的响应式机制提供支持的, 是没有问题的

将 el-select 的 value 传入更新为 :value="model.sex", 然后 三秒之后 model.sex 在 setInterval 中更新, 然后可以看到 视图也更新了

31df12f80986491c88ca8cf6eadd26d9.gif

 

 

v-model 中 视图 -> 数据 的同步绑定

整个流程是通过 vue 的 input 事件串联起来的

用户这边点击的是 select 下面的 option, 实现 option 的 dom 元素是一个 li, li 上面注册了一个 click 事件, 如下, 提交了一个 事件给父组件

ea45ed968b8f4174b6e2665f686da98f.png

1aa066e3be0047309eff581391cb1dbc.png

 

select 组件这边处理的时候, 又给 父组件提交了一个 input 事件, 携带了最新的 value

574c2b80f3a8453aaba6b7fd22ae4dad.png

 

select 的父组件就是 我们这边的业务组件了, 由编译的时候 注册了一个 input 事件的处理函数

这里 $$v 拿到的是 用户选择的最新的值, 然后 这里的通过 input 事件的回调 来更新了模型上面的数据

17efcffeee30489aaeb7d3e2e4a963a7.png

 

 

项目中可能碰到的 v-model 双向绑定失效的情况

这种情况主要的来源是 绑定的对象不是响应式对象, 因此 造成了 el-select 提交 input 事件之后, 业务组件这边虽然有 _vm.$set(_vm.model, "sex", $$v), 但是 model.sex 不是响应式对象, 造成了级联更新通知, 等等 存在问题

注意观察如下的 model.sex 属性, 是在函数中使用 model.sex 创建的属性, 这种方式创建的属性不是响应式的, 然后 导致了上面的问题, 所以 编码的时候, 视图中使用到的属性, 最好是在 data 中枚举出来, 避免一些 不必要的响应式的问题

复现的方式如下

<template>
  <div class="testParent" >
<!--    <el-select :value="model.sex"  >-->
    <el-select v-model="model.sex"  >
      <el-option v-for="item in sexList" :key="item.code" :label="item.name" :value="item.code"></el-option>
    </el-select>

<!--      <el-input :value="model.sex" ></el-input>-->
<!--      <el-input v-model="model.sex" ></el-input>-->
  </div>
</template>

<script>
  export default {
    name: 'App',
    components: {
    },
    data() {
      return {
        model: {

        },
        sexList: [
          {code: "1", name: "男"},
          {code: "2", name: "女"},
        ]
      };
    },
    computed: {},
    created() {
    },
    mounted() {
      let _this = this
      _this.model.sex = "1"
      setInterval(function() {
        _this.model.sex = "2"
        console.log("--", _this.model)
      }, 3000)
    },
    methods: {
    }
  };
</script>

<style>

</style>

 

如下, model.sex 没有响应式的 setter, getter, el-select 中虽然提交了一个 input 的事件

业务组件这边 也有 _vm.$set(_vm.model, "sex", $$v) 处理, 但是这里仅仅是更新了 model.sex 的值, 没有响应式的相关级联操作

因此 造成了数据通知给 el-select 存在问题, 然后 造成了 el-select 这边, 虽然 我们点击了该 option, 但是 最终的结果就像是 没有点击一样

dfd17ed70df6449a91a89d8ab3fbc2da.png

 

操作的现象如下

d4b4e7cc15e7486c80af8c842e678ae5.gif

 

解决的方式, 视图中使用了 model.sex, 在 data 下面的 model 下面将 sex 枚举出来

或者 首次初始化 model.sex 的时候, 使用 $set, this.$set(this.model, "sex", "1") 

 

 

完 

 

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1560003.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

正多边形拓扑与泛函

&#xff08;原创&#xff1a;Daode3056&#xff09; 也许&#xff0c;关于“拓扑”&#xff0c;“泛函”几本书上的内容与实例都是大同小异&#xff0c;总是那么点内容&#xff0c;数学要开拓一些新领域与新内容才能满足不断发展的社会与工业各种需要。本文就以人工智能生成对…

鸿蒙OS开发实例:【ArkTS 实现MQTT协议】

介绍 MQTT是物联网中的一种协议&#xff0c;在HarmonyOS API9平台&#xff0c;解决方案以C库移植为实现方案。 遥遥领先的平台&#xff0c;使用MQTT怎能不遥遥领先呢&#xff01; 新年快乐&#xff0c;本篇将带领你手把手实现HarmonyOS ArkTS语言的MQTT协议。 准备 阅读…

阿里云通用算力型u1云服务器配置性能评测及价格参考

阿里云服务器u1是通用算力型云服务器&#xff0c;CPU采用2.5 GHz主频的Intel(R) Xeon(R) Platinum处理器&#xff0c;ECS通用算力型u1云服务器不适用于游戏和高频交易等需要极致性能的应用场景及对业务性能一致性有强诉求的应用场景(比如业务HA场景主备机需要性能一致)&#xf…

如何使用极狐GitLab 自定义 Pages 根域名

本文作者&#xff1a;徐晓伟 GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署极狐GitLab。 本文主要讲述了极狐GitLab Pages …

JS实现正则匹配文本中的URL地址

如何利用JS正则表达式&#xff0c;提取文本中的URL地址呢&#xff1f; 目录 一、程序代码 二、运行结果 一、程序代码 function extractUrls(text) {var urlRegex /(https?:\/\/[^\s])/g;return text.match(urlRegex); }var text "3.02 复制打开抖音&#xff0c;看…

YOLOV8逐步分解(3)_trainer训练之模型加载

yolov8逐步分解(1)--默认参数&超参配置文件加载 yolov8逐步分解(2)_DetectionTrainer类初始化过程 接上2篇文章&#xff0c;继续讲解yolov8训练过程中的模型加载过程。 使用默认参数完成训练器trainer的初始化后&#xff0c;执行训练函数train()开始YOLOV8的训练。 1. t…

SaaS 电商设计 (十) 记一次 5000kw 商品数据ES迁移 (详细的集群搭建以及线上灰度过程设计)

目录 一.背景二.技术目标三.技术方案3.1 整体流程3.2 ES 切换前:完成整体新集群的搭建.i:拓扑结构设计ii: 如何选择整体的 **ES** 集群配置. 3.3 **ES** 版本切换中3.3.1 多client版本兼容3.3.2 Router的设计 3.4 ES 切换后3.5 开箱即用 四.总结 专栏系列 -SaaS 电商设计 (一) …

每日面经分享(pytest装饰器)

pytest装饰器 a. pytest.mark.parametrize&#xff1a;这个装饰器用于标记测试函数&#xff0c;并为其提供多组参数进行参数化测试。可以使用元组、列表、字典等形式来指定参数组合。 import pytestpytest.mark.parametrize("num1, num2, expected", [(2, 2, 4), (5…

2024 3.23~3.29周报

上周工作 SVInvNet论文研读 本周计划 加入DenseNet&#xff0c;修改网络架构&#xff0c;跑代码 总结 DenseNet 密集块&#xff1a;DenseNet将网络分成多个密集块&#xff08;Dense Block)。在每个密集块内&#xff0c;每一层都连接到前面所有的层。这种跳跃连接有助于解…

【Laravel】07 快速套用一个网站模板

【Laravel】07 快速套用一个网站模板 1. 新增post表2.补充 &#xff1a;生成Model、Controller、迁移文件3. 使用php artisan tinker4. 网站模板下载 课程地址 1. 新增post表 在Model中创建Post (base) ➜ example-app php artisan make:model Post Model created successfu…

手机有线投屏到直播姬pc端教程

1 打开哔哩哔哩直播姬客户端并登录(按下图进行操作) 2 手机用usb数据线连接电脑(若跳出安装驱动的弹窗点击确定或允许),usb的连接方式为仅充电(手机差异要求为仅充电),不同品牌手机要求可能不一样,根据实际的来 3 在投屏过程中不要更改usb的连接方式(不然电脑会死机需要重启) …

verilog中的testbench语句——display,fopen,fread,fwrite——更新中

一、fopen bmp_file_read $fopen("../pic/picture.bmp","rb"); 要注意这类操作文件的函数&#xff0c;在vivado2018自带的仿真软件里&#xff0c;不综合直接仿真&#xff0c;它的当前文件夹如图所示。 一、fwrite $fwrite(bmp_file_write,"%c"…

LeetCode - 岛屿数量

200. 岛屿数量 第一种写法&#xff1a;遍历岛屿&#xff0c;当遇到岛屿的时候&#xff0c;就开始进行深搜&#xff0c;遇到岛屿就将岛屿从1变为0。 class Solution { public:int dx[4] {0,0,1,-1};int dy[4] {1,-1,0,0};void dfs(int i, int j, vector<vector<char>…

【第十二届“泰迪杯”数据挖掘挑战赛】【2024泰迪杯】B题基于多模态特征融合的图像文本检索—解题全流程(论文更新)

【第十二届“泰迪杯”数据挖掘挑战赛】【2024泰迪杯】B题基于多模态特征融合的图像文本检索更新&#xff08;论文更新&#xff09; ​ 本节主要更新了论文、训练日志的log数据提取&#xff08;Loss、ACC、RK&#xff09;等数据可视化作图的代码 B题交流QQ群&#xff1a; 4583…

C#调用FreeSpire.Office读取word数据的基本用法

FreeSpire.Office是Spire.Office的免费版本&#xff0c;后者支持全面、复杂的office文件操作功能&#xff0c;包括文件格式转换、文档操作、文档打印等&#xff0c;详细介绍见下图及参考文献1。本文学习FreeSpire.Office的基本用法并用其获取word文档的基本信息。   新建Win…

JavaScript动态渲染页面爬取——Splash的使用

JavaScript动态渲染页面爬取 JavaScript动态渲染得页面不止Ajax一种。例如&#xff0c;有些页面的分页部分由JavaScript生成&#xff0c;而非原始HTML代码&#xff0c;这其中并不包含Ajax请求。还有类似淘宝这种页面&#xff0c;即使是Ajax获取的数据&#xff0c;其Ajax接口中…

Unix中的进程和线程-1

目录 1.如何创建一个进程 2.如何终止进程 2.2遗言函数 3.进程资源的回收 4.孤儿进程和僵尸进程 孤儿进程 (Orphan Process)&#xff1a; 僵尸进程 (Zombie Process)&#xff1a; 代码示例&#xff1a; 5. 进程映像的更新 在Linux中&#xff0c;进程和线程是操作系统进行工作调…

【Docker笔记02】【常用软件安装】

一、前言 本系列是根据 B 站 尚硅谷 Docker 视频 学习记录笔记。因为没有视频课件&#xff0c;部分内容摘自 https://www.yuque.com/tmfl/cloud/dketq0。 本系列仅为自身学习笔记记录使用&#xff0c;记录存在偏差&#xff0c;推荐阅读原视频内容或本文参考笔记。 本文主要介…

Adobe ColdFusion 任意文件读取漏洞复现(CVE-2024-20767)

0x01 产品简介 Adobe ColdFusion是美国奥多比(Adobe)公司的一套快速应用程序开发平台。该平台包括集成开发环境和脚本语言,将可扩展、改变游戏规则且可靠的产品的愿景变为现实。 0x02 漏洞概述 由于 Adobe ColdFusion 的访问控制不当,未经身份认证的远程攻击者可以构造恶…

go语言基础学习-通道(续)

1、如何有序的从通道取值 第一种 判断ok的值 package day13import "fmt"func D131() {ch1 : make(chan int)// 开始goroutine将0-100的数据发送到ch1中go func() {for i : 0; i < 100; i {ch1 <- i}close(ch1)}()for {i, ok : <-ch1 // 通道关闭后再取值o…