前情提要:
最近业务中需要实现产品与设备的联动搜索功能,需要两个el-select框,并且每个Select框是支持筛选的,毕竟设备和产品数量较多。这个功能在之前迭代的模块中实现过,但是并没有封装成为组件,现在要开发一个新的业务,其中”产品+设备“的联动搜索效果应用场景还有很多,因此决定将其封装成组件,方便之后使用。
一、组件介绍
(1)product-device-select组件-”产品+设备“ 的概念
因为我们是做物联网(IoT)平台的相关业务,所以,对这个概念比较熟悉了。就是我登录自己的账号,其中有我公司创建的10个产品,其中不同的产品下有不同数量的设备。如果你不太明白的话,再举个例子:把产品比喻成名著,我有四个产品分别是:西游记、水浒传、三国演义、红楼梦;那么设备就比喻成其中的人物。西游记中可以有孙悟空、猪八戒等;三国演义中有刘备、曹操等等。水浒传里有武松、林冲等等。
这下应该能理解的多,这样可以方便各位在封装自己公司业务中的组件时,看看是否有相关类似的业务也可以仿照这个思路。
思路图:
如上图所示,我们的最终目的就是封装使用product-device-select组件,方便业务组件使用双select搜索的功能
效果图:
<iframe allowfullscreen="true" data-mediaembed="csdn" frameborder="0" id="vV09Qaz6-1729585520327" src="https://live.csdn.net/v/embed/430506"></iframe>产品-设备联动搜索
二、组件封装
(1)之前的实现:
//页面html部分
<el-form :inline="true" class="demo-form-inline">
<el-form-item label="请选择产品:">
<el-select
:model-value="modelValue"
:loading="productLoading"
:remote-method="filterProductList"
filterable
remote
clearable
placeholder="请选择"
remote-show-suffix
:disabled="disabled"
@change="handleSelectedChange"
>
<el-option v-for="item in productOptions" :key="item.productKey"
:label="item.productName" :value="item.productKey!" />
</el-select>
</el-form-item>
<el-form-item label="请选择设备:">
<el-select
:model-value="modelValue2"
:loading="deviceLoading"
:remote-method="filterDeviceList2"
filterable
remote
placeholder="请选择设备"
remote-show-suffix
:disabled="disabled"
@change="handleSelectedChange"
>
<el-option v-for="item in deviceOptions" :key="item.iotId"
:label="item.deviceName" :value="item.deviceName" />
</el-select>
</el-form-item>
<el-form-item v-if="searchButton">
<el-button type="primary" @click="onSubmit()">
查询
</el-button>
<!-- <el-button @click="onReset">
重置
</el-button> -->
</el-form-item>
</el-form>
(2)封装之后:
在之前的基础之上我们已经封装过了产品<product-select>与设备<device-select>两个搜索组件,把选择产品的数据和逻辑以及接口调用封装在<product-select>中,把选择设备的数据和逻辑以及接口调用封装在<device-select>组件中,改进之后如下:
<el-form :inline="true" class="demo-form-inline">
<el-form-item label="请选择产品:">
<product-select v-model="productKey" @change="handleCancelSelect" />
</el-form-item>
<el-form-item label="请选择设备:">
<device-select v-model="deviceName" :product-key="productKey" :disabled="disabled" @change="handleCancelSelect2" />
</el-form-item>
<el-form-item v-if="searchButton">
<el-button type="primary" @click="onSubmit()">
查询
</el-button>
<!-- <el-button @click="onReset">
重置
</el-button> -->
</el-form-item>
</el-form>
js部分:
<script lang="ts" setup>
import ProductSelect from 'components/product-select/index.vue'
import { queryProductList } from '@/api/product'
import type { Product } from '@/types/global'
import DeviceSelect from '@/components/device-select/index.vue'
import { deviceTableList } from '@/api/device'
withDefaults(defineProps <{
disabled?: boolean,
deviceTypeParams?: any, // 由业务组件传入,以确定产品的设备类型的不同组合 全部产品可以不传,其他组合以数组形式传入
searchButton?: boolean,
label1?: string,
label2?: string,
}>(), {
disabled: false,
deviceTypeParams: undefined,
searchButton: false,
label1: '产品:',
label2: '设备:',
})
const emits = defineEmits(['update', 'change'])
const vm = getCurrentInstance()!
const { $message } = vm.appContext.config.globalProperties
const productKey = ref('')
const deviceName = ref('')
// 设备选择框禁用
const disabledDevice = ref(true)
// 产品回传
function handleCancelSelectProductKey(val:any) {
console.log('handleCancelSelectProductKey', val)
productKey.value = val
deviceName.value = ''
// 判断产品是否有设备
deviceTableList({ pageNum: 1, pageSize: 10000, productKey: val }).then((res) => {
if (!res.deviceDTOList) {
disabledDevice.value = true
$message.error('此产品暂无设备,无法调试')
}
})
// 判断产品是否有设备
if (productKey.value)
disabledDevice.value = false
else
disabledDevice.value = true
}
// 设备回传
function handleCancelSelectDevice(deviceName:any) {
// 将产品id+设备id 回传给父组件
emits('change', productKey.value, deviceName)
}
</script>
目前已经大大精简了我们的代码。
(3)封装功能的数据流转及逻辑注意点:
1.首先在<product-select>中调接口拿到全部产品数据列表,作为给产品的el-select组件中el-option的数据,同时给产品的el-select绑定change事件,当选定产品后,通过change事件使用emits实现子传父,将产品id传递给父组件product-device-select使用
2.product-device-select组件拿到产品id,通过父传子,传递给<device-select>组件,<device-select>中再根据产品id调用接口获取这个产品下的全部设备的数据。给<device-select>组件中的select同样绑定change事件,监听设备的变化,同样通过emits实现子传父,传递设备id供给product-device-select使用
3.最后product-device-select中通过自定义事件中,再次使用emits,将获取的产品id和设备id传递给业务组件使用。
注意:
1.第一个select中的产品值被修改之后,需要同时删除之前的设备值,不然会出现二者不匹配的情况。比如”西游记“中出现了”刘备“,这是不被允许的。
2.当产品值为空时,设备选择框置灰不可点击选择,这一点也是防止数据紊乱。
三、经验分享
组件封装的基本要求:
(1)首先就是”开箱即用“。别人几乎无需修改,直接引用后使用。
(2)”高复用“。在业务中”使用频率较高“的时候,这种功能有必要封装成为组件使用。把组件封装好之后,可以简化之后的业务开发。
(3)好的拓展性。如果碰到业务上的特殊的需求,可以根据业务中的字段区分判断出来。
(4)高内聚低耦合。这里的联动搜索,配合使用了两个子组件搜索,有一定的耦合性。应该避免其中的两个子组件修改影响到父组件。
(5)单一职责原则:一个组件应该只有一个职责,即一个组件只负责完成一个特定的功能。这样可以降低组件的复杂度,易于理解和维护。如果一个组件的功能过于复杂,应该将其拆分成多个独立的组件。
标签:el,封装,产品,组件,id,select,设备 From: https://blog.csdn.net/LM0916/article/details/143157379