<!--
? ? /**
? ? * 樹形下拉選擇組件傀顾,下拉框展示樹形結(jié)構(gòu),提供選擇某節(jié)點(diǎn)功能薄货,方便其他模塊調(diào)用
? ? * @author sxy https://bysjb.cn
? ? * @date 2020-12-02
? ? */
-->
<template>
? <div>
? ? <div v-show="isShowSelect" class="mask" @click="isShowSelect = !isShowSelect" />
? ? <el-popover
? ? ? v-model="isShowSelect"
? ? ? placement="bottom-start"
? ? ? :width="width"
? ? ? trigger="manual"
? ? ? style="padding: 12px 0;"
? ? ? @hide="popoverHide"
? ? >
? ? ? <el-tree
? ? ? ? ref="tree"
? ? ? ? class="common-tree"
? ? ? ? :style="style"
? ? ? ? :data="data"
? ? ? ? :props="defaultProps"
? ? ? ? :show-checkbox="multiple"
? ? ? ? :node-key="nodeKey"
? ? ? ? :check-strictly="checkStrictly"
? ? ? ? default-expand-all
? ? ? ? :expand-on-click-node="false"
? ? ? ? :check-on-click-node="multiple"
? ? ? ? :highlight-current="true"
? ? ? ? @node-click="handleNodeClick"
? ? ? ? @check-change="handleCheckChange"
? ? ? />
? ? ? <el-select
? ? ? ? slot="reference"
? ? ? ? ref="select"
? ? ? ? v-model="selectedData"
? ? ? ? :style="selectStyle"
? ? ? ? :size="size"
? ? ? ? :multiple="multiple"
? ? ? ? :clearable="clearable"
? ? ? ? :collapse-tags="collapseTags"
? ? ? ? class="tree-select"
? ? ? ? @click.native="isShowSelect = !isShowSelect"
? ? ? ? @remove-tag="removeSelectedNodes"
? ? ? ? @clear="removeSelectedNode"
? ? ? ? @change="changeSelectedNodes"
? ? ? >
? ? ? ? <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
? ? ? </el-select>
? ? </el-popover>
? </div>
</template>
<script>
export default {
? props: {
? ? // 樹結(jié)構(gòu)數(shù)據(jù)
? ? data: {
? ? ? type: Array,
? ? ? default() {
? ? ? ? return []
? ? ? }
? ? },
? ? defaultProps: {
? ? ? type: Object,
? ? ? default() {
? ? ? ? return {
? ? ? ? ? children: 'children',
? ? ? ? ? label: 'name'
? ? ? ? }
? ? ? }
? ? },
? ? // 配置是否可多選
? ? multiple: {
? ? ? type: Boolean,
? ? ? default() {
? ? ? ? return false
? ? ? }
? ? },
? ? // 配置是否可清空選擇
? ? clearable: {
? ? ? type: Boolean,
? ? ? default() {
? ? ? ? return false
? ? ? }
? ? },
? ? // 配置多選時(shí)是否將選中值按文字的形式展示
? ? collapseTags: {
? ? ? type: Boolean,
? ? ? default() {
? ? ? ? return false
? ? ? }
? ? },
? ? nodeKey: {
? ? ? type: String,
? ? ? default() {
? ? ? ? return 'id'
? ? ? }
? ? },
? ? // 顯示復(fù)選框情況下翁都,是否嚴(yán)格遵循父子不互相關(guān)聯(lián)
? ? checkStrictly: {
? ? ? type: Boolean,
? ? ? default() {
? ? ? ? return false
? ? ? }
? ? },
? ? // 默認(rèn)選中的節(jié)點(diǎn)key數(shù)組
? ? checkedKeys: {
? ? ? type: Array,
? ? ? default() {
? ? ? ? return []
? ? ? }
? ? },
? ? size: {
? ? ? type: String,
? ? ? default() {
? ? ? ? return 'medium'
? ? ? }
? ? },
? ? width: {
? ? ? type: Number,
? ? ? default() {
? ? ? ? return 250
? ? ? }
? ? },
? ? height: {
? ? ? type: Number,
? ? ? default() {
? ? ? ? return 300
? ? ? }
? ? }
? },
? data() {
? ? return {
? ? ? isShowSelect: false, // 是否顯示樹狀選擇器
? ? ? options: [],
? ? ? selectedData: [], // 選中的節(jié)點(diǎn)
? ? ? style: 'width:' + (this.width - 24) + 'px;' + 'height:' + this.height + 'px;',
? ? ? selectStyle: 'width:' + (this.width + 24) + 'px;',
? ? ? checkedIds: [],
? ? ? checkedData: []
? ? }
? },
? watch: {
? ? isShowSelect(val) {
? ? ? // 隱藏select自帶的下拉框
? ? ? this.$refs.select.blur()
? ? },
? ? checkedKeys(val) {
? ? ? console.log('checkedKeys', val)
? ? ? if (!val) return
? ? ? this.checkedKeys = val
? ? ? this.initCheckedData()
? ? }
? },
? mounted() {
? ? this.initCheckedData()
? },
? methods: {
? ? // 單選時(shí)點(diǎn)擊tree節(jié)點(diǎn),設(shè)置select選項(xiàng)
? ? setSelectOption(node) {
? ? ? const tmpMap = {}
? ? ? tmpMap.value = node.key
? ? ? tmpMap.label = node.label
? ? ? this.options = []
? ? ? this.options.push(tmpMap)
? ? ? this.selectedData = node.key
? ? },
? ? // 單選菲驴,選中傳進(jìn)來的節(jié)點(diǎn)
? ? checkSelectedNode(checkedKeys) {
? ? ? var item = checkedKeys[0]
? ? ? this.$refs.tree.setCurrentKey(item)
? ? ? var node = this.$refs.tree.getNode(item)
? ? ? this.setSelectOption(node)
? ? },
? ? // 多選荐吵,勾選上傳進(jìn)來的節(jié)點(diǎn)
? ? checkSelectedNodes(checkedKeys) {
? ? ? // this.$refs.tree.setCheckedKeys(checkedKeys)
? ? ? // 優(yōu)化select回顯顯示 有個(gè)延遲的效果
? ? ? const that = this
? ? ? setTimeout(function() {
? ? ? ? that.$refs.tree.setCheckedKeys(checkedKeys)
? ? ? }, 10)
? ? ? // console.log('checkSelectedNodes', checkedKeys, this.selectedData)
? ? },
? ? // 單選,清空選中
? ? clearSelectedNode() {
? ? ? this.selectedData = []
? ? ? this.$refs.tree.setCurrentKey(null)
? ? },
? ? // 多選赊瞬,清空所有勾選
? ? clearSelectedNodes() {
? ? ? var checkedKeys = this.$refs.tree.getCheckedKeys() // 所有被選中的節(jié)點(diǎn)的 key 所組成的數(shù)組數(shù)據(jù)
? ? ? for (let i = 0; i < checkedKeys.length; i++) {
? ? ? ? this.$refs.tree.setChecked(checkedKeys[i], false)
? ? ? }
? ? },
? ? initCheckedData() {
? ? ? if (this.multiple) {
? ? ? ? // 多選
? ? ? ? // console.log(this.checkedKeys.length)
? ? ? ? if (this.checkedKeys.length > 0) {
? ? ? ? ? this.checkSelectedNodes(this.checkedKeys)
? ? ? ? } else {
? ? ? ? ? this.clearSelectedNodes()
? ? ? ? }
? ? ? } else {
? ? ? ? // 單選
? ? ? ? if (this.checkedKeys.length > 0) {
? ? ? ? ? this.checkSelectedNode(this.checkedKeys)
? ? ? ? } else {
? ? ? ? ? this.clearSelectedNode()
? ? ? ? }
? ? ? }
? ? },
? ? popoverHide() {
? ? ? if (this.multiple) {
? ? ? ? this.checkedIds = this.$refs.tree.getCheckedKeys() // 所有被選中的節(jié)點(diǎn)的 key 所組成的數(shù)組數(shù)據(jù)
? ? ? ? this.checkedData = this.$refs.tree.getCheckedNodes() // 所有被選中的節(jié)點(diǎn)所組成的數(shù)組數(shù)據(jù)
? ? ? } else {
? ? ? ? this.checkedIds = this.$refs.tree.getCurrentKey()
? ? ? ? this.checkedData = this.$refs.tree.getCurrentNode()
? ? ? }
? ? ? this.$emit('popoverHide', this.checkedIds, this.checkedData)
? ? },
? ? // 單選先煎,節(jié)點(diǎn)被點(diǎn)擊時(shí)的回調(diào),返回被點(diǎn)擊的節(jié)點(diǎn)數(shù)據(jù)
? ? handleNodeClick(data, node) {
? ? ? if (!this.multiple) {
? ? ? ? this.setSelectOption(node)
? ? ? ? this.isShowSelect = !this.isShowSelect
? ? ? ? this.$emit('change', this.selectedData)
? ? ? }
? ? },
? ? // 多選,節(jié)點(diǎn)勾選狀態(tài)發(fā)生變化時(shí)的回調(diào)
? ? handleCheckChange() {
? ? ? var checkedKeys = this.$refs.tree.getCheckedKeys() // 所有被選中的節(jié)點(diǎn)的 key 所組成的數(shù)組數(shù)據(jù)
? ? ? // console.log('handleCheckChange', checkedKeys)
? ? ? this.options = checkedKeys.map((item) => {
? ? ? ? var node = this.$refs.tree.getNode(item) // 所有被選中的節(jié)點(diǎn)對(duì)應(yīng)的node
? ? ? ? const tmpMap = {}
? ? ? ? tmpMap.value = node.key
? ? ? ? tmpMap.label = node.label
? ? ? ? return tmpMap
? ? ? })
? ? ? this.selectedData = this.options.map((item) => {
? ? ? ? return item.value
? ? ? })
? ? ? this.$emit('change', this.selectedData)
? ? },
? ? // 多選,刪除任一select選項(xiàng)的回調(diào)
? ? removeSelectedNodes(val) {
? ? ? this.$refs.tree.setChecked(val, false)
? ? ? var node = this.$refs.tree.getNode(val)
? ? ? if (!this.checkStrictly && node.childNodes.length > 0) {
? ? ? ? this.treeToList(node).map(item => {
? ? ? ? ? if (item.childNodes.length <= 0) {
? ? ? ? ? ? this.$refs.tree.setChecked(item, false)
? ? ? ? ? }
? ? ? ? })
? ? ? ? this.handleCheckChange()
? ? ? }
? ? ? this.$emit('change', this.selectedData)
? ? },
? ? treeToList(tree) {
? ? ? var queen = []
? ? ? var out = []
? ? ? queen = queen.concat(tree)
? ? ? while (queen.length) {
? ? ? ? var first = queen.shift()
? ? ? ? if (first.childNodes) {
? ? ? ? ? queen = queen.concat(first.childNodes)
? ? ? ? }
? ? ? ? out.push(first)
? ? ? }
? ? ? return out
? ? },
? ? // 單選,清空select輸入框的回調(diào)
? ? removeSelectedNode() {
? ? ? this.clearSelectedNode()
? ? ? this.$emit('change', this.selectedData)
? ? },
? ? // 選中的select選項(xiàng)改變的回調(diào)
? ? changeSelectedNodes(selectedData) {
? ? ? // 多選,清空select輸入框時(shí)巧涧,清除樹勾選
? ? ? if (this.multiple && selectedData.length <= 0) {
? ? ? ? this.clearSelectedNodes()
? ? ? }
? ? ? this.$emit('change', this.selectedData)
? ? }
? }
}
</script>
<style scoped>
? .mask {
? ? width: 100%;
? ? height: 100%;
? ? position: fixed;
? ? top: 0;
? ? left: 0;
? ? opacity: 0;
? ? z-index: 11;
? }
? .common-tree {
? ? overflow: auto;
? }
? .tree-select {
? ? z-index: 111;
? }
</style>