1. 起因
当一个项目不断进行需求迭代时,避免不了有相似功能的功能出现,这些功能可能重复率很高,只有部分内容不同,重复去复制粘贴代码会让整个项目变的更加臃肿,积重难返,所以需要根据项目的功能需求,基于element-ui进行二次功能开发,并在封装组件中进行不断的迭代,减少重复代码,使项目变得更加整洁,干净,避免臃肿。
2.实现思路
根据需要,在根目录组件文件夹下面,创建一个独立页面进行代码开发。将常用的功能进行封装,并将可选参数暴露出来,同时通过插槽留好空缺,遇到个别特殊的功能可以通过插槽来实现功能。
3. 开发过程
<template>
<div>
<el-form
ref="searchForm"
:model="searchForm"
class="searchForm"
label-width="120px"
>
<el-form-item
v-for="(v, i) in columns"
:key="i"
:label="v.label"
:style="{ width: (v.width ? v.width : v.inputWidth ? v.inputWidth + 120 : 320) + 'px' }"
>
<!-- 插槽 -->
<template v-if="v.type === 'slot'">
<slot :name="v.slotName"> </slot>
</template>
<!-- 输入框 -->
<template v-else-if="v.type === 'input'">
<el-input
v-model.trim="searchForm[v.prop]"
clearable
:placeholder="v.placeholder || `请输入` + v.label"
:style="{ width: (v.inputWidth || 200) + 'px' }"
></el-input>
</template>
<!-- 下拉框 -->
<template v-else-if="v.type === 'select'">
<el-select
v-model="searchForm[v.prop]"
clearable
filterable
collapse-tags
:multiple="!!v.multiple"
:style="{ width: (v.inputWidth || 200) + 'px' }"
:placeholder="v.placeholder || `请选择` + v.label"
>
<el-option
v-for="(item, idx) in v.selList"
:key="idx"
:label="item.label"
:value="item.value"
/>
</el-select>
</template>
<!-- 时间日期选择框 -->
<template v-else-if="v.type === 'datePicker'">
<el-date-picker
v-model="searchForm[v.prop]"
clearable
:type="v.dateType || 'daterange'"
align="right"
:placeholder="v.placeholder || `请选择` + v.label"
:style="{ width: (v.inputWidth || 300) + 'px' }"
unlink-panels
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
:value-format="v.valueFormat || 'yyyy-MM-dd'"
:picker-options="v.pickerOptions"
>
</el-date-picker>
</template>
<template v-else-if="v.type === 'button'">
<div class="search-btn">
<!-- 默认按钮 -->
<el-button
type="primary"
:icon="v.iconFlag ? 'el-icon-search' : ''"
@click="handleClickSearch"
>查询</el-button>
<el-button
type="danger"
:icon="v.iconFlag ? 'el-icon-delete' : ''"
@click="handleClickReset"
>重置</el-button>
<!-- 附加插槽按钮 -->
<slot name="btnSlot"> </slot>
</div>
</template>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name: "SearchCom",
props: {
/**
* columns: array 搜索栏目 (必传)
* item项目:
* {
* 公共传参:
* type: string 搜索项类型 (必传)
* type类型 input(输入框)
* select(单/多选)
* datePicker(日期框)
* button(按钮项)
* slot(插槽)
* label:string 搜索项中文(必传)
* prop: string 搜索项对应val (必传)
* input和select类型建议传接口参数明 搜索fn返回对应key
* width: number 搜索项宽度单位px 默认 340
* 340 = lable 宽度120 + input/select默认宽度200
* datePicker 如果占两项宽度简易建议给640
* inputWidth: number 输入/选择/日期框宽度 单位px
* 搜索框默认200 日期框默认300
* placeholder: string
*
* type === 'selsect' 传参:
* selList: array 下拉列表 (必传) {label,value}
* multiple: boolean 是否多选
*
* type === 'datePicker' 传参:
* dateType: string 日期框类型 默认daterange
* pickerOptions: object
* valueFormat: string 日期格式 默认 yyyy-MM-dd
* defaultValue: array 默认日期
*
* type === 'slot' 传参:
* slotName: string 插槽名(必传)
* }
*
* type === ‘button’ 如果加额外按钮 插槽名用btnSlot
* iconFlag: boolean 搜索和重置按钮是否展示icon
**/
columns: {
type: Array,
default: () => []
}
},
data() {
return {
// 查询项
searchForm: {}
};
},
created() {
this.initData();
this.handleClickSearch();
},
methods: {
// 初始化数据
initData() {
const form = {};
const types = ["input", "select", "datePicker"];
for (const v of this.columns) {
if (types.includes(v.type)) {
form[v.prop] = v.defaultValue || null;
}
}
this.searchForm = form;
},
/**
* 点击搜索
* $emit传值不包含type==='slot'项
* */
handleClickSearch() {
this.$emit("onHandleSearch", {
...this.searchForm
});
},
/**
* 点击重置
* $emit传值不包含type==='slot'项
* 需使用页面自行处理重置操作
* */
handleClickReset() {
this.initData();
this.$emit("onHandleReset", {
...this.searchForm
});
}
}
};
</script>
<style lang="scss" scoped>
.searchForm {
display: flex;
align-items: center;
flex-wrap: wrap;
.search-btn {
display: flex;
flex-wrap: wrap;
}
}
</style>
4. 使用方法
在需要使用的地方,使用import引入,根据自己的功能传入不同的参数,如果需要给组件传值则使用$emit传值。
5. 后续迭代
如果有多个通用的功能可以对公共组件进行修改开发,如果只是特殊的功能建议使用插槽去进行开发。