【Vue】数据监视输入绑定

news/2024/10/23 5:32:44/

hello,我是小索奇,精心制作的Vue系列持续发放,涵盖大量的经验和示例,如有需要,可以收藏哈
本章给大家讲解的是数据监视,前面的章节已经更新完毕,后面的章节持续输出,有任何问题都可以留言或私信哈,一起加油~

数据监视

Vue实现数据监测的核心是通过defineProperty()劫持属性的getter& setter,当我们获取data数据时,底层都是通过调用getter & setter来实现的,在属性读取或修改时可以进行额外操作这实际上将数据对象“代理”了一层,形成所谓的“响应式数据”

具体一点来说哈,在初始化组件时,Vue会遍历data对象的所有属性,使用Object.defineProperty将它们转换成getter/setter这种代理允许Vue追踪依赖,在属性被访问和修改时通知变化(VM中的data就数据代理自_data)

例如我们定义了一个名为message的data属性,Vue会将其转化为

Object.defineProperty(data, 'message', {get () {// ...进行依赖收集 },set (newValue) {// ...触发更新}
})

这样在读取或修改message时,就可以触发getter和setter,从而进行依赖收集和更新触发,把这些直接叫做数据劫持即可

数据劫持就是Vue实现响应式的基石,它可以检测数据变化并触发回调来完成视图更新,使开发者只需要关注数据本身而不需要手动操作DOM

这里为什么提到数据劫持呢?

一句话形容:数据劫持是手段,数据监视是目的(没有数据劫持,就无法精确监视数据变化)

具体往下看,这里划重点,结合下面,不懂再爬上来一下哈

模拟一个小响应系统的工作方式:

<div id="app"><!-- 视图渲染 -->
</div><script>
// 数据对象  
const data = {name: 'John',age: 20
};function reactive(obj) {
// 汇总所有obj形成一个数组并进行遍历// 核心响应式转换代码Object.keys(obj).forEach(key => {let value = obj[key];const dep = new Set();Object.defineProperty(obj, key, {get() {// 收集依赖dep.add(updateView); return value;},set(newVal) {// 更新值value = newVal;// 触发依赖更新dep.forEach(fn => fn());}});});return obj;
}// 数据响应式处理
const reactiveData = reactive(data);// 视图更新函数 
function updateView() {// ...渲染视图
}// 初始化
updateView(); // 数据改变时触发视图更新
reactiveData.name = "Bob";
</script>

这个响应式系统,可以自动更新视图

当获取属性值时,收集订阅者;当设置属性值时,通知订阅者更新视图

没有get和set就不会有响应式数据,也不会显示到页面上!(调试页面中的带括号的就证明有,直接定义的没有get、set也不会响应到页面上)

拓展

响应式转换可能不理解?

// 响应式转换
const reactiveData = reactive(data);

reactive函数是用来把普通对象转换成响应式对象的,它接受一个普通对象作为参数,对这个对象的所有属性进行响应式处理,然后返回这个响应式对象

所以这里

const data = {name: 'John',age: 20
};

是定义一个普通对象data

调用:

const reactiveData = reactive(data);

reactive函数会遍历data对象的所有属性,使用Object.defineProperty()把这些属性转换成getter/setter的形式

这样responsiveData就变成一个响应式对象了,它和data对象具有相同的属性,但多了响应式的功能之后我们使用responsiveData来代替data,就可以实现视图的自动更新

简单来说reactive(data)这一行的作用就是把一个普通对象data转换成响应式对象reactiveData,得到一个可以实现数据监听与视图更新的响应式数据对象

需要注意的是,由于是直接监测属性,所以对象上的层级结构过深时,内部属性的变化不会触发响应这需要完整替换对象或手动设置新值

data: {user: {name: 'John',friend: {name: 'Chris' }}
}

如果直接这样改friend.name,Vue监测不到(直接修改深层属性无法被监测到,是因为Vue的响应式通过劫持属性的getter和setter来实现的但它只能劫持对象的第一层属性~)

this.user.friend.name = '小索奇'

重要:必须整个替换user对象,或者用Vue.set | this.$set 改friend.name,才会是响应式的数据,才会生效!

// 非响应式
this.user.name = '小索奇'
// 响应式
// Vue.set(target, key, value) | this.$set(target, key, value)
this.$set(this.user.friend, 'name', '小索奇')

数组也一样,记住不能够通过数组的索引值更改(数组本身不具备get、set方法)

this.list[0] = 'A'
// 如果数组下有对象属性,可以更改
this.list[0].name = '小索奇'

要直接调用Vue的全局API来改变数组,如用Vue.set改索引,或者用数组自身push、pop、shift、unshift、splice、sort、reverse、之类的API

  • 这些方法都被Vue做了包装,所以可以进行视图更新

上面的就可以用splice替换

this.list.splice(start, deleteCount, item1)

异步函数里改数据,页面也不会立刻更新,只有等异步函数完了,页面才显示新数据

setTimeout(() => {this.message = 'hello'
}, 1000)

所以用定时器、ajax之类的改数据,页面会晚一点才刷新

这就是Vue数据监测需要注意的几个点概括来说就是:

  • 嵌套深的数据要用Vue.set或者整个替换
  • 数组索引要用Vue.set或数组方法改
  • 异步函数里改数据,页面更新会 delay 一下

拓展

Vue.set(target,key,val)

// vm.$set()
Vue.set(vm._data.obj,'country','China')
// 为什么等同于下面的
Vue.set(vm.obj,'country','China')

这是因为数据代理-review

Vue.set 方法可以向响应式对象中添加一个属性并确保这个新属性同样是响应式的

Vue 在初始化时,会将 data 对象代理到 Vue 实例上,所以 vm.obj 等同于访问 vm._data.obj

也就是说,在组件实例 VM 中,访问 vm.obj 等同于访问 vm._data.obj,因为它会被代理到 _data 中的原始数据对象上

这是通过 Vue 的 proxy 方法实现的,大致如下:

function proxy(vm) {Object.keys(vm._data).forEach(key => {Object.defineProperty(vm, key, {get() { return vm._data[key];}});});
}

所以 Vue.set 方法既可以接受原始的 _data 对象,也可以接受代理后的组件实例对象,效果是相同的

它们都指向同一个原始数据对象

注意

  • target不允许是VM实例,也不允许是直接根对象,比如data

image-20230823005727583

表单输入绑定

这里不废话,直接上重点了哈:

如果:<input type="text"/>,则v-model收集的是value值,用户输入的就是value值

如果:<input type="radio"/>,则v-model收集的是value值,且要给标签配置value值

如果:<input type="checkbox"/>

  • 没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)

配置input的value属性:

  1. v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)

  2. v-model的初始值是数组,那么收集的的就是value组成的数组

v-model默认是收集value值,必须要写value,才能够在vue中收集到设置的内容,否则收集默认值(比如checkbox默认为checked-布尔值)

Vue 中对表单元素绑定默认值的常见示例如下:

单选框绑定字符串值

// 不设置value默认读取null
<input type="radio" v-model="picked" value="A">
<script>
data() {return {picked: 'A'}
}  
</script>

复选框绑定布尔值:

// checkbox 必须设置value值,不设置的话默认为checked的状态(布尔值)
// 如果有多组值,需要把绑定的数据设置为数组,
睡觉<input type="checkbox" v-model="hobby" value="sleep">
玩<input type="checkbox" v-model="hobby" value="play">
吃<input type="checkbox" v-model="hobby" value="eat"><script>
data() {hobby:[]
}
</script>

选择框绑定字符串:

<select v-model="selected"><option>A</option><option>B</option><option>C</option>
</select><script>
data() {return {selected: 'A'}  
}  
</script>

文本输入绑定字符串:

<input v-model="message"><script>
data() {return {message: ''}
}
</script>

此外,还有更多实用的功能等着我们去汲取,例如:

  • 使用计算属性来处理表单输入的值,可以进行一些数据的预处理或者格式化。
  • 使用v-model的修饰符,如.number.trim,可以在需要时对输入进行自动转换或者修饰。

下节继续加油~


http://www.ppmy.cn/news/1130765.html

相关文章

【数据库——MySQL】(13)过程式对象程序设计——存储函数、错误处理以及事务管理

目录 1. 存储函数2. 存储函数的应用3. 错误处理4. 抛出异常5. 事务处理6. 事务隔离级7. 应用实例参考书籍 1. 存储函数 要 创建 存储函数&#xff0c;需要用到 CREATE 语句&#xff1a; CREATE FUNCTION 存储函数名([参数名 类型, ...])RETURNS 类型[存储函数体]注意&#xff1…

深度解读F5:从企业级负载均衡到云原生应用服务

上世纪九十年代&#xff0c;Internet 的快速发展催生了大量在线网站&#xff0c;Web 访问量迅速提升。在互联网泡沫破灭以前&#xff0c;这个领域基本是围绕如何对 Web 网站进行负载均衡与优化。因而在早期&#xff0c;也会有“Web 交换机”的说法。从1997年 F5 发布了 BIG-IP …

关于Java的IO流里面的方法read()的细究

我们会经常看到上面的代码&#xff0c;很显然read(b)&#xff0c;是把字节读入到b这个字节数组里&#xff0c;然后read()返回一个成功读取的字节长度&#xff0c;如果现在用不带参的read()去一个一个字节的读了&#xff1f;那么len bInput.read()就是把这一个节字读入到len&am…

Win10电脑任务栏没有蓝牙图标的简单解决方法

Win10电脑任务栏没有蓝牙图标怎么办&#xff1f;在Win10电脑中&#xff0c;用户有时候会发现任务栏上没有蓝牙图标了&#xff0c;这样就无法通过蓝牙图标快速打开蓝牙服务了。下面小编给大家介绍最简单的解决方法&#xff0c;帮助大家找回任务栏上面的蓝牙图标吧。 问题原因 反…

Unity调用API函数对系统桌面和窗口截图

Unity3D调用WINAPI函数对系统窗口截图 引入WINAPI函数调用WINAPI函数进行截图使用例子 引入WINAPI函数 using System; using System.Collections; using System.Runtime.InteropServices; using System.Drawing;[DllImport("user32.dll")]private static extern Int…

【计算机网络】Linux 内核网络概述

文章目的 了解 Linux 内核网络架构通过网络包过滤器或者防火墙获得使用的 IP 数据包&#xff08;分组&#xff09;管理技巧熟悉如何在 Linux 内核级别使用套接字 概述 网络应用程序的开发过去这些年按照指数级增长&#xff0c;这样增加了对系统网络子系统的速度要求和产品化要…

Python 中的 Urljoin 简介

文章目录 介绍Python中的urljoin及其使用方法使用urljoin()方法使用urljoin()模块构建URLs使用urljoin()构建URLs 本篇文章介绍了 Python urljoin 及其使用时的行为。 它还使用不同的示例代码演示了在 Python 中使用 urljoin。 介绍Python中的urljoin及其使用方法 URL通常包含…

AutoAnimate - 无需任何配置,一行代码自动为元素添加优雅的过渡动画,可以搭配 Vue / React 和 Sevelt 使用

这个动画库只要一行代码就可以自动在我们的组件中添过渡动画&#xff0c;为什么这么省事高效呢&#xff1f; AutoAnimate 是一个无需任何配置&#xff0c;自动为我们开发的 Web 项目添加平滑过渡动画的 JavaScript 工具库。AutoAnimate 和之前推荐的一些 js 动画库相比&#x…