Look at the renderings first
1, Foreword
Party A has to export well and use excel for advanced screening. It has to implement one in the web page....
The initial attempt to use the official screening of element is very different from that of excel after showing it to Party A.. Fortunately, the official provides a custom header, so you can manually implement one. Finally, there is the complete code
In fact, this function is quite simple, but a little troublesome. I divide the screening into four types
- txt text type (i.e. input input box)
- scope type (query amount range)
- Date time type (query date)
- select drop-down box
The overall logic is: the child component gives the filtered data to the parent component, which filters it and then displays it to the table
2, Parent component
It is divided into two parts
1.tag section, which displays the filter conditions used
2.table part
html
<!-- condition tag --> <div style="margin-bottom: 10px" v-if="conditionList.length != 0"> <span>Conditions:</span> <el-tag @close="conditionClose(index)" style="margin-left: 10px" v-for="(tag, index) in conditionList" :key="index" closable :type="tag.prop" > {{ tag.label }} : <span style="color: red">{{ tag.value.value1 }}</span> <span v-if="tag.value.value2" style="color: red" >- {{ tag.value.value2 }}</span > </el-tag> </div> <!-- form --> <el-table :data="tableData" style="width: 100%" border stripe> <template v-for="(item, index) in tableConfig"> <el-table-column sortable :key="index" :label="item.label" align="center" :prop="item.prop" :width="item.width" :filters="[]" > <template slot="header" slot-scope="scope"> <custom-header v-if="customFlag" :column="scope.column" :item="item" :customParams="customParams" :labelColorList="labelColorList" @tableUpdate="tableUpdate" ></custom-header> </template> </el-table-column> </template> </el-table>
Custom header is a sub component, which contains four types of code
Data in parent data
data() { return { customFlag: false, // Show custom filter customParams: {}, //Custom filter parameters conditionList: [], //Custom filter criteria labelColorList: [], //Screening conditions already in use for dyeing // table data tableData: [], // table data copy, we do not operate on the original data tableDataCopy: [], // table configuration tableConfig: [ { label: "full name", prop: "name", width: "150px", conditionType: "txt", // Condition type }, { label: "Worth", prop: "amount", width: "150px", conditionType: "scope", // Condition type }, { label: "birthday", prop: "date", width: "150px", conditionType: "date", // Condition type }, { label: "City", prop: "city", conditionType: "select", // Condition type conditionListName: "cityList", //Condition type drop-down box data fuzzyQuery: false, //Fuzzy query }, { label: "City (fuzzy query)", prop: "city2", conditionType: "select", // Condition type conditionListName: "cityList", //Condition type drop-down box data fuzzyQuery: true, //Fuzzy query }, ], }; },
The data in tableConfig will be traversed by El table
Of which:
conditionType: the type of condition. As mentioned in the preface, it is the four types (txt,scope,date,select)
conditionListName: if it is a select type, there must be drop-down box data, right? This is the List name of the drop-down box data, but the name is not data (if you don't understand, you can understand it from the sub component)
fuzzyQuery: fuzzy query
Several key methods of parent methods
methods: { // Request dropdown data getCustomData() {}, //Color the headings that use the filter criteria setlabelColor() {}, //Custom retrieval of emitted events tableUpdate() {}, //Filter data customSearch() {}, }
getCustomData (): summarize the data of the drop-down box
customSearch (): filtering logic processing. You can change the filtering logic later. The complete code posted later is also very clear. If you don't understand, you can ask me
3, Subcomponents
props received
Column: current column data, used to display header
tableConfig: process type judgment
customParams: select drop-down data
labelColorList: the filter condition being used, for dyeing
computed
computed: { selectList() { return function (data) { return this.customParams[data.conditionListName]; }; }, },
According to the drop-down box name, find the corresponding drop-down box List data
There's nothing else to say. The sub components are relatively simple. You can see it at a glance from the complete code
4, Complete code
Parent component
<template> <div class="app"> <!-- condition tag --> <div style="margin-bottom: 10px" v-if="conditionList.length != 0"> <span>Conditions:</span> <el-tag @close="conditionClose(index)" style="margin-left: 10px" v-for="(tag, index) in conditionList" :key="index" closable :type="tag.prop" > {{ tag.label }} : <span style="color: red">{{ tag.value.value1 }}</span> <span v-if="tag.value.value2" style="color: red" >- {{ tag.value.value2 }}</span > </el-tag> </div> <!-- form --> <el-table :data="tableData" style="width: 100%" border stripe> <template v-for="(item, index) in tableConfig"> <el-table-column sortable :key="index" :label="item.label" align="center" :prop="item.prop" :width="item.width" :filters="[]" > <template slot="header" slot-scope="scope"> <custom-header v-if="customFlag" :column="scope.column" :item="item" :customParams="customParams" :labelColorList="labelColorList" @tableUpdate="tableUpdate" ></custom-header> </template> </el-table-column> </template> </el-table> </div> </template> <script> import customHeader from "./components/customHeader.vue"; export default { name: "app", data() { return { customFlag: false, // Show custom filter customParams: {}, //Custom filter parameters conditionList: [], //Custom filter criteria labelColorList: [], //Screening conditions already in use for dyeing // table data tableData: [], // table data copy, we do not operate the original data tableDataCopy: [], // table configuration tableConfig: [ { label: "full name", prop: "name", width: "150px", conditionType: "txt", // Condition type }, { label: "Worth", prop: "amount", width: "150px", conditionType: "scope", // Condition type }, { label: "birthday", prop: "date", width: "150px", conditionType: "date", // Condition type }, { label: "City", prop: "city", conditionType: "select", // Condition type conditionListName: "cityList", //Condition type drop-down box data fuzzyQuery: false, //Fuzzy query }, { label: "City (fuzzy query)", prop: "city2", conditionType: "select", // Condition type conditionListName: "cityList", //Condition type drop-down box data fuzzyQuery: true, //Fuzzy query }, ], }; }, methods: { getCustomData() { /* It is necessary to pay attention to the following data: 1.The data format is processed here and kept consistent, so that the customHeader does not need to be processed any more 3.Because we are looking for text when filtering later, the value here is always consistent with the value displayed in the list, which is also text. 3.You can write promise All, request all the data required by the drop-down box, and then open customFlag */ this.customParams = { //City list cityList: [ { value: "Beijing" }, { value: "Nanjing City" }, { value: "Shanghai" }, { value: "Guangzhou City" }, { value: "Shenzhen City" }, { value: "Hangzhou" }, { value: "Chengdu" }, ], // ... }; this.customFlag = true; }, // Color the headings that use the filter criteria setlabelColor() { this.labelColorList = []; this.conditionList.forEach((_item) => { this.labelColorList.push(_item.prop); }); }, // Custom retrieval of emitted events tableUpdate(data) { console.log(data, "condition"); let flag = true; // Update the filter criteria if they already exist this.conditionList.forEach((item, index) => { if (item.prop == data.prop) { item.value = data.value; flag = false; } }); // If not, add if (flag) { this.conditionList.push(data); } this.customSearch(); //Filter data }, // Filter data customSearch() { /* This can be said to be the core part of filtering. The custom filtering rules are here. Come here if you want to change any screening rules in the future */ console.log(this.conditionList, "this.conditionList"); this.setlabelColor(); //Sets the header color for custom retrieval // If the custom search is empty, the query will be called again if (this.conditionList.length == 0) { this.search(); return false; } const result = []; // Traverse list data for (let i = 0; i < this.tableDataCopy.length; i++) { const dataItem = this.tableDataCopy[i]; // Traverse the user-defined filter conditions and push them if they meet the rules let flag = true; for (let l = 0; l < this.conditionList.length; l++) { const item = this.conditionList[l]; // Fuzzy query of attribute name and attribute value type const { prop, value, conditionType, fuzzyQuery } = item; // txt type if (conditionType == "txt") { if (dataItem[prop].indexOf(value.value1) != -1) { flag = true; } else { flag = false; } //Range type } else if (conditionType == "scope") { if ( dataItem[prop] >= value.value1 && dataItem[prop] <= value.value2 ) { flag = true; } else { flag = false; } // Time type } else if (conditionType == "date") { // Convert to timestamp and judge let current = new Date(dataItem[prop]).getTime(); let value1 = new Date(value.value1).getTime(); let value2 = new Date(value.value2).getTime(); if (current >= value1 && current <= value2) { flag = true; } else { flag = false; } } // Drop down box type else if (conditionType == "select") { // If fuzzyQuery is true, it means fuzzy query, otherwise it means exact query if (fuzzyQuery) { if (dataItem[prop].indexOf(value.value1) != -1) { flag = true; } else { flag = false; } } else { if (dataItem[prop] == value.value1) { flag = true; } else { flag = false; } } } if (flag === false) break; } if (flag) result.push(dataItem); } console.log(result, "result"); this.tableData = result; // this.totalSize = result.length; }, search() { this.tableData = [ { name: "Wang Xiaohu", amount: 100, date: "2018-05-02", city: "Beijing", city2: "Beijing", }, { name: "Zhang Erbao", amount: 200, date: "2019-05-04", city: "Shanghai", city2: "Shanghai", }, { name: "Wang Erya", amount: 500, date: "2020-05-01", city: "Shenzhen City", city2: "Shenzhen City", }, { name: "Hu Tutu", amount: 1000, date: "2021-05-03", city: "Guangzhou City", city2: "Guangzhou City, Guangdong Province", }, { name: "Zhang Xiaolong", amount: 2000, date: "2022-05-03", city: "Hangzhou", city2: "Hangzhou City, Zhejiang Province", }, ]; // Copy a copy of the data this.tableDataCopy = JSON.parse(JSON.stringify(this.tableData)); }, // Closing condition tag conditionClose(index) { this.conditionList.splice(index, 1); this.customSearch(); //Filter data }, }, mounted() { // Request custom filter drop-down box data this.getCustomData(); // Request table data this.search(); }, components: { customHeader, }, }; </script> <style scoped lang='scss'> // Occupy space, solve the problem that clicking the user-defined filter written by yourself will bubble to sorting /deep/ .el-table__column-filter-trigger { display: none !important; } </style>
Subcomponents
<template> <!-- Note: the logic part should not be written into this component as far as possible, because this component is based on the outside table The loop is created. Writing logic here will greatly affect the performance --> <div class="customHeader" @click.stop style="display: inline-block"> <el-popover placement="bottom" title="query criteria" width="300" trigger="click" ref="popover" > <!-- txt text --> <div v-if="item.conditionType == 'txt'"> <el-input v-model.trim="conditions.value1" placeholder="Please enter the query content" @keyup.native.enter="confirm()" ></el-input> </div> <!-- scope Range--> <div v-else-if="item.conditionType == 'scope'"> <el-input style="width: 120px" v-model.trim="conditions.value1" placeholder="Please enter condition 1" ></el-input> - <el-input style="width: 120px" v-model.trim="conditions.value2" placeholder="Please enter condition 2" ></el-input> </div> <!-- date date--> <div v-else-if="item.conditionType == 'date'"> <el-date-picker v-model="conditions.value1" type="date" clearable placeholder="start time" value-format="yyyy-MM-dd" ></el-date-picker> <el-date-picker style="margin-top: 10px" v-model="conditions.value2" type="date" clearable placeholder="End time" value-format="yyyy-MM-dd" ></el-date-picker> </div> <!-- select Selection box--> <div v-else-if="item.conditionType == 'select'"> <el-select v-model="conditions.value1" placeholder="Please select" style="width: 100%" clearable > <el-option v-for="(item, index) in selectList(item)" :key="index" :label="item.value" :value="item.value" > </el-option> </el-select> </div> <!-- confirm OK box--> <div style="text-align: center"> <el-button @click="confirm" type="primary" size="mini" class="confirm" >determine</el-button > </div> <!-- label Title Display--> <span slot="reference" onselectstart="return false" oncontextmenu="return false" class="label" :class="{ labelColor: labelColorList.includes(item.prop) }" >{{ column.label }} <i class="el-icon-arrow-down"></i> </span> </el-popover> </div> </template> <script> export default { name: "customHeader", // Column current column data, data in tableConfig, customParams drop-down box data, and the filter criteria being used in labelColorList props: ["column", "item", "customParams", "labelColorList"], data() { return { conditions: { value1: "", value2: "", }, }; }, methods: { confirm() { if (!this.conditions.value1 && !this.conditions.value2) { return this.$message.warning("Please select filter criteria"); } // Close popover this.$refs.popover.doClose(); this.$emit("tableUpdate", { value: this.conditions, //Filtered data ...this.item, //table configuration }); }, }, computed: { selectList() { return function (data) { return this.customParams[data.conditionListName]; }; }, }, }; </script> <style scoped> .confirm { margin-top: 10px; } /* Do not double-click the selected text */ .label { -moz-user-select: none; /*Firefox*/ -webkit-user-select: none !important; /*webkit browser*/ -ms-user-select: none; /*IE10*/ -khtml-user-select: none; /*Early browser*/ user-select: none; } .labelColor { color: #409eff; } </style>
There must be some imperfections in the writing. Please advise