一、效果圖
二、代碼(此代碼是基于自己項(xiàng)目更改,根據(jù)各自項(xiàng)目進(jìn)行調(diào)整)
1、子組件封裝
注意使用:正常使用
// 在el-tree觸發(fā)@check-change="checkChange" 事件,方法如下:
checkChange() {
// 節(jié)點(diǎn)選中狀態(tài)更改
// 獲取選中的node節(jié)點(diǎn)
let selectedArray = this.getCheckedNodes();
// 設(shè)置select展示的label
this.selectShowLabel = selectedArray.map(node => node[this.defaultProps.label]);
// 更新model綁定值
let selectValueArray = selectedArray.map(node => node[this.defaultProps.value]);
this.$emit("changeChecked", selectValueArray)
},
正常使用的情況下可以不需要這些,個(gè)人需求需要
useData: {
type: Array,
default: () => []
},
item: {
type: Object,
default: () => {}
},
initData: {
type: Object,
default: () => {}
},
// 因項(xiàng)目需求不一致,故使用了@check="checkChange(useData, item,initData)" @check-change="onSetCheckedNodes"兩種
// 子組件使用文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-681321.html
<template>
<div class="root">
<el-select v-model="selectShowLabel" :clearable="clearable" :placeholder="placeholder" multiple :collapse-tags="collapseTags" :popper-append-to-body="false" @blur="handleBlur" @visible-change="visibleChange" @change="changeHandle" @clear="clear" @remove-tag="removeTag">
<el-option :value="selectShowLabel" disabled :style="'margin:5px'">
<el-input v-model="filterText" size="small" prefix-icon="el-icon-search" clearable placeholder="輸入關(guān)鍵字進(jìn)行查找"> </el-input>
</el-option>
<el-tree ref="tree" :data="treeData" :expand-on-click-node="false" check-on-click-node check-strictly show-checkbox :node-key="defaultProps.value" :props="defaultProps" :default-expand-all="expandAll" :filter-node-method="filterNode" @check="checkChange(useData, item,initData)" @check-change="onSetCheckedNodes">
</el-tree>
</el-select>
</div>
</template>
<script>
import CircularJSON from 'circular-json';
export default {
model: {
prop: 'checkedArray', // 把父組件傳過(guò)來(lái)的值重命名為checkedArray
event: 'changeChecked' // 把父組件傳過(guò)來(lái)的方法重命名為changeChecked 其實(shí)就是 input
},
props: {
// 選中節(jié)點(diǎn)的值
checkedArray: {
type: Array,
default: () => {
return [];
}
},
// 樹(shù)數(shù)據(jù)
treeData: {
type: Array,
required: true
},
useData: {
type: Array,
default: () => []
},
item: {
type: Object,
default: () => {}
},
initData: {
type: Object,
default: () => {}
},
// 設(shè)置指定的label,value,children
nodeConfig: {
type: Object,
default: () => {
return {
value: 'code',
label: 'name',
children: 'childrenList'
};
}
}
},
data() {
return {
// 用于下拉列表展示
selectShowLabel: '',
// 篩選輸入框綁定值
filterText: '',
placeholder: '請(qǐng)選擇',
clearable: true, // 開(kāi)啟下拉框一鍵清空
collapseTags: true, // 下拉框tag是否折疊
expandAll: false, // 是否展開(kāi)所有節(jié)點(diǎn)
modelData: [],
modelList: [],
modelListData: [],
filtraArr: [],
filterMessage: ''
};
},
computed: {
defaultProps() {
return Object.assign(
{
value: 'code',
label: 'name',
children: 'childrenList'
},
this.nodeConfig
);
}
},
watch: {
// 設(shè)置回顯
checkedArray: {
handler(val) {
if (val && val.length > 0) {
this.setCheckedNodes(val);
}
},
// 監(jiān)聽(tīng)第一次數(shù)據(jù)更改
immediate: true
},
// 篩選符合條件選項(xiàng)
filterText(val) {
this.$refs.tree.filter(val);
this.getFilterData();
}
},
methods: {
onSetCheckedNodes(data) {
this.filtraArr = [data.code];
},
visibleChange($event) {
if (!$event) {
this.filterText = '';
}
},
// el-select失去焦點(diǎn)后校驗(yàn)
handleBlur(val) {
this.$emit('blur', val.target.value);
this.dispatch('ElFormItem', 'el.form.blur', [this.checkedArray]);
},
// el-select清空樹(shù)選擇的內(nèi)容
clear() {
this.$emit('changeChecked', []);
this.$refs.tree.setCheckedKeys([]);
},
// el-select選擇值發(fā)生改變后校驗(yàn)
changeHandle() {
this.dispatch('ElFormItem', 'el.form.change', [this.checkedArray]);
},
// select移除選中標(biāo)簽
removeTag(label) {
// 選中項(xiàng)的value
let selectedValueArray = this.$refs.tree
.getCheckedNodes()
.filter((o) => o[this.defaultProps.label] !== label)
.map((o) => o[this.defaultProps.value]);
// 移除的節(jié)點(diǎn)
let removeNode = this.$refs.tree
.getCheckedNodes()
.filter((o) => o[this.defaultProps.label] === label);
// 更新樹(shù)選中節(jié)點(diǎn)
removeNode.forEach((o) => {
this.$refs.tree.setChecked(o, false, true);
});
// 更新父組件綁定值
this.$emit('changeChecked', selectedValueArray);
},
// 樹(shù)節(jié)點(diǎn)過(guò)濾方法
filterNode(value, data) {
if (!value) return true;
return data[this.defaultProps.label].indexOf(value) !== -1;
},
getFilterData() {
if (this.filterText) {
const rootData = this.$refs.tree.root;
if (rootData.visible) {
const childNodesStr = CircularJSON.stringify(rootData.childNodes);
const childNodes = CircularJSON.parse(childNodesStr);
this.filterData = this.recursionNodes(childNodes);
this.filterMessage = '';
} else {
this.filterMessage = '暫無(wú)數(shù)據(jù)';
}
}
},
// 這里解釋一下為什么要用CircularJSON這個(gè)插件,因?yàn)閑lement tree 這node數(shù)據(jù)存在一個(gè)對(duì)象里的子項(xiàng)存在循環(huán)引用,存在循環(huán)引用的對(duì)象
recursionNodes(childNodes) {
const nodes = childNodes;
const result = [];
for (const item of nodes) {
if (item.visible) {
result.push(item.data);
}
if (item.childNodes && item.childNodes.length) {
const tempResult = this.recursionNodes(item.childNodes);
item.data.children = tempResult;
}
}
return result;
},
// 獲取選中節(jié)點(diǎn)
getCheckedNodes() {
let onlyLeaf = true;
return this.$refs.tree.getCheckedNodes(onlyLeaf).map((node) => ({
[this.defaultProps.label]: node[this.defaultProps.label],
[this.defaultProps.value]: node[this.defaultProps.value]
}));
},
// 設(shè)置選中節(jié)點(diǎn)
async setCheckedNodes(selectedArray) {
if (!selectedArray || selectedArray.length === 0) {
this.clear();
return;
}
// 外層"this.$nextTick"處理第一次回顯dom可能未加載導(dǎo)致setCheckedKeys報(bào)錯(cuò)
this.$nextTick(() => {
this.$refs.tree.setCheckedKeys(selectedArray);
});
},
// 過(guò)濾出當(dāng)前點(diǎn)擊得code
filtrationArr(arr, arr1) {
const tempArr = [];
arr.forEach((item) => {
const itemStr = item.toString();
let flag = false;
arr1.forEach((item1) => {
const itemStr1 = item1.toString();
if (itemStr === itemStr1) {
flag = true;
}
});
if (!flag) {
tempArr.push(item);
}
});
return tempArr;
},
// 數(shù)據(jù)將屬性結(jié)構(gòu)扁平化
treeArr(data, parentCode, res = []) {
data.forEach((item) => {
const { code, name, level, childrenList } = item;
res.push({
code: code,
parentCode: parentCode,
name: name,
level: level
});
if (childrenList && childrenList.length) {
this.treeArr(childrenList, code, res);
}
});
return res;
},
// 節(jié)點(diǎn)選中狀態(tài)更改
checkChange(model, item, initData) {
let filtraArr = null;
// 1、樹(shù)結(jié)構(gòu)扁平化處理數(shù)組放到vuex
this.$store.commit('cascaderData', this.treeArr(item.options));
// 2、記錄點(diǎn)擊選中與上一次得數(shù)據(jù)
if (this.modelData.length === 0) {
this.modelData = [...this.$refs.tree.getCheckedNodes()];
} else {
this.modelListData = [...this.modelList];
this.modelList = [...this.modelData];
this.modelData = [...this.$refs.tree.getCheckedNodes()];
}
// 3、過(guò)濾出當(dāng)前選中得數(shù)據(jù)(判斷選中數(shù)據(jù)大于等2是且記錄數(shù)據(jù)不為0,并且選中數(shù)據(jù)大于記錄數(shù)據(jù))
if (this.modelData.length >= 1 && this.modelList.length !== 0) {
let modelData = [];
let modelList = [];
let modelListData = [];
this.modelData.forEach((item) => {
modelData.push(item.code);
});
this.modelList.forEach((item) => {
modelList.push(item.code);
});
this.modelListData.forEach((item) => {
modelListData.push(item.code);
});
filtraArr = this.filtraArr;
}
// 4、根據(jù)選中得值跟 扁平化數(shù)據(jù)對(duì)比
if (filtraArr !== undefined && filtraArr !== null) {
let flatData = this.$store.state.user.cascaderData; // 扁平數(shù)據(jù)
let currentValue = filtraArr[0];
let currentNode = flatData.filter(
(item) => item.code === currentValue
)[0];
let parent = flatData.filter(
(item) => item.code === currentNode.parentCode
)[0];
let count = 1;
const deleteCodes = [];
if (parent !== undefined) {
deleteCodes.push(parent.code);
// 往上尋找
while (parent.level !== '1' && count < 10) {
parent = flatData.filter(
(item) => item.code === parent.parentCode
)[0];
deleteCodes.push(parent.code);
count++;
}
}
let childrenNodes = flatData.filter(
(item) => item.parentCode === currentValue
);
let childrenCodes = [];
childrenNodes.forEach((item) => {
childrenCodes.push(item.code);
});
while (childrenCodes.length > 0) {
const code = childrenCodes.shift();
deleteCodes.push(code);
const children = flatData.filter((item) => item.parentCode === code);
if (children.length > 0) {
children.forEach((item) => {
childrenCodes.push(item.code);
});
}
}
const modelArr = [];
const modelAller = [];
this.modelData.forEach((item) => {
modelAller.push(item.code);
});
modelAller.forEach((item) => {
let deleteState = deleteCodes.indexOf(item);
if (deleteState === -1) {
if (filtraArr[0] === item) {
modelArr.unshift(item);
} else {
modelArr.push(item);
}
}
});
let modelArrData = [];
modelArr.forEach((items) => {
let tree = flatData.filter((item) => item.code === items);
modelArrData.push({
code: tree[0].code,
name: tree[0].name
});
});
// // 設(shè)置select展示的label
this.selectShowLabel = modelArrData.map(
(node) => node[this.defaultProps.label]
);
// // // 更新model綁定值
let selectValueArray = modelArrData.map(
(node) => node[this.defaultProps.value]
);
this.$emit('changeChecked', selectValueArray);
} else if (this.modelData.length === 1) {
this.selectShowLabel = this.modelData.map(
(node) => node[this.defaultProps.label]
);
// // // 更新model綁定值
let selectValueArray = this.modelData.map(
(node) => node[this.defaultProps.value]
);
this.$emit('changeChecked', selectValueArray);
}
},
// 提供表單校驗(yàn)
dispatch(componentName, eventName, params) {
var parent = this.$parent || this.$root;
var name = parent.$options.componentName;
while (parent && (!name || name !== componentName)) {
parent = parent.$parent;
if (parent) {
name = parent.$options.componentName;
}
}
if (parent) {
parent.$emit.apply(parent, [eventName].concat(params));
}
}
}
};
</script>
<style lang="scss" scoped>
::v-deep .el-input .el-input__inner {
height: 34px;
line-height: 34px;
}
</style>
父組件調(diào)用文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-681321.html
<template>
<div id="app">
<selectTree v-model="address" placeholder="請(qǐng)選擇地址" :tree-data="mockData" />
</div>
</template>
<script>
import selectTree from './components/selectTree.vue'
export default {
name: 'App',
components: {
selectTree
},
data(){
return{
address:[],
mockData:[],// 樹(shù)形結(jié)構(gòu)數(shù)據(jù)
}
}
}
</script>
到了這里,關(guān)于Element-UI實(shí)現(xiàn)的下拉搜索樹(shù)組件(el-select、el-input、el-tree組合使用)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!