在 el-table 中嵌入 el-checkbox el-input el-upload 多组件,实现复杂业务场景

news/2025/1/3 4:09:52/

由于业务场景的复杂性,需实现:在 el-table 表格中 嵌入 el-checkbox 多选框 及 el-input 输入框 及 el-upload 上传组件 ,先附上实现效果图。

在这里插入图片描述

从图片可以看出其实就是一个规格可以带有多个属性的规格表,实现此效果需涉及到的知识点大概有以下:

  1. 阻止冒泡
  2. this.$set() 动态绑定
  3. 图片上传,预览
  4. Scoped slot 获取到 table 内部的状态管理数据

首先搭建表格框架(固定两列),这个比较简单

<el-table><el-table-columnprop=""label="规格"width="220px"></el-table-column><el-table-columnprop=""label="属性"width="660px"></el-table-column>
</el-table>

由于行数不固定,行内容非普通的静态数据展示,故需用到 slot 来自定义

:data 属性绑定 commodityPropertyList数据,scope 获取 row, column, $index 和 store 等的表格内部数据

实现表格第一列

<el-table:data="commodityPropertyList"style="width: 100%"><el-table-columnprop=""label="规格"width="220px"><template slot-scope="scope"><span style="font-size: 14px;">{{scope.row.propertyName}}</span><i style="margin-left: 10px;" class="el-icon-delete" @click="deleteProperty(scope)" ></i><div style="display: flex;align-items: center;cursor: pointer;" class="property" @click="changeGPicFlag(scope)"><i  v-if="scope.row.gPicFlag == 1" class="el-icon-circle-check"></i><i class="el-icon-circle-close" v-else></i><div>开启图片上传</div></div></template></el-table-column><el-table-columnprop=""label="属性"width="660px"></el-table-column>
</el-table>

补充表格第二列

<el-table:data="commodityPropertyList"style="width: 100%"><el-table-columnprop=""label="规格"width="220px"><template slot-scope="scope"><span style="font-size: 14px;">{{scope.row.propertyName}}</span><i style="margin-left: 10px;" class="el-icon-delete" @click="deleteProperty(scope)" ></i><div style="display: flex;align-items: center;cursor: pointer;" class="property" @click="changeGPicFlag(scope)"><i  v-if="scope.row.gPicFlag == 1" class="el-icon-circle-check"></i><i class="el-icon-circle-close" v-else></i><div>开启图片上传</div></div></template></el-table-column><el-table-columnprop=""label="属性"width="660px"><template slot-scope="scope"><el-checkbox-group v-model="checkPropertyList"><el-checkbox v-for="(item1,index) in scope.row.options"   :label="item1" :key="item1.id" :disabled="pageType == 'view'"><div  style="display: flex;justify-content: center;align-items: center;margin-bottom: 20px;"><div style="width: 50%;font-size: 14px;">{{item1.optionValue}}</div><el-input :disabled="pageType == 'view'" style="margin-right: 20px;" size="mini" v-model="item1.optionAlias" placeholder="备注(可选)"></el-input><el-input :disabled="pageType == 'view'" size="mini" v-model="item1.optionSort" placeholder="排序,输入数字"></el-input><span v-if="scope.row.gPicFlag == 1" style="margin-left: 20px;"><div v-if="item1.gPicUrl" style="display: inline;"><el-image ref="preview2"  :preview-src-list="[showgPicUrl]" style="width: 20px;height: 20px;" :src="item1.gPicUrl"></el-image><i @click.stop.prevent="deleteImage(scope,index)" v-if="pageType != 'view'"  style="margin-left: 10px;font-size: 12px;" class="el-icon-delete" ></i><i style="margin-left: 10px;font-size: 12px;" @click.stop.prevent="previewImage2(scope,index)" class="el-icon-view"></i></div><el-upload v-show="!item1.gPicUrl && pageType != 'view'" ref="upload" class="insert-block" style="display: inline-block; vertical-align: top; margin-right: 8px;"action="/api/mdm/upload/image" :limit="1"  accept=".jpg,.jpeg,.png"  :on-success="handleSuccess2" :on-error="handleFormatError":file-list="imgFilesListOfOnce" :show-file-list="false"><i slot="default" @click.stop.prevent="uploadImage(scope,index)" class="el-icon-upload2"></i></el-upload><span>尺寸:800*800px,最多1</span></span></div></el-checkbox></el-checkbox-group></template></el-table-column>
</el-table>

到此,表格的页面及样式已基本完成,接下来还需处理事件逻辑。

表格第一列事件处理

changeGPicFlag(scope) {if(this.pageType == 'view') {return}this.commodityPropertyList.forEach((item,index) => {if(index == scope.$index) {item.gPicFlag = item.gPicFlag == 1 ? 0 : 1}})this.commodityPropertyList = [...this.commodityPropertyList]}

表格第二列事件处理

deleteImage(scope,index) {this.commodityPropertyList[scope.$index].options[index].gPicUrl = ""this.commodityPropertyList = [...this.commodityPropertyList] //实时更新修改的数据
},previewImage2(scope,index) {this.showgPicUrl = this.commodityPropertyList[scope.$index].options[index].gPicUrlthis.$refs.preview2[0].showViewer = true
},uploadImage(scope,index) {let num = 0let list = []list = this.commodityPropertyList.filter((item,index) => index < scope.$index)list.forEach(item => { num += item.options.length})//阻止冒泡到选checkboxthis.upload2Flag.propertyIndex = scope.$indexthis.upload2Flag.optionsIndex = indexthis.$refs['upload'][num+index].$refs['upload-inner'].handleClick()
},

表格“属性”列由 多选框checkbox、输入框input、 图片上传upload 等组件组成,从代码可看出 checkbox-group 包裹 input等组件,所以当在输入框输入或点击上传图片等操作时,都会触发勾选/取消勾选多选框。这效果不是我们想要的,我们只是想操作上传图片,所以需要在定义事件时加 @click.stop.prevent = 事件名 来阻止冒泡(阻止触发勾选操作)

于是又有问题出现了,当在 el-upload 组件加上 @click.stop.prevent = 事件名 时,你会发现,操作点击时不会触发弹出选择文件窗口,这是因为加了阻止冒泡后没有触发到选择文件的操作,这就需要我们自己在事件处理中写逻辑去触发。

1.需要在 el-upload 组件定义 ref
2.用 index 结合 num 找出被点击的那个 el-upload 组件

    uploadImage(scope,index) {let num = 0let list = []list = this.commodityPropertyList.filter((item,index) => index < scope.$index)list.forEach(item => { num += item.options.length})//阻止冒泡到选checkboxthis.upload2Flag.propertyIndex = scope.$indexthis.upload2Flag.optionsIndex = indexthis.$refs['upload'][num+index].$refs['upload-inner'].handleClick()//触发选择文件的弹窗},

在实现的过程中,我还碰到一个输入框不能输入的问题,我操作输入之后,没有动静,再点击勾选操作时就可以正确显示出来了。于是我猜想了很多种可能并一一去验证
1.el-checkbox 不能包裹其他标签?(从网上搜集到很少有这样复杂地使用多选框)
2.没有加 slot-scope="scope" ?

最后在控制台打印后端返回的 commodityPropertyList 数据中发现,其 options 数组下没有 optionAliasoptionSort 字段,需要前端这边自己加,最开始我是这样加的

//在commodityPropertyList获取数据的地方
......
this.commodityPropertyList.forEach((group) => {if (group.options && group.options.length) {group.options.forEach((item) => {item.optionAlias = ""item.optionSort = ""var key = item.propertyCode + ":" + item.optionCodevar prop = this.propSpenMap.get(key)if (prop) {group.gPicFlag = prop.gPicFlag == 1 ? 1  : 0    propList.push(prop)this.checkPropertyList.push(item)}})}
})

最后发现还是不可以,于是我尝试 this.$set() 就可以了,是因为 v-model 需要双向绑定,而 this.$set() 则是启用了动态绑定

将上面代码的
item.optionAlias = ""
item.optionSort = ""改成
this.$set(item,'optionAlias',"")
this.$set(item,'optionSort',"")

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

相关文章

uniapp 跨页面传值及跨页面方法调用

uniapp 跨页面传值及跨页面方法调用 1、跨页面传值 使用全局方法监听uni.$emit、uni.$on、uni.$off 发布、监听、移除 methods: {addFun(){let data [1]uni.navigateBack({ // 返回上一页delta: 1})uni.$emit(successFun,{data}) // 传值} }监听页 onLoad() {uni.$on(succ…

目标检测—YOLO系列(二 ) 全面解读论文与复现代码YOLOv1 PyTorch

精读论文 前言 从这篇开始&#xff0c;我们将进入YOLO的学习。YOLO是目前比较流行的目标检测算法&#xff0c;速度快且结构简单&#xff0c;其他的目标检测算法如RCNN系列&#xff0c;以后有时间的话再介绍。 本文主要介绍的是YOLOV1&#xff0c;这是由以Joseph Redmon为首的…

3DMAX平铺插件MaxTiles教程

MaxTiles 结合了一组材质和地图插件&#xff0c;任何建筑师或 3D 可视化艺术家都会喜欢。与静态位图纹理不同&#xff0c;MaxTiles 材质可以更改键合图案、替换和混合砖块、更改边缘、随机化颜色、位置、表面等等。MaxTiles 结合了以下功能&#xff1a; 墙壁和瓷砖 – 用于创建…

nginx服务器

nginx反向代理 nginx 反向代理的好处&#xff1a; 提高访问速度 因为nginx本身可以进行缓存&#xff0c;如果访问的同一接口&#xff0c;并且做了数据缓存&#xff0c; nginx就直接可把数据返回&#xff0c;不需要真正地访问服务端&#xff0c;从而提高访问速度。 进行负载均衡…

C语言编程陷阱(五)

陷阱21:不要使用逗号运算符代替分号 C语言中,我们可以使用分号来结束一个语句,比如a = b;,这样可以让编译器知道语句的边界,以及执行的顺序。但是,如果我们想要在一个语句中执行多个表达式,就可以使用逗号运算符,比如a = (b = c, c + 1);,这样可以让编译器按照从左到右…

Leetcode -2

Leetcode Leetcode -234.回文链表Leetcode -160.相交链表 Leetcode -234.回文链表 题目&#xff1a;给你一个单链表的头节点 head &#xff0c;请你判断该链表是否为回文链表。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&#xff1a; 输…

【算法】距离(最近公共祖先节点)

题目 给出 n 个点的一棵树&#xff0c;多次询问两点之间的最短距离。 注意&#xff1a; 边是无向的。所有节点的编号是 1,2,…,n。 输入格式 第一行为两个整数 n 和 m。n 表示点数&#xff0c;m 表示询问次数&#xff1b; 下来 n−1 行&#xff0c;每行三个整数 x,y,k&am…

interview review

M: intrinsic matrix [ f x s c x 0 f y c y 0 0 1 ] \begin{bmatrix}f_x & s & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1\end{bmatrix} ​fx​00​sfy​0​cx​cy​1​ ​ ( c x , c y ) (c_x, c_y) (cx​,cy​): camera center in pixels ( f x , f y …