vue中v-model如何绑定多循环表达式实战案例
作者:Dignity_呱 发布时间:2024-04-09 10:59:42
一、存在问题
在v-model
想绑定表达式 || 函数方法,发现控制台报错了,不允许这波操作。
下面我们分析存在该问题的原因和解决方法。
实战经验。
二、还原场景
有这样子的数组对象结构
const arr = [
{ value: 'a' }, { value: 'b' }
]
const item {
a: 1,
b: 2,
__config__:{ required: false },
}
想循环arr数组,然后通过arr.value
去找item
里面的属性,然后绑定在v-model
上。
理想效果是:
arr我们有两个对象,就循环两个出来,通过arr[0].value
去寻找item的属性。
<div>
<van-switch v-model="item[arr[0].value]" />
<van-switch v-model="item[arr[1].value]" />
</div>
于是,我们可以很顺利的😁写出遍历
<div
v-for="(cell, cellKey) in arr"
:key="cellKey"
>
<van-switch v-model="item[cell.value]" />
</div>
需求提升
前面只是为下面做铺垫,其实真实的场景会更复杂点。
数组对象结构是这样子的:
想通过arr.value
去找item里面的属性,然后绑定在v-model
上。
现在的arr数组的对象不再是一层了,而是多层,如:
{ value: '__config__.required' }
这样的结构怎么在template上遍历呢?
const arr = [
{ value: 'a' }, { value: '__config__.required' }
]
const item {
a: 1,
b: 2,
__config__:{ required: false },
}
三、进行分析
3.1 直接赋值法
于是,有了第一个想法,就是arr数组写着:
{ value: '__config__.required' }
直接看v-for遍历出来是怎么样的。
<div
v-for="(cell, cellKey) in arr"
:key="cellKey"
>
<van-switch v-model="item[cell.value]" />
</div>
他不是在__config__
对象中去设置required
,而是把__config__.required
当做一个属性了。
v-model
不仅仅是语法糖,它还有副作用。
如果 v-model
绑定的是响应式对象上某个不存在的属性,那么 vue
会悄悄地增加这个属性,并让它响应式。
很明显,这个方法不行❌,只适用于item.a
,不能支持多层item.__config__.required
。
再尝试另外一种方法🚶。
3.2 通过方法解析
我想在v-model绑定一个函数专门来让其value里面的'__config__.required'
取出。
理想是通过一个方法,比如叫_get方法,这个方法可以让他处理成item['__config__']['required']
,这样子我们就可以取到正确的值了。
开干!
* @description 实现 lodash 的_.get
*
* @param {Array/Object} source 目标数组/对象
* @param {String} path 获取对象的字符串路径
* @param {*} [defaultValue=undefined] 若值为空,则可传入默认值作为返回值
* @return {*}
* @example
* const get1 = tool._get({ a: null }, "a.b.c", 3) // output: 3
const get2 = tool._get({ a: [{ b: 1 }] }, "a[0].b") // output: 1
*/
_get(source, path, defaultValue = undefined) {
// a[3].b -> a.3.b -> [a,3,b]
// path 中也可能是数组的路径,全部转化成 . 运算符并组成数组
const paths = path.replace(/\[(\d+)\]/g, ".$1").split(".")
let result = source
for (const p of paths) {
// 注意 null 与 undefined 取属性会报错,所以使用 Object 包装一下。
result = Object(result)[p]
if (result == undefined) {
return defaultValue
}
}
return result
}
然后在模板里面遍历,通过_get解析取值。
<div
v-for="(cell, cellKey) in arr"
:key="cellKey"
>
<van-switch v-model="_get(item, cell.value)" />
</div>
data(){
return {
const arr = [
{ value: 'a' }, { value: '__config__.required' }
]
const item {
a: 1,
b: 2,
__config__:{ required: false },
}
}
}
发现控制台报错了。
v-model‘ directives require the attribute value which is valid as LHS
📖中文翻译: “v-model”指令要求属性值必须与LHS一样有效
❓原因:v-model将始终把Vue实例的data视为数据真实的来源,你应该在组件的JavaScript里的data中声明初始值,这意味着你不能要求v-model一次观察多个变量。
通俗易懂的说:你不能在v-model绑定函数或者表达式。
看来,这个方法也❌行不通,继续探索解决方案🚶。
3.3 通过computed计算属性
v-model 的值只能是一个变量。
值得一提,v-model
可以绑定计算属性的值,因为计算属性也是data数据真实的数据,是一个变量。
那我们就可以在computed
计算属性里面去通过_get
方法解析取值。
<div
v-for="(cell, cellKey) in arr"
:key="cellKey"
>
<van-switch v-model="getItem" />
</div>
computed:{
getItem(){
return _get(this.item, 写啥)
}
}
我们可以发现,写不下去了,如果没有v-for遍历,只是一个值的话,就可以。
但是,咱们这里的遍历的,我们不能在遍历的时候,传参数给计算属性getItem
,传了就变成方法了,就会报错。
计算属性可以用,但在v-model不能传参。
<van-switch v-model="getItem" />
// 我们不能写
<van-switch v-model="getItem(item, cell.value)" />
看来,计算属性在我们这里是❌行不通了,但计算属性可以解决我们v-model不能去调用方法的问题。
计算属性还是可以很好的解决单个值写表达式的。
3.4 two value
我想到一个最傻的方案。
就是写两个value,然后判断一下,如下代码:
<div
v-for="(cell, cellKey) in arr"
:key="cellKey"
>
<template v-if="cell.value1">
<van-switch v-model="item[cell.value][cell.value1]" />
</template>
<template v-else>
<van-switch v-model="item[cell.value]" />
</template>
</div>
data(){
return {
const arr = [
{ value: 'a' }, { value: '__config__', value1: 'required' }
]
const item {
a: 1,
b: 2,
__config__:{ required: false },
}
}
}
如果可以写表达式,里面就不需要写两条了,直接写:
<van-switch
v-model="cell.value1 ? item[cell.value][cell.value1] : item[cell.value]"
/>
当然,直接写个方法来解析获取__config__.required
会更好。
3.5 父子组件 + 计算属性
有了以上的实践,我们可以来总结一下目前的情况:
可以使用计算属性写表达式。
但局限于,我们的场景是循环的,那我们使用计算属性的话需要传参,但一旦传参则认为是方法,v-model无法支持。
我们可以想到,可以创建一个新的组件,然后组件内接收每次循环的item,在新的组件里面写v-model
绑定计算属性。
Perfect完美。
代码如下:
父组件
<div v-for="(cell, cellKey) in arr" :key="cellKey">
<Item :item="item" :cell="cell" />
</div>
data(){
return {
const arr = [
{ value: 'a' }, { value: '__config__', value1: 'required' }
]
const item {
a: 1,
b: 2,
__config__:{ required: false },
}
}
}
子组件Item.vue
<div>
<van-switch v-model="itemVal" />
</div>
<script>
props:['item', 'cell']
computed:{
itemVal(){
return this.cell.value1 ? this.item[this.cell.value][this.cell.value1] : this.item[this.cell.value]
}
},
</script>
于是,我们愉快的打开页面看下效果成功了没,发现控制台吐了块红色的错误。
Computed property "itemVal" was assigned to but it has no setter.
意思是:计算属性 itemVal
被赋值了,但此它并未定义 set
方法 。
要解决这个问题,首先要明确这个问题出现的原因。这个警告是由于Vue的计算属性内部没有set方法,即:计算属性不支持值的修改(只能针对data中的值进行计算)。
因为我们是v-model
双向绑定,所以会触发到值的修改。
computed:{
itemVal:{
get(){
return this.cell.value1 ? this.item[this.cell.value][this.cell.value1] : this.item[this.cell.value]
},
set(v){
if(this.cell.value1){
this.item[this.cell.value][this.cell.value1] = v
}else{
this.item[this.cell.value] = v
}
}
}
},
如上面所示,只要手动给计算属性添加get和set方法的不同操作,这个警告就解决了。
那既然可以写方法了,我们可以利用上面的_get
方法去解析,就不需要写两个value、value1
了,写一个value: "__config__.required"
,通过_get
去解析即可。
后记
巧妙的利用计算属性可以是变量,来为v-model
进行绑定。
这是在开发过程中的一些思路、一些尝试点。
代码总是一点一点优化,有时候先把功能点走通,再花点时间看看,能不能优化,精而再精🦀。
这也是在实际项目中真实遇到的场景。
来源:https://juejin.cn/post/7166786222419869732


猜你喜欢
- 目录1、前言2、递归3、回调函数3.1匿名回调函数3.2带参数的回调函数3.3回调函数的优缺点4、自调函数5、为值的函数6、闭包1、前言在J
- 先来了解下什么是数据库连接池数据库连接池技术的思想非常简单,将数据库连接作为对象存储在一个Vector对象中,一旦数据库连接建立后,不同的数
- “/”应用程序中的服务器错误。用户 'jb51net' 登录失败。原因: 该帐户的密码必须更改。说明: 执行当前 Web 请
- 优化查询使用Explain语句分析查询语句Explain 用来分析 SELECT 查询语句,开发人员可以通过分析 Explain 结果来优化
- ExecuteReader(),ExecuteNonQuery(),ExecuteScalar(),ExecuteXmlReader()之间
- 这是我在做的一个游戏的半成品,整理了一下发出来.原理:通过更新变换矩阵来记录转动(函数remx()).利用矩阵计算出转动后的正方体顶点坐标,
- 上一章节学习了如何在 PPT 中添加段落以及自定义段落(书写段落的内容以及样式的调整),今天的章节将学习在 PPT 中插入表格与图片以及在表
- 许多服务器管理员都知道,MySQL数据库管理系统(RDBMS)是高度灵活的软件块,带有范围广阔的启动选项,可以用来修改相关行为。然而,大部分
- 本文实例讲述了Python多进程multiprocessing、进程池用法。分享给大家供大家参考,具体如下:内容相关:multiproces
- python 版本 3.x首先安装 PIL由于PIL仅支持到Python 2.7,加上年久失修,于是一群志愿者在PIL的基础上创建了兼容的版
- 一、Python 下载Python是运行的环境,必不可少,如果你是Linux系统的话,不用安装,自带了Python。首先我们打开浏览器搜索P
- 本文实例讲述了JS仿iGoogle自定义首页模块拖拽特效的方法。分享给大家供大家参考。具体实现方法如下:<!DOCTYPE html
- 前言:在motplotlib的学习过程中,我们使用最多的就是numpy模块。numpy 模块被称为 matplotlib 模块绘制图表伴侣。
- SQL Server 2005开始,我们可以直接通过CTE来支持递归查询,CTE即公用表表达式公用表表达式(CTE),是一个在查询中定义的临
- 摘要:对动态SQL的程序开发进行了总结,并结合笔者实际开发经验给出若干开发技巧。 关键词:动态SQL,PL/SQL,高性能 1. 静态SQL
- 即text-overflow:ellipsis,需要配合white-space:nowrap使用。运行代码:<div style=&q
- 一、问题代码如下,发现标题的中文显示的是方块import matplotlibimport matplotlib.pyplot as plt
- 大家好,常用探索性数据分析方法很多,比如常用的 Pandas DataFrame 方法有 .head()、.tail()、.info()、.
- 本文介绍基于Python语言arcpy模块,实现栅格影像图层建立与多幅遥感影像数据批量拼接(Mosaic)的操作。首先,相关操作所需具体代码
- 软件版本及平台:MySQL-5.7.17-winx64,win7家庭版一、下载安装包https://cdn.mysql.com//Downl