在查詢表格資料的時候,常常見到表格上方有一個表單區域, 用于資料查詢條件動態查詢表格資料.如下圖:
在此, 我開發了一個可以復用的組件. 可根據需要進行配置表單項(支持input, select, date型別的表單)和表格(支持表頭配置和單元格樣式配置).實作自定義配置表單個數和表格
一. 表單配置組件
表單配置組件-完整代碼QueryCondition.vue
<template>
<div style="width: 100%; height: 100%" class="form-condition">
<div class="form-content">
<el-form label-width="100px">
<el-row v-for="(formType, indexs) in formTypeArray" :key="indexs">
<el-col :span="span" v-for="(data, index) in formTypeArray[indexs]" :key="index">
<el-form-item :label="data.label">
<!-- 輸入框型別 -->
<el-input v-if="data.type == 'input'" v-model="formTypeArray[indexs][index].value" :placeholder="data.placeholder"></el-input>
<!-- 時間型別 -->
<el-date-picker popper-class="date-style" v-if="data.type == 'date'" type="date" :placeholder="data.placeholder"
v-model="formTypeArray[indexs][index].value"></el-date-picker>
<!-- 下拉框型別 -->
<el-select :popper-append-to-body="false" v-if="data.type == 'select'" v-model="formTypeArray[indexs][index].value" :placeholder="data.placeholder">
<el-option v-for="(item, i) in data.option" :key="i" :label="item.label" :value="item.value"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="span">
<el-form-item label="">
<div class="content-btn">
<div class="btn-search" style="float: left" @click="getCondition">
<i class="el-icon-search"></i>搜索
</div>
<div class="btn-clean" style="float: left" @click="cleanFormValue">
清空
</div>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
</div>
</template>
<script>
import {inject, ref} from "@vue/runtime-core";
import {watchEffect} from "vue";
export default {
name: "QueryCondition",
emits: ["conditionParams"],
setup(props, context) {
let span = ref(6)
let formTypeArray = ref(new Array())
const formTypeConfig = inject("formTypeConfig");
/**
* 給父組件回傳表單輸入的內容
*/
const getCondition = () => {
context.emit('conditionParams', formTypeArray.value)
}
/**
* 清空表單內容
*/
const cleanFormValue = () => {
formTypeArray.value.forEach((e, index) => {
for (let i = 0; i < e.length; i++) {
formTypeArray.value[index][i].value = ''
}
})
}
// 監聽表單配置資料 資料變化時, 更新配置
watchEffect(() => {
console.log('-------監聽formTypeConfig--------')
console.log(formTypeConfig)
setFormType(formTypeConfig, 4)
})
/**
* 設定表單型別
* @param array 表單配置
* @param col 每行表單項個數
*/
function setFormType(array, col) {
if (col == null || col == '' || array == null || array == '') {
col = 4 // 默認分4列
}
span.value = 24 / col
// 只有一行
if (col >= array.length) {
formTypeArray.value.push(array)
} else {
// 超過一行
let deb = col
let i = 0
while (i < array.length) {
let item = [] //null
while (i < deb) {
item.push(array[i])
console.log(deb)
i++
}
formTypeArray.value.push(item)
if (array.length - i < col) {
deb = array.length
} else {
deb = i + col
}
}
}
console.log('---------表單配置資料 SUCCESS----------');
}
return {
formTypeArray, span, getCondition, cleanFormValue
}
}
}
</script>
<style>
.form-condition .el-input__inner {
border: 2px solid #285267;
height: 35px;
background-color: #111D30;
}
.form-condition .el-select-dropdown {
background: #1f3758e0;
}
.form-condition .el-select-dropdown__item.hover, .el-select-dropdown__item:hover {
background-color: #314665a1;
}
.date-style .el-picker__popper .date-style .el-popper .is-light .is-pure {
background: #1f3758e0;
}
.date-style .el-picker-panel {
background: #1f3758e0;
}
.search-third .el-input__inner {
height: 36px;
}
.search-third .el-input {
margin-top: -3px;
}
.search-header .el-input__inner {
border: 2px solid #285267;
height: 35px;
background-color: #111D30;
}
</style>
<style scoped>
.form-condition {
border-radius: 3px 3px 3px 3px;
background: rgba(8, 11, 21, 0.48);
padding-top: 16px;
margin-bottom: 8px;
}
.form-condition .el-dialog__header {
padding-top: 0px;
}
/*事件*/
.btn-search:hover {
color: #aa8383;
background: #2FCE7C;
}
.btn-clean:hover {
color: #aa8383;
}
.content-btn > div {
margin-right: 16px;
}
.content-btn > div:first-child {
border: 2px solid #328597;
height: 28px;
width: 69px;
color: #d2cbcb;
text-align: center;
line-height: 28px;
border-radius: 3px 3px 3px 3px;
background-image: linear-gradient(#347489, #0E1D32);
font-size: 10px;
cursor: pointer;
}
.content-btn > div:last-child {
border: 2px solid #415770;
height: 28px;
width: 69px;
color: #d2cbcb;
text-align: center;
line-height: 28px;
border-radius: 3px 3px 3px 3px;
background-color: #1A2942;
font-size: 10px;
cursor: pointer;
}
.search-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
padding: 0 16px;
}
.search-first {
float: left;
border: 1px solid rgba(102, 226, 251, 0.24);
border-radius: 5px 5px 5px 5px;
}
/* 搜索框 */
.search-first>ul {
list-style: none;
display: flow-root;
}
.search-first>ul li {
float: left;
margin: 3px 9px;
line-height: 22px;
}
.search-first>ul li:not(:first-child)::after {
content: '';
width: 1px;
height: 14px;
background: linear-gradient(180deg, #B1D8FF 0%, rgba(177, 216, 255, 0) 100%);
display: inline-block;
position: absolute;
top: 10px;
margin: 0 -9px;
}
.search-first>ul li div {
/*border: 2px solid #328597;*/
height: 22px;
width: 54px;
color: #99BBDF;
text-align: center;
line-height: 27px;
/*border-radius: 3px 3px 3px 3px;*/
/*background-image: linear-gradient(#347489, #0E1D32);*/
font-size: 10px;
cursor: pointer;
}
/* 選中*/
.search-first>ul li:first-child div {
border: 1px solid #328597;
height: 22px;
width: 54px;
color: #d2cbcb;
text-align: center;
line-height: 22px;
border-radius: 2px;
background-image: linear-gradient(180deg, rgba(102, 226, 251, 0.4) 0%, rgba(102, 226, 251, 0) 100%);
font-size: 10px;
}
.header-right {
display: flex;
align-items: center;
}
.header-right-button {
padding: 5px 10px;
margin-right : 16px;
background: linear-gradient(180deg, rgba(102, 226, 251, 0.4) 0%, rgba(102, 226, 251, 0) 100%);
border-radius: 2px;
border: 1px solid;
font-size: 12px;
color: #99BBDF;
cursor: pointer;
}
.search-second {
display: flow-root;
float: left;
color: #d4cccc;
margin-top: 1px;
height: 26px;
border: 1px solid #21dde6;
box-shadow: 0 0 0 1px #5d4b4b;
border-radius: 4px 4px 4px 4px;
padding: 5px 4px 1px 7px;
margin-left: 12px;
margin-right: 12px;
cursor: pointer;
}
.search-second>div {
float: left;
}
.search-second div:first-child img {
width: 18px;
height: 19px;
}
.search-second div:last-child img {
width: 20px;
height: 21px;
}
.search-third {
float: left;
margin-top: 1px;
}
.form-content {
padding: 16px 16px 0;
}
</style>
1. 上面的formTypeConfig變數會接收從父組件傳來的資料配置表單項, 所以先從它入手
const formTypeConfig = inject("formTypeConfig");
在父組件中配置表單資訊, 必須按照這個資料格式(配置簡單易懂, 不作詳細說明)
父組件:
provide("formTypeConfig", [
{label: '用戶名稱', type: 'input', placeholder: '請輸入. . .', value: ''},
{label: '省份', type: 'input', placeholder: '請輸入. . .', value: ''},
{label: '模式', type: 'input', placeholder: '請輸入. . .', value: ''},
{label: '行業', type: 'input', placeholder: '請輸入. . .', value: ''},
{
label: '標簽',
type: 'select',
placeholder: '請選擇',
option: [{label: '第一項', value: '1'}, {label: '第二項', value: '2'}],
value: ''
},
{
label: '分公司',
type: 'select',
placeholder: '請選擇',
option: [{label: '第一項', value: '1'}, {label: '第二項', value: '2'}],
value: ''
},
{label: '受理員工號', type: 'input', placeholder: '請輸入. . .', value: ''},
{label: '流水號', type: 'date', placeholder: '請選擇', value: ''},
{label: '流水號', type: 'input', placeholder: '請輸入. . .', value: ''},
{label: '流水號', type: 'input', placeholder: '請輸入. . .', value: ''},
{label: '流水號', type: 'input', placeholder: '請輸入. . .', value: ''},
{label: '流水號', type: 'input', placeholder: '請輸入. . .', value: ''},
]
)
在父組件中配置好資料后,表單就能根據配置自己顯示出來啦~
2. 搜索和清空
搜索系結getCondition函式, 它會把你輸入到表單的資料發送給父組件, 具體的搜索操作(資料介面)請在父組件中寫, 搜索出來的資料再次傳給表單組件的formTypeConfig即可實作動態改變資料.
/**
* 給父組件回傳表單輸入的內容
*/
const getCondition = () => {
context.emit('conditionParams', formTypeArray.value)
}
/**
* 清空表單內容
*/
const cleanFormValue = () => {
formTypeArray.value.forEach((e, index) => {
for (let i = 0; i < e.length; i++) {
formTypeArray.value[index][i].value = ''
}
})
}
在組件中還有一個重要的方法setFormType. 他是組件的一些邏輯, 可不了解, 直接copy, 需要注意col引數, 它是配置每行顯示的表單項個數, 可根據需要進行修改.
/**
* 設定表單型別
* @param array 表單配置
* @param col 每行表單項個數
*/
function setFormType(array, col) {
if (col == null || col == '' || array == null || array == '') {
col = 4 // 默認分4列
}
span.value = 24 / col
// 只有一行
if (col >= array.length) {
formTypeArray.value.push(array)
} else {
// 超過一行
let deb = col
let i = 0
while (i < array.length) {
let item = [] //null
while (i < deb) {
item.push(array[i])
console.log(deb)
i++
}
formTypeArray.value.push(item)
if (array.length - i < col) {
deb = array.length
} else {
deb = i + col
}
}
}
console.log('---------表單配置資料 SUCCESS----------');
}
二. 表格配置組件
TableDialog.vue
<template>
<div class="content-table" style="width: 100%">
<el-table :data="tableData" row-class-name="row-style" header-row-class-name="row-style">
<!--<el-table-column type="selection" width="55"></el-table-column>-->
<el-table-column v-for="(head, index) in tableHeader" :key="index" :label="head.label" :prop="head.fieldName"
:sortable="head.sortable">
<template #default="scope">
<div :style="scope.row[head.fieldName].style">
{{ scope.row[head.fieldName].value }}
</div>
</template>
</el-table-column>
<el-table-column align="center" width="60px" label="操作">
<template #default="scope">
<div class="btn-option" @click="submitData(scope)"><i class="el-icon-tickets"></i></div>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="page.currentPage"
:page-sizes="[10, 20, 30, 40]"
:page-size="page.size"
layout="total, sizes, prev, pager, next"
:total="page.total"
popper-class='select_bottom'
>
</el-pagination>
</div>
</div>
</template>
<script>
import {inject, reactive} from "@vue/runtime-core";
import {watchEffect} from "vue";
export default {
name: "TableDialog",
emits: ["tableMessage"],
setup(props, context) {
// 資料及配置
let tableData = reactive([])
let page = reactive({})
// 表頭配置
let tableHeader = reactive([])
const tableHeaderConfig = inject("tableHeaderConfig");
const tableDataConfig = inject("tableDataConfig");
// 監聽表單配置資料
watchEffect(() => {
console.log('-------監聽tableHeaderConfig,tableDataConfig--------')
tableHeader = tableHeaderConfig
tableData = tableDataConfig ? tableDataConfig.tableData : []
page = tableDataConfig ? tableDataConfig.page : {}
})
function submitData(scope) {
context.emit('tableMessage', {page: page, scope: scope})
}
function handleSizeChange(val) {
console.log(`每頁 ${val} 條`);
context.emit('tableMessage', {page: page, scope: null})
}
function handleCurrentChange(val) {
console.log(`當前頁: ${val}`);
context.emit('tableMessage', {page: page, scope: null})
}
return {
tableHeader, tableData, submitData, handleSizeChange, handleCurrentChange, page
}
}
}
</script>
<style scoped>
.content-table :deep(.el-table) {
background: rgba(8, 11, 21, 0.48);
}
:deep(.row-style) {
background: rgba(8, 11, 21, 0.48);
}
:deep(.el-table::before) {
height: 0;
}
.content-table :deep(.el-table th.el-table__cell) {
background: rgba(8, 11, 21, 0.48);
border-bottom: rgba(8, 11, 21, 0.48);
}
.content-table .el-table tr {
background-color: #202c5d00;
font-size: 10px;
}
.content-table :deep(.el-table td.el-table__cell) {
border-bottom: rgba(8, 11, 21, 0.48);
}
.content-table :deep(.el-table--enable-row-hover .el-table__body tr:hover > td.el-table__cell) {
background-color: #131A2B;
border-bottom: rgba(8, 11, 21, 0.48);
}
.content-table :deep(.el-checkbox__inner) {
background-color: #12203c2b;;
}
.pagination {
margin-top: 16px;
text-align: right;
}
.pagination :deep(.el-input__inner) {
border: 2px solid #285267;
height: 32px;
background-color: #111D30;
color: #B1D8FF;
}
.pagination :deep(.el-pager li) {
border: 1px solid #285267;
height: 30px;
color: #B1D8FF;
background-color: #111D30;
}
.pagination :deep(.el-pager li.active) {
background: linear-gradient(180deg, rgba(102, 226, 251, 0.4) 0%, rgba(102, 226, 251, 0) 100%);;
}
.pagination :deep(.el-pagination .btn-prev) {
background-color: #111D30;
height: 30px;
color: #B1D8FF;
border: 1px solid rgba(177, 216, 255, 0.4);
}
.pagination :deep(.el-pagination .btn-next) {
background-color: #111D30;
height: 30px;
color: #B1D8FF;
border: 1px solid rgba(177, 216, 255, 0.4);
}
:deep(.el-pagination__total) {
color: #B1D8FF;
}
.select_bottom :deep(.el-select-dropdown__item.selected) {
color: #606266;
background: #1f3758e0;
border: 1px solid #517ca5
}
.select_bottom :deep(.el-select-dropdown) {
background-color: #1f3758e0;
}
.btn-option {
font-size: 22px;
color: #78b7b1;
text-shadow: 0px 0px 1px #26A7FF;
cursor: pointer;
}
</style>
和表單類似. 表格的配置也需要接收父組件傳來的配置, 負責接收的引數如下:
// 表頭
const tableHeaderConfig = inject("tableHeaderConfig");
// 表格資料
const tableDataConfig = inject("tableDataConfig");
資料格式如下:
// 設定表頭 [fieldName欄位名, label列名, width列寬, sortable排序]
tableHeader.value = [
{fieldName: 'test1', label: '客戶名稱', width: '250px', sortable: true},
{fieldName: 'test4', label: '省份', width: '200px', sortable: true},
{fieldName: 'test2', label: '客戶服務模式', width: '200px', sortable: true},
{fieldName: 'test3', label: '客戶行業', width: '200px', sortable: true},
]
// 表格資料
tableDatas.value = [
{
number: {value: 1, style: 'color: #dfe4e9;'},
name: {value: 'Huzz', style: 'color: #dfe4e9; font-weight: 600;'},
sex: {
value: 'A',
style: 'color: #F9A400;border: 2px solid #F9A400;width: 20%;text-align: center;border-radius: 5px 5px 5px 5px;'
},
option: {value: '金牌', style: 'color: #FFCE57;'},
test1: {value: '昆明', style: 'color: #dfe4e9;'},
test2: {value: '霍詠', style: 'color: #dfe4e9;'},
test3: {value: 18345681564, style: 'color: #dfe4e9;'}
},
{
number: {value: 2, style: 'color: #dfe4e9;'},
name: {value: 'Huzz', style: 'color: #dfe4e9;font-weight: 600;'},
sex: {
value: 'B',
style: 'color: #2DC277;border: 2px solid #2DC277;width: 20%;text-align: center;border-radius: 5px 5px 5px 5px;'
},
option: {value: '標準', style: 'color: #4CE2FF;'},
test1: {value: '昆明', style: 'color: #dfe4e9;'},
test2: {value: '霍詠', style: 'color: #dfe4e9;'},
test3: {value: 18345681564, style: 'color: #dfe4e9;'}
},
{
number: {value: 3, style: 'color: #dfe4e9;'},
name: {value: 'Huzz', style: 'color: #dfe4e9; font-weight: 600;'},
sex: {
value: 'C',
style: 'color: #0FD1FF;border: 2px solid #0FD1FF;width: 20%;text-align: center;border-radius: 5px 5px 5px 5px;'
},
option: {value: '銀牌', style: 'color: #FFFFFF;'},
test1: {value: '昆明', style: 'color: #dfe4e9;'},
test2: {value: '霍詠', style: 'color: #dfe4e9;'},
test3: {value: 18345681564, style: 'color: #dfe4e9;'}
},
{
number: {value: 4, style: 'color: #dfe4e9;'},
name: {value: 'Huzz', style: 'color: #dfe4e9; font-weight: 600;'},
sex: {
value: 'D',
style: 'color: #FFFFFF;border: 2px solid #FFFFFF;width: 20%;text-align: center;border-radius: 5px 5px 5px 5px;'
},
option: {value: '銅牌', style: 'color: #FF9945;'},
test1: {value: '昆明', style: 'color: #dfe4e9;'},
test2: {value: '霍詠', style: 'color: #dfe4e9;'},
test3: {value: 18345681564, style: 'color: #dfe4e9;'}
},
])
// 配置表頭資料
provide("tableHeaderConfig", tableHeader)
// 配置單元格資料及屬性/ 分頁配置默認值
provide("tableDataConfig", {page: {currentPage: 1, size: 10, total: 2}, tableData: tableDatas})
注 -- 父組件中匯入
表單:<QueryCondition @conditionParams="getCondition"></QueryCondition>
表格:<TableDialog @tableMessage="getTableMessage"></TableDialog>
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/299199.html
標籤:其他
