Bootstrap

elementPlus vue3 树滑动显示增删且改写节点为下拉框

elementPlus 树滑动显示增删且改写节点为下拉框

需求:鼠标滑过树节点 显示增删改按钮,且可改选值,节点为下拉框
效果图:
在这里插入图片描述
在这里插入图片描述

改写为下拉框的思路:

因为el-option展开只能依靠el-select 所以不可以把el-option单独提出来 只能当点击下拉框小按钮的时候把原来树节点的span标签替换为下拉框标签 然后让下拉框自动展开 后改写下拉框的样式

附上完整代码:

<template>
    <el-tree 
        :allow-drop="allowDrop" 
        :allow-drag="allowDrag" 
        :data="dataSource" 
        draggable 
        default-expand-all 
        node-key="id" 
        ref="one" 
        highlight-current
        :expand-on-click-node="false"
    >
        <template #default="{ node, data }">
            <span class="custom-tree-node" @mouseleave="mouseLeave(data)">
                <span class="treeLabel" @mouseenter="mouseEnter(data)" v-if="!data.isSelect">{{ data.label }}</span>
                <el-select
                    v-if="data.isSelect"
                    v-model="data.optionValue"
                    :teleported="true"
                    size="small"
                    ref="selectRef"
                    class="selectClass"
                    @change="selectChange($event,data)"
                    @visible-change="selectVisibleChange($event,data)"
                    suffix-icon="none"
                    popper-class="optionClass"
                    :fit-input-width="false"
                >
                    <el-option id="selectOption"
                        v-for="item in options"
                        :key="item.value"
                        :label="item.label"
                        :value="item.value"
                    >
                        <span>{{item.label}}</span>
                    </el-option>
                </el-select>
                <span @click="chooseIcon(data,node)"><el-icon><ArrowDown /></el-icon></span>
                <span class="textLink" v-if="data.isHover">
                    <a @click.stop="append(data)"><el-icon color="#3E5ECD"><CirclePlus /></el-icon></a>
                    <a style="margin-left: 8px" @click.stop="remove(node, data)"> <el-icon color="#3E5ECD"><Delete /></el-icon> </a>
                </span>
            </span>
        </template>
    </el-tree> 
</template>
<script lang='ts'>
import { defineComponent, reactive, ref, nextTick, onMounted } from 'vue'
import type Node from 'element-plus/es/components/tree/src/model/node'
import type { NodeDropType } from 'element-plus/es/components/tree/src/tree.type'
import { ElSelect, ElTree } from 'element-plus'
import  treeData  from '@/utils/treeData'
export default defineComponent({
    name: 'oneFour',
    setup() {
        interface Tree {
            id: number
            label: string
            children?: Tree[]
        }
        let one = ref<InstanceType<typeof ElTree>>()
        let selectRef = ref<InstanceType<typeof ElSelect>>()
        const allowDrop = (draggingNode: Node, dropNode: Node, type: NodeDropType) => {
            return false
        }
        const allowDrag = (draggingNode: Node) => {
            return true
        }
        const append = (data: Tree) => {
            const newChild = { id: num++, label: 'node', children: [] }
            if (!data.children) {
                data.children = []
            }
            data.children.push(newChild)
            dataSource.value = [...dataSource.value]
        }
        const remove = (node: Node, data: Tree) => {
            const parent = node.parent
            const children: Tree[] = parent.data.children || parent.data
            const index = children.findIndex((d) => d.id === data.id)
            children.splice(index, 1)
            dataSource.value = [...dataSource.value]
        }
        const dataSource = ref(treeData)
        let num:number = 100
        const mapData = (data:any)=>{
            for(let i in data){
                let element = data[i]
                element.id = num++
                element.isHover = false;
                element.isSelect = false;
                element.optionValue = element.label;
                mapData(element.children)
            }
        }
        const mouseLeave = (data:any)=>{
            data.isHover = false
        }
        const mouseEnter = (data:any)=>{
            data.isHover = true
        }
        const options = ref([
            {
                label:'大米饭',
                value:'001'
            },
            {
                label:'小米饭',
                value:'002'
            },
            {
                label:'玉米饭',
                value:'003'
            },
            {
                label:'糙米饭',
                value:'004'
            }
        ])
        const chooseIcon = (data:any,node:any)=>{
            data.isSelect = true;
            nextTick(()=>{
                selectRef.value!.toggleMenu()
            })
        }
        const selectChange = (val:any,data:any)=>{
            let s = options.value.filter((d:any)=>d.value == val)
            data.label = s[0].label;
            data.selectOption = val;
            data.isSelect = false
        }
        const selectVisibleChange = (val:any,data:any)=>{
            if(val == false){
                data.isSelect = false
            }
        }
        onMounted(()=>{
            mapData(dataSource.value)   
        })
        return {
			allowDrop,
			allowDrag,
			dataSource,
            append,
            remove,
            mouseEnter,
            mouseLeave,
            chooseIcon,
            selectChange,
            selectVisibleChange,
            options,
            selectRef
        }
    }
})
</script>
<style scoped>
.custom-tree-node {
  flex: 1;
  display: flex;
  align-items: center;
  font-size: 14px;
  padding-right: 8px;
}
.textLink{
    margin-left: 10%;
    color: #3E5ECD;
}
.treeLabel{
    margin-right: 20px;
}
.selectClass{
    width: 50%;
    --el-select-input-focus-border-color:transparent !important;
    --el-input-bg-color:transparent !important;
}
.selectClass :deep(.el-select .el-input.isfocus .el-input__wrapper){
    box-shadow: none !important;
    background-color: transparent !important;
}
.selectClass :deep(.el-select){
    --el-select-input-focus-border-color:transparent !important;
    --el-input-bg-color:transparent !important;
}
.selectClass :deep(.el-input__wrapper){
    background-color: transparent !important;
}
.selectClass :deep(.el-input__inner){
    color: #606266 !important;
    font-weight: 600;
    font-size: 14px !important;
}
.selectClass :deep(.el-input__suffix-inner){
   display: none !important;
}
.selectClass :deep(.el-select-dropdown__item){
   padding:0 10px !important;
}
.selectClass :deep(.el-select-dropdown optionClass){
   min-width: 100px !important;
}
</style>  

俺的项目链接 可参考:https://gitee.com/sydsdz/vue3_element-plus_ts

;