js uview实现下拉树选择器功能
效果:
TreePick是最后在页面内使用的弹窗组件,tree.vue是递归树
TreePick.vue
<template>
<view>
<u-popup :show="open" mode="bottom" round="20" @close="cancel">
<view class="tree-btn">
<u-button class="btn" text="取 消" size="mini" type="text" @click="cancel">
</u-button>
<span>树</span>
<u-button class="btn" text="确 定" size="mini" type="text" @click="submit"></u-button>
</view>
<scroll-view style="height: 400px; ">
<tree :data="data" @handler="handler" v-bind="$attrs" v-on="$listeners" :treeNode.sync="treeNode"
checkColor="#20A7B2">
</tree>
</scroll-view>
</u-popup>
</view>
</template>
<script>
import tree from './tree.vue';
export default {
name: 'TreePicker',
props: {
data: {
type: Array,
default: () => {
return [];
}
},
showModel: {
type: Boolean,
default: false
},
},
data() {
return {
treeNode: {},
originNode: {}
};
},
components: { tree },
computed: {
open: {
get() {
return this.showModel;
},
set(val) {
this.$emit('update:showModel', val);
}
}
},
watch: {
open: {
handler(val) {
if (val) {
this.originNode = JSON.parse(JSON.stringify(this.$store.state.treeNode))
this.initData(this.data, 0);
this.getLocation(this.data)
}
},
immediate: true,
deep: true
},
},
methods: {
close() {
this.open = false;
},
//初始化树,设置节点层级level
initData(data, plevel) {
data.forEach(item => {
if (item.pid == 0) item.level = 0;
else item.level = plevel + 1;
if (item.children && item.children.length) this.initData(item.children, item.level);
});
this.treeNode = JSON.stringify(this.treeNode) == "{}" ? data[0] : this.treeNode
},
handler(data) {
let { treeNode } = data
this.treeNode = treeNode;
},
//显示当前选中节点,其余折叠
getLocation(data) {
let target = this.$store.state.treeNode.ancestors ? this.$store.state.treeNode.ancestors.split(",") : []
data.forEach(e => {
if (target.includes(String(e.id))) e.isExpand = true
else e.isExpand = false
if (e.children && e.children.length) this.getLocation(e.children)
})
},
submit() {
this.originNode = this.treeNode
this.$emit('getTreeNode', this.treeNode);
this.close()
},
cancel() {
this.$emit('getTreeNode', this.originNode);
this.close()
}
}
};
</script>
<style lang="scss" scoped>
.tree-btn {
display: flex;
justify-content: space-between;
align-items: center;
padding: 5px 0;
.btn {
flex: 1;
}
span {
flex-grow: 3;
font-size: 9px;
text-align: center;
color: #000;
}
}
::v-deep .u-button--mini {
width: 15px;
}
::v-deep .u-button__text {
color: #7BACB0;
font-size: 9.16px !important;
font-weight: 500;
}
</style>
tree.vue
<template>
<view class=" tree" id="tree">
<view v-for="(item, index) in data" :key="index" style="padding: 2px 8px;">
<span class="tree-node" :style="{ 'padding-left': item.level * indent + 'px' }">
<u-icon name="arrow-right" size="14px" v-if="item.children && !item.isExpand"
@click="changeExpand(item, index)"></u-icon>
<u-icon name="arrow-down" size="14px" v-else-if="item.children && item.isExpand"
@click="changeExpand(item, index)"></u-icon>
<p class="node-span"
:style="{ color: node?(item.id == node.id ? checkColor : '#666'):'','margin-left':'8px' }"
@click="clickNode(item)" :class=" node?(item.id == node.id ? 'selected' : ''):'' ">
{{ item.name}}
</p>
</span>
<tree v-if="item.children && item.isExpand" :data="item.children" v-bind="$attrs" v-on="$listeners"
:class="item.isExpand ? 'dh' : ''" :label="label" :checkColor="checkColor" :indent="indent"
:treeNode="treeNode"></tree>
</view>
</view>
</template>
<script>
export default {
name: 'tree',
props: {
data: {
type: Array,
default: () => []
},
label: {
type: String,
default: () => "name"
},
indent: {
type: Number,
default: 4
},
checkColor: {
type: String,
default: "#3c9cff"
},
treeNode: {
type: Object
}
},
data() {
return {
windowHeight: 0
};
},
computed: {
node() {
return this.$store.state.treeNode;
}
},
methods: {
changeExpand(item, index) {
this.$nextTick(() => {
this.$set(item, 'isExpand', !item.isExpand);
this.$forceUpdate()
})
},
clickNode(item) {
this.$store.state.treeNode = item
this.$emit("handler", {
treeNode: item
})
},
}
};
</script>
<style lang="scss" scoped>
.tree-node {
font-size: 9.16px;
display: flex;
font-weight: 500;
overflow: hidden;
.node-span {
margin: 3px;
}
}
.selected {}
.tree {
animation: move 0.5s;
overflow: hidden;
padding: 0 10px;
}
.dh {
@keyframes move {
0% {
opacity: 0;
margin-top: -20px;
}
100% {
opacity: 1;
margin-top: 0px;
}
}
}
</style>