vue本地搜索-递归查询列表-封装树结构列表
tableSearch.vue-界面
<template>
<div class="container">
<div>
<SearchTree
style="flex: 1"
:dataList="treeData"
:isEdit="false"
:isSearch="true"
:isDrag="true"
v-show="!isShowInfo"
@treeSearch="treeSearch"
:treeProps="{
label: 'settingtypename',
children: 'seatTypeList',
}"
></SearchTree>
</div>
<div>
<!-- row-key="myID" 更换唯一标识 避免index或id有相同的,产生冲突 -->
<el-table
stripe
:data="tableData"
style="width: 100%; margin-bottom: 20px"
row-key="myID"
></el-table>
</div>
</div>
</template>
<script>
import SearchTree from "./SearchTree";
export default {
components: {
SearchTree,
},
data() {
return {
isShowwInfo: false,
tableDataMergeInfo: [],
};
},
created() {
var tableDataMerge = [];
var oneSeatPlan = {};
oneSeatPlan = this.tableDataResult;
tableDataMerge.push(oneSeatPlan);
this.recursion(tableDataMerge);
this.tableDataMergeInfo = tableDataMerge;
this.tableData = this.tableDataMergeInfo;
},
methods: {
// 递归添加字段
recursion(arr) {
arr.forEach((el) => {
let myID = Math.random().toString(36).substr(2);
this.$set(el, "myID", myID);
if (el.children && el.children.length) {
this.recursion(el.children);
}
});
},
// 递归搜索数据
recursion2(arr, filterWords) {
arr.forEach((el) => {
if (el.seattingtypename.includes(filterWords)) {
this.midellTreeArr.push(el);
return;
}
if (el.seatTypeList && el.seatTypeList.length) {
this.recursion2(el.seatTypeList, filterWords);
}
});
this.treeData = this.midellTreeArr;
},
treeSearch(val) {
if (!val) {
this.treeData = this.initTreeData;
return;
}
let filterData = [...this.initTreeData];
this.midellTreeArr = [];
console.log(this.initTreeData);
this.recursion2(filterData, val);
},
},
};
</script>
<style scoped lang="less">
// 树结构菜单
.search-tree-warp {
border-top: none;
box-sizing: border-box;
position: relative;
margin-top: 2vw;
margin-right: 2vw;
height: 53vh;
flex: 1;
}
</style>
SearchTree.vue-组件
<template>
<div class="search-tree-warp">
<slot></slot>
<div class="search-tree-title" v-if="title">{{ title }}</div>
<el-input
v-if="isSearch"
class="tree-search-input"
placeholder="请搜索相关内容"
size="mini"
suffix-icon="el-icon-search"
clearable
v-model="treeSearch"
></el-input>
<el-tree
:data="dataList"
:props="treeProps"
:filter-node-method="treeFilter"
:allow-drag="allowDrag"
:allow-drop="allowDrop"
:default-expanded-keys="myTreeExpandData"
highlight-current
node-key="id"
@node-drag-start="handleDragStart"
@node-click="handleNodeClick"
accordion
draggable
ref="tree"
:class="isSearch ? 'tree-heigth' : ''"
v-on="$listeners"
>
<span
class="train-class-tree"
slot-scope="{ node, data }"
@drop="handleDrop($event, node, data)"
>
<i class="tree-round"></i>
<i class="tree-my-icon" v-if="data.icon" :class="data.icon"></i>
<span>{{ node.label }}</span>
<div class="tree-btn-warp" v-if="isEdit">
<span
@click="editTree(data, node)"
class="el-icon-edit"
v-if="node.level != 1 || rootEdit"
></span>
<span @click="addTree(data, node)" class="el-icon-plus"></span>
<i
@click.stop="delTree(data, node)"
class="el-icon-minus"
v-if="node.level != 1|| rootEdit"
></i>
</div>
</span>
</el-tree>
</div>
</template>
<script>
export default {
name: "SearchTree",
props: {
isSearch: {
type: Boolean,
default: false,
},
treeProps: {
type: Object,
default: function () {
return {
label: "label",
children: "children",
};
},
},
isEdit: {
type: Boolean,
default: true,
},
isRootEdit: {
type: Boolean,
default: true,
},
rootEdit:{
type: Boolean,
default: false,
},
dataList: {
type: Array,
default: function () {
return [];
},
},
myTreeExpandData: {
type: Array,
default: function () {
return ["0"];
},
},
title: {
type: String,
default: "",
},
isDrop: {
type: Boolean,
default: false,
},
isDrag: {
type: Boolean,
default: false,
},
isDragRoot: {
type: Boolean,
default: true,
},
},
data() {
return {
treeSearch: "",
};
},
watch: {
treeSearch(val) {
this.$emit("treeSearch", val);
},
},
methods: {
/**
* 自定义按钮
*/
editTree(data, node) {
// this.myTreeExpandData = [];
// this.myTreeExpandData.push(data.id);
let subData = Object.assign({}, data);
this.$emit("editTree", subData);
},
addTree(data, node) {
this.$emit("addTree", data);
},
delTree(data, node) {
this.$confirm("是否要删除?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}).then(() => {
this.$emit("delTree", data, node);
});
},
// tree
treeFilter(value, data) {
if (!value) return true;
return data[this.treeProps.label].indexOf(value) !== -1;
},
allowDrag(node, ev) {
// ev.dataTransfer.setData("itemData", str);
if (this.isDragRoot) {
// 默认只能最底层节点拖拽
return this.isDrag && node.childNodes.length === 0;
} else {
return this.isDrag;
}
},
allowDrop(draggingNode, dropNode, type) {
return this.isDrop;
},
handleNodeClick(obj, dom, com) {
dom.expanded = true;
this.$emit("clickTree", obj, dom, com);
},
handleDragStart(node, ev) {
/* console.log(node)
console.log(ev) */
let str = JSON.stringify(node.data);
ev.dataTransfer.setData("itemData", str);
},
handleDrop(ev, node, dropData) {
if (!this.isDrop) {
this.$message({
message: "此处不能被放置",
type: "error",
});
return;
}
// console.log(789,)
let droped = false;
if (
this.$refs.tree.getCurrentNode() &&
this.$refs.tree.getCurrentNode().id == dropData.id
) {
droped = true;
}
this.$refs.tree.setCurrentNode(dropData);
let strData = ev.dataTransfer.getData("itemData");
let dragData = JSON.parse(strData);
this.$emit("drop", dragData, node, dropData,droped);
},
handleDragOver(node, dropNode, ev) {
ev.preventDefault();
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style lang="scss">
.search-tree-warp {
border-top: none;
box-sizing: border-box;
position: relative;
margin-top: 2vw;
margin-right: 2vw;
flex: 1;
.search-tree-title {
font-size: 14px;
color: #fff;
border-radius: 8px;
text-align: center;
margin-bottom: 20px;
}
/*搜索框*/
.tree-search-input {
margin: 0vw 0.39rem;
margin-bottom: 1vw;
width: calc(100% - 0.39rem - 8px);
box-sizing: border-box;
> input {
background-color: #104769;
border: solid 0.05vw #2685b3;
font-size: 0.14rem;
color: #fff;
&::-webkit-input-placeholder {
color: #82c5e8;
}
}
}
.is-current {
> .el-tree-node__content {
background-image: linear-gradient(
90deg,
rgba(38, 133, 179, 0),
rgba(38, 133, 179, 1),
rgba(38, 133, 179, 0)
) !important;
}
}
.el-tree {
width: 100%;
// position: absolute;
height: 100% !important;
overflow: auto;
background: transparent;
.el-tree-node__expand-icon {
margin-right: 5px;
}
&::-webkit-scrollbar-button {
display: none;
// background-image: url();
}
&::-webkit-scrollbar-track {
border-radius: 10px;
background-color: #184660;
}
.el-tree-node {
.el-icon-caret-right {
padding: 0px;
margin-left: 0.39rem;
}
.el-tree-node__content {
background-color: transparent !important;
padding: 20px;
&:hover {
background-image: linear-gradient(
90deg,
rgba(38, 133, 179, 0),
rgba(38, 133, 179, 1),
rgba(38, 133, 179, 0)
);
}
}
}
.el-tree-node__expand-icon {
color: #39baf8;
margin-right: 0.1rem;
}
.el-tree-node__expand-icon.is-leaf {
color: transparent !important;
}
div[role="group"] {
//非根节点
.tree-round {
display: none;
}
.tree-my-icon {
margin-right: 0.1rem;
display: inline-block;
}
.tree-btn-warp {
display: inline-block;
}
}
}
.tree-heigth {
height: calc(100% - 3vw - 60px) !important;
}
.train-class-tree {
font-size: 0.14rem;
color: #daf0fc;
display: flex;
align-items: center;
cursor: pointer;
padding: 0.12rem 0px;
/* 席位类别树形结构按钮包裹盒子 */
.tree-btn-warp {
margin-left: 0.1rem;
span {
color: #39baf8;
}
i {
color: #d9374e;
}
span,
i {
padding: 0px 0.05rem;
}
}
> .tree-round {
margin-right: 0.1rem;
}
.tree-round {
display: block;
width: 0.1rem;
height: 0.1rem;
background: #42cfaf;
border: 0.04rem solid #1c4f56;
border-radius: 50%;
}
}
}
</style>
效果图
1.1-搜索子级携带父级
1.2
2.1-搜索菜单组件
2.2