vue3+arco design通過動態(tài)表單方式實現(xiàn)自定義篩選功能
1.說明
(1) 本文主要實現(xiàn)通過動態(tài)表單的方式實現(xiàn)自定義篩選的功能,用戶可以自己添加篩選的項目,篩選條件及篩選內(nèi)容。
(2) 每個項目的篩選包含篩選項目,篩選條件,篩選方式及篩選值。
篩選項目代表表中的字段,如姓名,年齡等
篩選條件包含等于,不等于,大于,小于,包含等
篩選類型包含手動輸入值的方式,通過下拉進行選擇的方式,和表中的其他字段進行比較的方式
篩選值可以手動輸入,可以通過下拉進行選擇,也可以選擇某個日期。
2.示例
<template> <a-modal :visible="visibleFlag" @ok="handleOk" @cancel="handleCancel" unmountOnClose width="auto"> <div style="text-align: right"> <a-button @click="handleAdd()">Add</a-button> </div> <a-form :model="form" layout='vertical' style="width: 1000px;height: 400px;" ref="formRef"> <div v-for="(item,index) in form.data"> <a-row :gutter="10"> <a-col :span="5"> <a-form-item :field="`data[${index}].filterColumn`" label="Column" :hide-label="index != 0" :rules="[{required:true,message:'Column不能為空'}]" validate-trigger="blur"> <a-select v-model="item.filterColumn" :style="{width:'500px'}" placeholder="Please select ..." @blur="columnBlur(form.data[index].filterColumn, form.data[index].filterType , index)" allow-clear> <a-option v-for="item of columns" :value="item.value" :label="item.label"/> </a-select> </a-form-item> </a-col> <a-col :span="6"> <a-form-item :field="`data[${index}].filterOperation`" label="Operation" :hide-label="index != 0" :rules="[{required:true,message:'Operation不能為空'}]" validate-trigger="blur"> <a-select v-model="item.filterOperation" :style="{width:'500px'}" placeholder="Please select ..." allow-clear> <a-option v-for="item of filterOpeData[index]" :value="item.value" :label="item.label"/> </a-select> </a-form-item> </a-col> <a-col :span="5"> <a-form-item :field="`data[${index}].filterType`" label="Type" :hide-label="index != 0" :rules="[{required:true,message:'Type不能為空'}]" validate-trigger="blur"> <a-select v-model="item.filterType" :style="{width:'500px'}" placeholder="Please select ..." @blur="typeBlur(form.data[index].filterColumn, form.data[index].filterType, index)" allow-clear> <a-option v-for="item of filterTypeData" :value="item.value" :label="item.label"/> </a-select> </a-form-item> </a-col> <a-col :span="5"> <a-form-item :field="`data[${index}].filterValue`" label="Value" :hide-label="index != 0" :rules="[{required:true,message:'Value不能為空'}]" validate-trigger="blur"> <a-input v-model="item.filterValue" :style="{width:'500px'}" placeholder="Please enter something" allow-clear v-if="valueFlag[index] == 0"/> <a-select v-model="item.filterValue" :style="{width:'400px'}" placeholder="Please select ..." v-if="valueFlag[index] == 1" allow-clear> <a-option v-for="item of colValList[index]" :value="item.value" :label="item.label"/> </a-select> <a-date-picker v-model="item.filterValue" :style="{width:'400px'}" v-if="valueFlag[index] == 2" /> </a-form-item> </a-col> <a-col :span="3"> <a-button v-show="index != 0" @click="handleDelete(index)" :style="{marginLeft:'10px'}">Delete</a-button> </a-col> </a-row> </div> </a-form> </a-modal> </template> <script lang="ts" setup> import {onMounted, ref} from 'vue'; import {Message} from '@arco-design/web-vue'; import {FormInstance} from '@arco-design/web-vue/es/form'; const formRef = ref<FormInstance>(); const visibleFlag = ref(false) // 0:輸入框;1:下拉選擇器;2:日期 const valueFlag = ref([] as any) valueFlag.value.push(0) const form = ref({ data: [{ filterColumn: '', filterOperation: '', filterType: '', filterValue: '' }] }) const colValList = ref([] as any) const filterOpeData = ref([] as any) const filterTypeData = [{ value: '0', label: 'Value', }, { value: '1', label: 'Column', }, { value: '2', label: 'User List', }] const operationData1 = [ {value: '1', label: 'EQUAL'}, {value: '2', label: 'GREATER_THAN'}, {value: '3', label: 'GREATER_THAN_OR_EQUAL'}, {value: '4', label: 'LESS_THAN'}, {value: '5', label: 'LESS_THAN_OR_EQUAL'}, {value: '6', label: 'NOT_EQUAL'}] const operationData2 = [ {value: '1', label: 'EQUAL'}, {value: '2', label: 'GREATER_THAN'}, {value: '3', label: 'GREATER_THAN_OR_EQUAL'}, {value: '4', label: 'LESS_THAN'}, {value: '5', label: 'LESS_THAN_OR_EQUAL'}, {value: '6', label: 'NOT_EQUAL'}, {value: '9', label: 'CONTAINS'}, {value: '10', label: 'STARTS_WITH'}, {value: '11', label: 'ENDS_WITH'}, {value: '12', label: 'DOES_NOT_START_WITH'}, {value: '13', label: 'DOES_NOT_END_WITH'}, {value: '14', label: 'DOES_NOT_CONTAIN'}, {value: '15', label: 'STARTS_OR_ENDS_WITH'} ] const handleOk = async () => { const validRes = await formRef.value?.validate(); if (!validRes) { visibleFlag.value = false; console.log(JSON.stringify(form.value.data)) } else { console.log("校驗失敗") } } const handleCancel = () => { visibleFlag.value = false; } const handleDelete = (index: any) => { form.value.data.splice(index, 1); valueFlag.value.splice(index, 1); colValList.value.splice(index, 1); } const handleAdd = () => { form.value.data.push({ filterColumn: '', filterOperation: '', filterType: '', filterValue: '' }) valueFlag.value.push(0) } const columnBlur = (colVal: any, typeVal: any, index: any) => { if (!colVal) { return } const col = columns.value.find((item: { value: any; }) => item.value == colVal) if (col.type == 'text' || col.type == 'number') { filterOpeData.value[index] = operationData2 } else { filterOpeData.value[index] = operationData1 } if (col.type == 'list' && typeVal != '1') { valueFlag.value[index] = 1 colValList.value[index] = [{ value: '1', label: '處理提交' }, { value: '2', label: '處理中' }, { value: '3', label: '處理完成' }] } if (col.type == 'date') { valueFlag.value[index] = 2 } } const typeBlur = (colVal: any, typeVal: any, index: any) => { if (typeVal == '1') { if (!colVal) { Message.error({content: 'column信息不能為空', position: 'top'}); return } else { const col = columns.value.find((item: { value: any; }) => item.value == colVal) if (col.type == 'list') { Message.error({content: 'list類型的column不支持和其他列進行比較', position: 'top'}); form.value.data[index].filterType = '' return } valueFlag.value[index] = 1 if (col.type == 'date') { colValList.value[index] = columns.value.filter((item: { type: string; }) => item.type == 'date') } else if (col.type == 'text') { colValList.value[index] = columns.value.filter((item: { type: string; }) => item.type == 'text' || item.type == 'number') } else if (col.type == 'number') { colValList.value[index] = columns.value.filter((item: { type: string; }) => item.type == 'number') } else if (col.type == 'list') { } else { colValList.value[index] = [] } } } } // 打開彈窗 const openDialog = () => { visibleFlag.value = true; }; // 導出方法在父組件中進行使用 defineExpose({openDialog}); const columns = ref() const getColumnList = () => { columns.value = [{ value: '12', label: 'genoId', type: 'text' }, { value: '13', label: 'status', type: 'list' }, { value: '14', label: 'createTime', type: 'date' }, { value: '15', label: 'qty', type: 'number' } ] } // 組件完成初始渲染并創(chuàng)建 DOM 節(jié)點后運行 onMounted(async () => { await getColumnList() }) </script> <script lang="ts"> export default { name: "dynamicFilter" } </script> <style scoped> </style>
說明:
①通過表單的方式進行實現(xiàn),表單關(guān)聯(lián)的數(shù)據(jù)源form是對象格式,如下:
const form = ref({ data: [{ filterColumn: '', filterOperation: '', filterType: '', filterValue: '' }] })
對象內(nèi)是一個id為data的數(shù)組,數(shù)組內(nèi)的每條數(shù)組則存儲一個項目的篩選內(nèi)容,包含篩選項目,篩選條件,篩選方式及篩選值。數(shù)據(jù)源設(shè)置為對象是為了進行校驗處理,如果是數(shù)組格式,無法實現(xiàn)動態(tài)表單的的校驗(不同的前端框架,可能會有所不同,但推薦使用對象格式)
②動態(tài)表單的實現(xiàn)
在form標簽內(nèi)嵌套div標簽,并在div標簽上進行循環(huán)form.data,如果動態(tài)的項目只有一個,可以直接在form-item上進行循環(huán)處理。具體的每個表單項可以通過form.data[index].表單項名的方式進行綁定,也可以通過item.表單項名的方式進行綁定。點擊新增按鈕,會向form.data中push一條新數(shù)據(jù),添加的篩選項目后面有刪除按鈕,點擊刪除按鈕,通過form.data.splice方法刪除數(shù)組中的元素。
③動態(tài)表單的校驗處理
在每個表單項中添加校驗規(guī)則,不要在form上添加校驗規(guī)則
在arco design框架中的動態(tài)表單校驗如下:
<a-form-item :field="`data[${index}].filterColumn`" label="Column" :hide-label="index != 0" :rules="[{required:true,message:'Column不能為空'}]" validate-trigger="blur"> <a-select v-model="item.filterColumn" :style="{width:'500px'}" placeholder="Please select ..." @blur="columnBlur(form.data[index].filterColumn, form.data[index].filterType , index)" allow-clear> <a-option v-for="item of columns" :value="item.value" :label="item.label"/> </a-select> </a-form-item>
通過rules關(guān)聯(lián)校驗規(guī)則,注意field屬性的設(shè)置,在arco design中field需要進行如上設(shè)置,結(jié)果例如:data[0].filterColumn。
在arco design中是設(shè)置field屬性,在element ui中是設(shè)置prop屬性,并且內(nèi)容的設(shè)置方式也不一樣,需要注意。
④提交時的校驗
當前表單嵌套在對話框中,點擊確定按鈕時,需要先進行表單的校驗處理,如下:
const handleOk = async () => { const validRes = await formRef.value?.validate(); if (!validRes) { visibleFlag.value = false; console.log(JSON.stringify(form.value.data)) } else { console.log("校驗失敗") } }
通過調(diào)用表單的ref對象的validate方法,如果校驗失敗則返回失敗的項目的field屬性內(nèi)容及錯誤信息,如果成功則返回undefined,所以通過判斷返回結(jié)果就可以判斷校驗成功與否。
校驗失敗的返回信息如下
{ "data[0].filterColumn": { "label": "Column", "field": "data[0].filterColumn", "type": "string", "isRequiredError": true, "message": "Column不能為空" }, "data[0].filterOperation": { "label": "Operation", "field": "data[0].filterOperation", "type": "string", "isRequiredError": true, "message": "Operation不能為空" }, "data[0].filterType": { "label": "Type", "field": "data[0].filterType", "type": "string", "isRequiredError": true, "message": "Type不能為空" }, "data[0].filterValue": { "label": "Value", "field": "data[0].filterValue", "type": "string", "isRequiredError": true, "message": "Value不能為空" }, "data[1].filterColumn": { "label": "Column", "field": "data[1].filterColumn", "type": "string", "isRequiredError": true, "message": "Column不能為空" }, "data[1].filterOperation": { "label": "Operation", "field": "data[1].filterOperation", "type": "string", "isRequiredError": true, "message": "Operation不能為空" }, "data[1].filterType": { "label": "Type", "field": "data[1].filterType", "type": "string", "isRequiredError": true, "message": "Type不能為空" }, "data[1].filterValue": { "label": "Value", "field": "data[1].filterValue", "type": "string", "isRequiredError": true, "message": "Value不能為空" }, "data[2].filterColumn": { "label": "Column", "field": "data[2].filterColumn", "type": "string", "isRequiredError": true, "message": "Column不能為空" }, "data[2].filterOperation": { "label": "Operation", "field": "data[2].filterOperation", "type": "string", "isRequiredError": true, "message": "Operation不能為空" }, "data[2].filterType": { "label": "Type", "field": "data[2].filterType", "type": "string", "isRequiredError": true, "message": "Type不能為空" }, "data[2].filterValue": { "label": "Value", "field": "data[2].filterValue", "type": "string", "isRequiredError": true, "message": "Value不能為空" } }
校驗通過后輸出的form.data信息,如下:
[{ "filterColumn": "12", "filterOperation": "1", "filterType": "0", "filterValue": "23" }, { "filterColumn": "13", "filterOperation": "1", "filterType": "0", "filterValue": "1" }, { "filterColumn": "14", "filterOperation": "2", "filterType": "0", "filterValue": "2024-05-14" }]
3.運行截圖
校驗失敗
輸入內(nèi)容后,校驗通過
4.總結(jié)
①注意表單綁定的數(shù)據(jù)源的格式及不同前端框架的校驗的方式
②為了使畫面更加友好,可以將表單放在表格中
到此這篇關(guān)于vue3+arco design通過動態(tài)表單方式實現(xiàn)自定義篩選的文章就介紹到這了,更多相關(guān)vue3自定義篩選內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vuejs如何解決瀏覽器切換頁面后setInterval計時器停止執(zhí)行的問題
setinterval()是定時調(diào)用的函數(shù),可按照指定的周期(以毫秒計)來調(diào)用函數(shù)或計算表達式,這篇文章主要給大家介紹了關(guān)于vuejs如何解決瀏覽器切換頁面后setInterval計時器停止執(zhí)行的問題,需要的朋友可以參考下2024-01-01vue中json格式化顯示數(shù)據(jù)(vue-json-viewer)
這篇文章主要給大家介紹了關(guān)于vue中json格式化顯示數(shù)據(jù)(vue-json-viewer)的相關(guān)資料,Vue-json-viewer是一個Vue組件,用于在Vue應(yīng)用中顯示JSON數(shù)據(jù)的可視化工具,需要的朋友可以參考下2024-05-05