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

使用VUE自定义组件封装部门选择功能

背景

照惯例,先交待下背景,从真实需求出发,讲述实现效果、设计思路和实现方式。
软件系统中,会有一些常见常用的选择功能,如部门选择、人员选择等,用于填报表单,使用频率很高。直接使用一方面会比较繁琐,另一方面造成代码重复,当需要调整时,则需要遍历整个项目源码,容易因漏改引发问题。这种情况下,更好的实现方案,是通过封装组件,来实现简化使用和复用的目的。
前面有一篇,介绍了使用VUE自定义组件封装数据字典,功能比较简单,今天进一步,封装一个比较复杂的部门单选组件,其他业务实体,如人员、角色等,实现非常类似,就不再赘述。

实现效果

首先展示下实现效果。
用户管理列表,左边是部门树,右侧是用户列表,如下图。
在这里插入图片描述
点击“新增”按钮,打开用户编辑页面,自动显示传入的部门。
在这里插入图片描述

第一行就是我们封装的部门单选组件,点击最右侧的图标,弹出部门选择页面来。
在这里插入图片描述

选择新部门后,确定,即可实现部门的变更。

站在使用的角度看,也非常简单,用户编辑页面整体源码如下

<template><el-dialog :title="title" :visible="visible" @close="visible=false"><el-formref="form":model="entityData":rules="rules"label-width="80px"label-position="right"style="width:90%;margin:0px auto;"><!--表单区域 --><el-form-item label="组织机构" prop="organizationId"><organization-single-selectv-model="entityData.organizationId"/></el-form-item><el-form-item label="账号" prop="account"><el-input v-model="entityData.account" /></el-form-item><el-form-item label="姓名" prop="name"><el-input v-model="entityData.name" /></el-form-item><el-form-item label="职务" prop="position"><el-input v-model="entityData.position" /></el-form-item><el-form-item label="性别" prop="gender"><dictionary-radio-groupv-model="entityData.gender":code="constant.DICTIONARY_TYPE_CODES.GENDER"/></el-form-item><el-form-item label="出生日期" prop="birthday"><el-date-pickerv-model="entityData.birthday"value-format="yyyy-MM-dd HH:mm:ss"format="yyyy年MM月dd日"type="date"placement="bottom-end"placeholder="请选择"class="form-item"/></el-form-item><el-form-item label="手机号" prop="telephone"><el-input v-model="entityData.telephone" /></el-form-item><el-form-item label="邮箱地址" prop="email"><el-input v-model="entityData.email" /></el-form-item><el-form-item label="状态" prop="status"><dictionary-radio-groupv-model="entityData.status":code="constant.DICTIONARY_TYPE_CODES.STATUS"/></el-form-item><el-form-item label="排序号" prop="orderNo"><el-input v-model="entityData.orderNo" /></el-form-item></el-form><div slot="footer" class="dialog-footer"><el-button v-show="saveButtonVisible" type="primary" @click="save">保存</el-button><el-button @click="close">关闭</el-button></div></el-dialog>
</template>

,引入部门单选组件后,具体使用的时候,只需要如下代码即可

<el-form-item label="组织机构" prop="organizationId"><organization-single-selectv-model="entityData.organizationId"/></el-form-item>

也就是说,封装组件后,使用部门单选功能,跟使用一个文本输入框类似,所有与之相关的页面展现和逻辑处理都在组件内部实现了,是不是对使用方非常友好?

设计与实现

技术栈采用的还是vue2.0,UI组件库使用element ui。

使用简单,是因为将复杂工作封装在了内部,这里同样用组件化的思路,将部门单选组件拆分成了两个vue页面,一个是整体组件,负责文本框的展示,对弹出部门选择页面的调度,另一个是负责具体的部门选择。

先附上整体组件源码

<template><div><el-input v-model="organizationName" disabled><el-button slot="append" icon="el-icon-s-grid" @click="openModal" /></el-input><organization-modal ref="organizationModel" @ok="handleOK" /></div>
</template><script>
import OrganizationModal from './OrganizationModal'
export default {name: 'OrganizationSingleSelect',components: {OrganizationModal},model: {prop: 'value',event: 'change'},props: {width: {type: Number,default: 500,required: false},value: {type: String,default: '',required: false},disabled: {type: Boolean,required: false,default: false}},data() {return {visible: false,organizationName: ''}},watch: {value: {immediate: true,handler: 'handleValue'}},methods: {openModal() {this.$refs.organizationModel.show(this.value, this.organizationName)},handleValue() {if (this.value) {this.$api.system.organization.get(this.value).then((res) => {this.organizationName = res.data.name})}},handleOK(id) {// 更新父组件绑定值this.$emit('change', id)}}
}
</script><style scoped>
</style>

下面重点说下封装需要注意的点。

1.UI元素比较简单,就一个文本框,默认设置为禁用状态,并且追加了一个按钮,用于触发部门选择页面的弹出。

 <el-input v-model="organizationName" disabled><el-button slot="append" icon="el-icon-s-grid" @click="openModal" /></el-input>

在这基础上当然也可以进行功能扩展,如再追加一个清空已选择的按钮,视需求而定。
2.很重要的一点,是设置model选项。因为默认情况下,model使用名为 value 的 prop 和名为 input 的事件,而我们封装的效果是选择控件,将文本框禁用了,事件应该使用chang而不是input,所以需要做如下设置:

 model: {prop: 'value',event: 'change'}

3.为了组件的可配置性,设置了部分prop属性,如宽度、是否禁用等,这样在使用的时候,就能通过属性绑定的方式灵活配置了。

 width: {type: Number,default: 500,required: false},value: {type: String,default: '',required: false},disabled: {type: Boolean,required: false,default: false}

4.通过vue的watch机制,监视value的变化,该值变化后,调用后端部门服务接口,拿到部门名称后更新显示。

  watch: {value: {immediate: true,handler: 'handleValue'}},……handleValue() {if (this.value) {this.$api.system.organization.get(this.value).then((res) => {this.organizationName = res.data.name})}}

5.选择项变化时,通过change事件,调用emit,把最新的值传递给使用方,这一步很关键。

 change(value) {this.$emit('change', value)}

接下来看下部门选择页面的实现,完整源码如下:

<template><div><el-dialog title="组织机构——单选" :visible="visible" width="400px" append-to-body @close="close"><el-input v-model="searchValue" placeholder="请输入关键字过滤" style="margin-bottom:10px" /><el-tag>当前机构:{{ selectedName }}</el-tag><el-treeref="tree":data="treeData"node-key="id":default-expanded-keys="defaultExpandedKeys":filter-node-method="filterNode"@current-change="handleTreeSelectChange"/><div slot="footer" class="dialog-footer"><el-button type="primary" @click="confirm">确定</el-button><el-button @click="close">关闭</el-button></div></el-dialog></div>
</template><script>export default {data() {return {visible: false,treeData: [],searchValue: '',defaultExpandedKeys: [],selectedValue: '',selectedName: ''}},watch: {searchValue(value) {this.$refs.tree.filter(value)}},methods: {show(id, name) {this.searchValue = ''this.defaultExpandedKeys = []this.selectedValue = idthis.selectedName = namethis.loadTree()this.visible = true},loadTree() {this.$api.system.organization.tree().then(res => {this.treeData = res.data// 默认展开根节点this.defaultExpandedKeys.push(this.treeData[0].id)// 默认展开当前节点this.defaultExpandedKeys.push(this.selectedValue)})},close() {this.visible = false},confirm() {this.$emit('ok', this.selectedValue)this.visible = false},// 树节点选中改变handleTreeSelectChange(data) {this.selectedValue = data.idthis.selectedName = data.label},filterNode(value, data) {if (!value) return truereturn data.label.indexOf(value) !== -1}}
}</script><style scoped>
</style>

具体功能包括了数据加载、默认展开、显示已选择值、搜索功能,已经可以满足常见的需求了。

多选功能的实现

上面实现了单选功能,其实多选功能实现也类似,这里只放代码,就不再展开介绍了

<template><div><el-input v-model="organizationName" disabled><el-button slot="append" icon="el-icon-s-grid" @click="openModal" /></el-input><organization-modal ref="organizationModel" @ok="handleOK" /></div>
</template><script>
import OrganizationModal from './organizationModal'
export default {name: 'OrganizationMultipleSelect',components: {OrganizationModal},model: {prop: 'value',event: 'change'},props: {value: {type: String,default: '',required: false},width: {type: Number,default: 500,required: false},disabled: {type: Boolean,required: false,default: false}},data() {return {visible: false,organizationName: ''}},watch: {value: {immediate: true,handler: 'handleValue'}},methods: {openModal() {this.$refs.organizationModel.show(this.value)},handleValue() {if (this.value) {const idList = this.value.split(',')this.$api.system.organization.getOrganization({ idList: idList }).then((res) => {this.organizationName = res.data.map(x => x.name).join(',')})}},handleOK(value) {// 处理父组件绑定值this.$emit('change', value.join(','))}}
}
</script><style scoped>
</style>
<template><div><el-dialog title="组织机构——多选" :visible="visible" width="400px" append-to-body @close="close"><el-input v-model="searchValue" placeholder="请输入关键字过滤" style="margin-bottom:10px" /><el-treeref="tree":data="treeData"node-key="id"show-checkbox:default-expanded-keys="defaultExpandedKeys":filter-node-method="filterNode":default-checked-keys="checkedNodesId"/><div slot="footer" class="dialog-footer"><el-button type="primary" @click="confirm">确定</el-button><el-button @click="close">关闭</el-button></div></el-dialog></div>
</template><script>export default {data() {return {visible: false,treeData: [],searchValue: '',defaultExpandedKeys: [],selectedValue: [],checkedNodesId: []}},watch: {searchValue(value) {this.$refs.tree.filter(value)}},methods: {show(idList) {this.searchValue = ''this.defaultExpandedKeys = []this.selectedValue = idListthis.loadTree()this.visible = true},loadTree() {this.$api.system.organization.tree().then(res => {this.treeData = res.data// 默认展开根节点this.defaultExpandedKeys.push(this.treeData[0].id)this.checkedNodesId = []this.getLeafNodeChecked(this.treeData)this.$refs.tree.setCheckedKeys(this.checkedNodesId)})},close() {this.visible = false},confirm() {this.$emit('ok', this.$refs.tree.getCheckedKeys())this.visible = false},filterNode(value, data) {if (!value) return truereturn data.label.indexOf(value) !== -1},getLeafNodeChecked(node) {// 遍历树节点,设置for (const treeNode of node) {// 如果节点有子节点,那他的选中状态不被考虑,继续往下找if (treeNode.children && treeNode.children.length > 0) {this.getLeafNodeChecked(treeNode.children)} else {// 是叶子节点,如果是check状态就记录if (this.selectedValue.includes(treeNode.id)) {this.checkedNodesId.push(treeNode.id)}}}}}
}</script><style scoped>
</style>

最后需要说一下的是,通过组件化的思想,可以将复杂功能拆分成一个个小的功能组件,降低复杂性和提高复用度。

相关文章:

使用VUE自定义组件封装部门选择功能

背景 照惯例&#xff0c;先交待下背景&#xff0c;从真实需求出发&#xff0c;讲述实现效果、设计思路和实现方式。 软件系统中&#xff0c;会有一些常见常用的选择功能&#xff0c;如部门选择、人员选择等&#xff0c;用于填报表单&#xff0c;使用频率很高。直接使用一方面会…...

C语言基础应用(一)数据类型

一、数据类型 1、数据类型的分类 2、常量 常量是固定值&#xff0c;在程序执行期间不会改变。这些固定的值&#xff0c;又叫做字面量。 2.1 常量举例 // 整型常量 举例 /*718 十进制0213 八进制0x4b 十六进制30u 无符号整数30l 长整型30ul 无符号长整型*/ // 浮点常量…...

算法笔记(三)—— 桶排序及排序总结

堆 逻辑上是一棵完全二叉树&#xff08;依次遍满或者全满&#xff09;。 数组可以转为完全二叉树&#xff0c;完全二叉树某结点左孩子(2*i1)&#xff0c;右孩子(i*22)&#xff0c;父结点((i-1/)2)&#xff0c;根节点的父还是自己。 如何将数组转化为堆&#xff08;大根堆&…...

Linux入门篇(一)

Linux前言Linux初探Linux内核GNU实用工具shellLinux发行版bash shell 基础Linux文件系统Linux文件操作命令前言 在阅读诸如docker之类的书的时候&#xff0c;经常碰到Linux的知识。同时&#xff0c;大部分的盲区也是在Linux方面。因此就想稍微了解一下这个广为人使用的操作系统…...

HTTPSHandler SSL Error

我在服务器ubuntu中&#xff0c;尝试使用pip3&#xff0c;但是出现下面的报错 ImportError: cannot import name HTTPSHandler 通过查询资料&#xff0c;发现报错的原因是&#xff0c;该pip3.5中没有安装好openssl. 我尝试在python3.5中使用import ssl, 确实是会显示下面的报错…...

基于Android的高校食堂餐厅配送系统

需求信息&#xff1a; 商家客户端&#xff1a; 1&#xff1a;登录注册&#xff1a;用户可以通过自己的信息进行账号的注册 2&#xff1a;发布菜单&#xff1a;发布自己经营的美食信息 3&#xff1a;用户订单&#xff1a;查看用户的购买订单 4&#xff1a;订单配送&#xff1a;对…...

Java设计模式-02工厂模式

为什么需要工厂模式&#xff0c;其作用什么&#xff1f;如何实现&#xff0c;代码演示解析优缺点。Q1:为什么需要工厂模式&#xff1f;工厂模式的作用(优点)是什么&#xff1f; 解耦。把对象的创建和使用的过程分开。就是Class A 想调用 Class B &#xff0c;那么A只是调用B的…...

AXI-Lite 学习笔记

AXI-Lite 学习笔记 参考 FPGA&#xff1a;AXI_Lite总线基础2-1]、第二节 AXI总线介绍、ZYNQ PL与PS交互专题_哔哩哔哩_bilibili AXI-Lite总线系列1 - 基础知识_哔哩哔哩_bilibili AXI4 介绍 AXI4 是ARM公司提出的一种片内总线&#xff0c;描述了主从设备之间的数据传输方式。主…...

77页智慧城市顶层设计方案

【版权声明】本资料来源网络&#xff0c;知识分享&#xff0c;仅供个人学习&#xff0c;请勿商用。【侵删致歉】如有侵权请联系小编&#xff0c;将在收到信息后第一时间删除&#xff01;完整资料领取见文末&#xff0c;部分资料内容&#xff1a;篇幅有限&#xff0c;无法完全展…...

JavaWeb--MavenMybatis基础

JavaWeb--Maven&Mybatis基础1 Maven1.1 Maven简介1.1.1 Maven模型1.1.2 仓库1.2 Maven基本使用1.2.1 Maven 常用命令1.2.2 Maven 生命周期1.3 IDEA使用Maven1.3.1 IDEA配置Maven环境1.3.2 Maven 坐标详解1.3.3 IDEA 创建 Maven项目1.3.4 IDEA 导入 Maven项目1.4 依赖管理1.…...

博客系统--测试用例编写

目录一&#xff0c;整体概览1.1&#xff0c;登录页面测试用例1.2&#xff0c;注册页面测试用例1.3&#xff0c;发布博客功能测试1.4&#xff0c;删除博客功能测试二&#xff0c;具体设计2.1&#xff0c;注册页面测试--等价类法2.2&#xff0c;删除博客功能测试--判定表法一&…...

SpringCloud Alibaba

文章目录&#x1f68f; 第十七章 SpringCloud Alibaba入门简介&#x1f6ac; 一、为什么使用Alibaba&#x1f6ad; 1、spring netflix进入维护模式&#x1f6ad; Spring cloud alibaba&#x1f6ac; 二、如何使用&#xff1f;&#x1f6ac; 三、版本对应&#x1f68f; 第十八章…...

地平线slam算法岗位 面试分享

本专栏分享 计算机小伙伴秋招春招找工作的面试经验和面试的详情知识点 专栏首页:秋招算法类面经分享 主要分享计算机算法类在面试互联网公司时候一些真实的经验 小伙伴自我介绍: 写在前面,南京某炮专,研二上阶段,简历写了两个竞赛和一个项目,一个机器人相关的二等奖,一个…...

32、基于51单片机红外智能垃圾桶系统设计

摘要 随着现代化进程的日益推进&#xff0c;科技越来越发达&#xff0c;人们的生活水平也提高了&#xff0c;城市化程度越来越高&#xff0c;与此同时也带了许多问题&#xff0c;生活垃圾越来越多垃圾设施却不够完善。无论是在公共场合还是家庭厨房的垃圾大都是没有盖或者有盖…...

PIL.Image与cv2之间的常用API汇总

简单介绍 主要是因为经常用到这两个&#xff0c;经常弄混淆&#xff0c;所以&#xff0c;总结一番。持续更新。 from PIL import Image import cv2 as cv import numpy as np import matplotlib.pyplot as plt1、读取文件与写入文件 1.1 Image.open() img_pil Image.open…...

【csdn首发】全网爆火的从零到一落地接口自动化测试

前段时间写了一系列自动化测试相关的文章&#xff0c;当然更多的是方法和解决问题的思路角度去阐述我的一些观点。结合我自己实践自动化测试的一些经验以及个人理解&#xff0c;这篇文章来聊聊新手如何从零到一落地实践接口自动化测试。 为什么要做接口测试 测试理念的演变 早…...

基于应力的拓扑优化的高效3D灵敏度分析代码(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

PMP®十万个为什么(二)

11.我的职位与项目管理并没有多大联系&#xff0c;PMP对我应该就没有什么价值了吧&#xff1f; 其实不然&#xff0c;首先&#xff0c;我们知道项目管理是一个系统性的工作&#xff0c;在一个企业内部如果要把项目管理的工作做好&#xff0c;除了项目团队的工作与管理水平不断提…...

【Linux】生产者消费者模型

&#x1f387;Linux&#xff1a; 博客主页&#xff1a;一起去看日落吗分享博主的在Linux中学习到的知识和遇到的问题博主的能力有限&#xff0c;出现错误希望大家不吝赐教分享给大家一句我很喜欢的话&#xff1a; 看似不起波澜的日复一日&#xff0c;一定会在某一天让你看见坚持…...

2023/2/13 蓝桥备战acwing刷题(set的使用、简单推个不等式+差分、快速幂、01背包模板回顾、类似01背包的题)

4454未初始化警告 set计数 #include<iostream> #include<set> using namespace std;int main(){int n,m;cin>>n>>m;set<int> s;int res 0;s.insert(0);while(m--){int l,r;cin>>l>>r;if(s.count(r)0){res;}s.insert(l);}cout<…...

Android Wi-Fi 连接失败日志分析

1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分&#xff1a; 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析&#xff1a; CTR…...

OpenLayers 可视化之热力图

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 热力图&#xff08;Heatmap&#xff09;又叫热点图&#xff0c;是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中&#xff0c;我们已经大致实现了rpc服务端的各项功能代…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

Docker 运行 Kafka 带 SASL 认证教程

Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明&#xff1a;server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)

可以使用Sqliteviz这个网站免费编写sql语句&#xff0c;它能够让用户直接在浏览器内练习SQL的语法&#xff0c;不需要安装任何软件。 链接如下&#xff1a; sqliteviz 注意&#xff1a; 在转写SQL语法时&#xff0c;关键字之间有一个特定的顺序&#xff0c;这个顺序会影响到…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

Module Federation 和 Native Federation 的比较

前言 Module Federation 是 Webpack 5 引入的微前端架构方案&#xff0c;允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...