elementplus el-tree 二次封裝支持配置刪除后展示展開或折疊編輯復選框懶加載功能

本文介紹了基于 ElementPlus 的 el-tree 組件進行二次封裝的 TreeView 組件,使用 Vue3 和 JavaScript 實現。TreeView 組件通過 props 接收樹形數據、配置項等,支持懶加載、節點展開/收起、節點點擊、刪除、編輯等操作。組件內部通過 ref 管理樹實例,并提供了 clearCurrentNode、setCurrentKey、setExpandedKeys 等方法供父組件調用。renderContent 方法用于自定義節點內容,支持根據配置顯示刪除和編輯按鈕。事件處理函數通過 emit 將節點操作傳遞給父組件,實現了組件與父組件的交互。樣式部分通過 scoped 樣式隔離,確保組件樣式獨立。

準備組件 TreeView treeUtils方法

  1. TreeView組件
<template><div class="tree-container"><div v-if="isShowHeader" class="tree-header"><slot name="header"></slot></div><el-tree ref="treeRef" :data="treeData" :props="treeProps" highlight-current node-key="id":render-content="renderContent" :lazy="lazy" :load="lazy ? loadNode : undefined":default-expanded-keys="expandedKeys" :show-checkbox="showCheckbox" :check-strictly="checkStrictly"@node-click="handleNodeClick" @node-expand="handleNodeExpand" @node-collapse="handleNodeCollapse"@check="handleCheck" /></div>
</template><script setup>
import { defineProps, defineEmits, ref } from 'vue'
import { Delete, Edit } from '@element-plus/icons-vue'
import { handleNodeExpand as handleNodeExpandUtil, handleNodeCollapse as handleNodeCollapseUtil } from '@/utils/treeUtils'// 接收父組件傳來的數據
const props = defineProps({treeData: {type: Array,required: true,},treeProps: {type: Object,default: () => ({children: 'children',label: 'label',isLeaf: 'isLeaf'})},showDelete: {type: Boolean,default: false},showEdit: {type: Boolean,default: false},lazy: {type: Boolean,default: false},isShowHeader: {type: Boolean,default: false},showCheckbox: {type: Boolean,default: false},checkStrictly: {type: Boolean,default: false}
})
const applicationYear = ref('')// 接收父組件傳來的事件
const emit = defineEmits(['nodeClick', 'loadChildren', 'deleteNode', 'nodeExpand', 'nodeCollapse','check'
])// 使用props中的treeProps
const { treeProps } = props// 添加treeRef
const treeRef = ref(null)// 展開的節點keys
const expandedKeys = ref([])// 添加取消選中節點的方法
const clearCurrentNode = () => {if (treeRef.value) {treeRef.value.setCurrentKey(null)}
}// 設置當前選中的節點
const setCurrentKey = (key) => {if (treeRef.value) {treeRef.value.setCurrentKey(key)}
}// 設置展開的節點
const setExpandedKeys = (keys) => {expandedKeys.value = [...keys]
}// 獲取當前展開的節點
const getExpandedKeys = () => {return expandedKeys.value
}// 處理復選框選中事件
const handleCheck = (data, { checkedKeys, checkedNodes }) => {emit('check', {data,checkedKeys,checkedNodes})
}// 獲取選中的節點
const getCheckedKeys = () => {return treeRef.value?.getCheckedKeys() || []
}// 獲取半選中的節點
const getHalfCheckedKeys = () => {return treeRef.value?.getHalfCheckedKeys() || []
}// 設置選中的節點
const setCheckedKeys = (keys) => {treeRef.value?.setCheckedKeys(keys)
}// 暴露方法給父組件
defineExpose({clearCurrentNode,setCurrentKey,setExpandedKeys,getExpandedKeys,getCheckedKeys,getHalfCheckedKeys,setCheckedKeys
})const renderContent = (hFn, { node, data }) => {const content = [hFn('span', data[props.treeProps.label] || data.label)]// 根據showDelete配置決定是否顯示刪除按鈕if (props.showDelete) {content.push(hFn('el-button',{type: 'danger',size: 'small',class: 'delete-btn',onClick: () => handleDeleteNode(node, data),},[hFn(Delete)]))}// 根據showDelete配置決定是否顯示修改按鈕if (props.showEdit) {content.push(hFn('el-button',{type: 'danger',size: 'small',class: 'edit-btn',onClick: () => handleEditNode(data),},[hFn(Edit)]))}return hFn('div',{ class: 'tree-node' },content)
}// 加載子節點數據
const loadNode = (node, resolve) => {if (!props.lazy) {return resolve([])}if (node.level === 0) {// 根節點直接返回初始數據return resolve(props.treeData)}// 觸發父組件的事件來獲取子節點數據emit('loadChildren', {node,resolve: (children) => {// 確保children是數組const childNodes = Array.isArray(children) ? children : []// 將子節點數據設置到當前節點的children屬性中if (node.data) {node.data.children = childNodes}resolve(childNodes)}})
}// 處理節點點擊事件
const handleNodeClick = (data, node) => {emit('nodeClick', data)
}// 處理刪除節點事件
const handleDeleteNode = (node, data) => {emit('deleteNode', { node, data })
}// 處理修改節點事件
const handleEditNode = (nodeData) => {emit('editNode', nodeData)
}// 處理節點展開
const handleNodeExpand = (data, node) => {expandedKeys.value = handleNodeExpandUtil({data,node,expandedKeys: expandedKeys.value,onExpand: (data) => emit('nodeExpand', data)})
}// 處理節點收起
const handleNodeCollapse = (data, node) => {expandedKeys.value = handleNodeCollapseUtil({data,expandedKeys: expandedKeys.value,onCollapse: (data) => emit('nodeCollapse', data)})
}
</script><style scoped>
.tree-container {height: 100%;border: 1px solid #e4e7ed;padding: 10px;overflow: auto;
}::v-deep(.tree-node .delete-btn) {display: none !important;
}::v-deep(.tree-node .edit-btn) {display: none !important;
}::v-deep(.tree-node:hover) {color: skyblue;
}::v-deep(.tree-node:hover .delete-btn) {width: 14px;display: inline-block !important;color: red;margin-left: 5px;transform: translateY(2px);
}::v-deep(.tree-node:hover .edit-btn) {width: 14px;display: inline-block !important;color: rgb(17, 0, 255);margin-left: 5px;transform: translateY(2px);
}.tree-header {border-bottom: 1px solid #e4e7ed;margin-bottom: 10px;
}
</style>
  1. treeUtils.js文件
import { nextTick } from 'vue'/*** 處理樹節點展開* @param {Object} options 配置選項* @param {Object} options.data 節點數據* @param {Object} options.node 節點對象* @param {Array} options.expandedKeys 展開節點數組* @param {Function} options.onExpand 展開回調函數* @returns {Array} 更新后的展開節點數組*/
export const handleNodeExpand = ({data,node,expandedKeys,onExpand
}) => {// 如果節點ID不在展開數組中,則添加if (!expandedKeys.includes(data.id)) {expandedKeys.push(data.id)}// 確保父節點也保持展開狀態let parent = node.parentwhile (parent && parent.data && parent.data.id) {if (!expandedKeys.includes(parent.data.id)) {expandedKeys.push(parent.data.id)}parent = parent.parent}// 調用展開回調if (onExpand) {onExpand(data)}return expandedKeys
}/*** 處理樹節點收起* @param {Object} options 配置選項* @param {Object} options.data 節點數據* @param {Array} options.expandedKeys 展開節點數組* @param {Function} options.onCollapse 收起回調函數* @returns {Array} 更新后的展開節點數組*/
export const handleNodeCollapse = ({data,expandedKeys,onCollapse
}) => {// 從展開數組中移除節點IDconst index = expandedKeys.indexOf(data.id)if (index > -1) {expandedKeys.splice(index, 1)}// 調用收起回調if (onCollapse) {onCollapse(data)}return expandedKeys
}/*** 處理樹節點刪除后的展開狀態* @param {Object} options 配置選項* @param {Object} options.node 要刪除的節點* @param {Object} options.data 節點數據* @param {Array} options.treeData 樹數據* @param {Function} options.getExpandedKeys 獲取展開節點的方法* @param {Function} options.setExpandedKeys 設置展開節點的方法* @param {Function} options.clearCurrentNode 清除當前選中節點的方法* @returns {Promise<void>}*/
export const handleTreeDelete = async ({node,data,treeData,getExpandedKeys,setExpandedKeys,clearCurrentNode
}) => {const parent = node.parentconst children = parent.data.children || parent.dataconst index = children.findIndex((d) => d.id === data.id)// 獲取當前展開的節點const currentExpandedKeys = getExpandedKeys()// 刪除節點children.splice(index, 1)// 強制刷新treeDatatreeData.value = JSON.parse(JSON.stringify(treeData.value))// 重新設置展開狀態await nextTick()// 確保父節點保持展開狀態if (parent && parent.data && parent.data.id) {if (!currentExpandedKeys.includes(parent.data.id)) {currentExpandedKeys.push(parent.data.id)}}clearCurrentNode()setExpandedKeys(currentExpandedKeys)return currentExpandedKeys
} 

父組件使用

  1. 導入組件
import TreeView from '@/components/basicComponents/TreeView'
  1. 使用組件
<TreeView ref="treeViewRef":treeData="treeData" :treeProps="customTreeProps" :showDelete="true" :lazy="true":default-expanded-keys="expandedKeys"@nodeClick="handleNodeClick" @deleteNode="handleNodeDelete"@loadChildren="handleLoadChildren"@nodeExpand="handleNodeExpand"@nodeCollapse="handleNodeCollapse"/>
  1. 父組件里使用方法
// 定義treeViewRef
const treeViewRef = ref(null)
const treeData = ref([]) //樹數據
const expandedKeys = ref([]) // 添加展開節點的key數組
// 自定義樹形配置
const customTreeProps = {children: 'children',  // 子節點字段名label: 'label',        // 使用label字段作為顯示文本isLeaf: 'isLeaf'       // 是否為葉子節點字段名
}
const handleLoadChildren = async ({ node, resolve }) => {try {const children = await fetchTreeChildrenData(node.data.id)resolve(children)} catch (error) {console.error('加載子節點失敗:', error)resolve([]) // 加載失敗時返回空數組}
}
// 獲取樹子節點數據 懶加載 格式化數據
const fetchTreeChildrenData = async (id = '') => {const { data } = await getZhuangBeiCategory( id )const formattedChildren = data.map(item => ({id: item.id,label: item.label,  // 添加label字段isLeaf: item.sonNum > 0 ? false : true,  // 修正isLeaf的邏輯children: [] // 初始化為空數組,等待后續加載}))if(id) return formattedChildrentreeData.value = formattedChildren
}
//刪除子節點
const handleNodeDelete = ({node, data}) => {ElMessageBox.confirm(`<div style="text-align: center;">確定要刪除【${data.label}】嗎?</div>'提示',{dangerouslyUseHTMLString: true,confirmButtonText: '確定',cancelButtonText: '取消',type: 'warning',}).then(async() => {try{await deleteZhuangBeiCategory(data.id)ElMessage({  type: 'success',  message: '刪除成功!'})await handleTreeDelete({node,data,treeData,getExpandedKeys: () => treeViewRef.value.getExpandedKeys(),setExpandedKeys: (keys) => treeViewRef.value.setExpandedKeys(keys),clearCurrentNode: () => treeViewRef.value.clearCurrentNode()})}catch{ElMessage({  type: 'error',  message: '刪除失敗!'})}}).catch(() => {// 取消了,不做處理})
}
// 處理節點展開
const handleNodeExpand = (data) => {if (!expandedKeys.value.includes(data.id)) {expandedKeys.value.push(data.id)}
}// 處理節點收起
const handleNodeCollapse = (data) => {const index = expandedKeys.value.indexOf(data.id)if (index > -1) {expandedKeys.value.splice(index, 1)}
}// 處理節點點擊
const handleNodeClick = (nodeData) => {
}
  • 其他方法比如復選框,編輯不在示例,感興趣的可以去試試

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/81481.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/81481.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/81481.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

2025年滲透測試面試題總結-安恒[實習]安全工程師(題目+回答)

網絡安全領域各種資源&#xff0c;學習文檔&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各種好玩的項目及好用的工具&#xff0c;歡迎關注。 目錄 安恒[實習]安全工程師 一面 1. 自我介紹 2. 前兩段實習做了些什么 3. 中等難度的算法題 4. Java的C…

網絡編程中的直接內存與零拷貝

本篇文章會介紹 JDK 與 Linux 網絡編程中的直接內存與零拷貝的相關知識&#xff0c;最后還會介紹一下 Linux 系統與 JDK 對網絡通信的實現。 1、直接內存 所有的網絡通信和應用程序中&#xff08;任何語言&#xff09;&#xff0c;每個 TCP Socket 的內核中都有一個發送緩沖區…

TransmittableThreadLocal使用場景

&#x1f680; 為什么要用 TransmittableThreadLocal&#xff1f;一文讀懂線程上下文傳遞問題 在 Java Web 開發中&#xff0c;我們經常用 ThreadLocal 來保存每個請求的用戶信息&#xff0c;例如 userId。但當我們使用線程池或異步方法&#xff08;如 Async&#xff09;時&am…

Milvus(24):全文搜索、文本匹配

1 全文搜索 全文搜索是一種在文本數據集中檢索包含特定術語或短語的文檔&#xff0c;然后根據相關性對結果進行排序的功能。該功能克服了語義搜索的局限性&#xff08;語義搜索可能會忽略精確的術語&#xff09;&#xff0c;確保您獲得最準確且與上下文最相關的結果。此外&…

2000 元以下罕見的真三色光源投影儀:雷克賽恩Cyber Pro1重新定義入門級投影體驗

當性價比遇上技術瓶頸 在 2000元以下的1080P投影儀&#xff0c;單LCD 技術長期主導。而三色光源的DLP和3LCD真1080P都在4000元以上。 單LCD投影為純白光光源&#xff0c;依賴CF濾光膜導致光效低下&#xff0c;普遍存在" 色彩失真 " 等問題。數據顯示&#xff0c;該價…

Maven 下載安裝與配置教程

## 1. Maven 簡介 Maven 是一個項目管理和構建自動化工具&#xff0c;主要用于 Java 項目。Maven 可以幫助開發者管理項目的構建、報告和文檔&#xff0c;簡化項目依賴管理。 ## 2. 下載 Maven 1. 訪問 Maven 官方網站 [https://maven.apache.org/download.cgi](https://maven.…

C# 深入理解類(從類的外部訪問靜態成員)

從類的外部訪問靜態成員 在前一章中&#xff0c;我們看到使用點運算符可以從類的外部訪問public實例成員。點運算符由實 例名、點和成員名組成。 就像實例成員&#xff0c;靜態成員也可以使用點運算符從類的外部訪問。但因為沒有實例&#xff0c;所以最常 用的訪問靜態成員的方…

Java在微服務架構中的最佳實踐:從設計到部署

在2025年的云計算和分布式系統時代&#xff0c;微服務架構已成為構建高可擴展、高可用系統的標準方法&#xff0c;廣泛應用于電商、金融和物聯網等領域。Java憑借其成熟的生態系統、強大的并發支持和跨平臺能力&#xff0c;是微服務開發的首選語言。例如&#xff0c;我們的訂單…

文件讀取漏洞路徑與防御總結

文件讀取漏洞路徑與防御總結 文件讀取漏洞允許攻擊者通過路徑遍歷等手段訪問未授權的文件。以下是Linux和Windows系統中常見敏感路徑的歸納及防御建議&#xff1a; Linux 系統常見敏感路徑 系統關鍵文件&#xff1a; /etc/passwd&#xff1a;用戶賬戶信息&#xff08;可被用來…

react-router基本寫法

1. 創建項目并安裝所有依賴 npx create-react-app react-router-pro npm i 2. 安裝所有的 react router 包 npm i react-router-dom 3. 啟動項目 npm run start router/index.js // 創建路由實例 綁定path elementimport Layout from "/pages/Layout"; import…

uni-app 開發HarmonyOS的鴻蒙影視項目分享:從實戰案例到開源后臺

最近&#xff0c;HBuilderX 新版本發布&#xff0c;帶來了令人興奮的消息——uni-app 現在支持 Harmony Next 平臺的 App 開發。這對于開發者來說無疑是一個巨大的福音&#xff0c;意味著使用熟悉的 Vue 3 語法和開發框架&#xff0c;就可以為鴻蒙生態貢獻自己的力量。 前言 作…

純css實現蜂窩效果

<!DOCTYPE html><html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>蜂窩效果</title><style>body {margin: 0…

JAVA EE_HTTP

為什么意氣風發的少年&#xff0c;總是聽不進去別人的勸解。 ??????? ??????? ----------陳長生. ?主頁&#xff1a;陳長生.-CSDN博客? &#x1f4d5;上一篇&#xff1a;JAVA EE_網絡原理_數據鏈路層-CSDN博客 1.HTTP 1.1.HTTP是什么 H…

存儲扇區分配表:NAND Flash與SD NAND(貼片式SD卡)的架構差異

NAND Flash 和 SD 卡&#xff08;SD NAND&#xff09;的存儲扇區分配表在原理上有相似之處&#xff0c;但由于二者的結構和應用場景不同&#xff0c;也存在一些差異。 相同點&#xff1a; 基本功能&#xff1a;NAND Flash 和 SD 卡&#xff08;SD NAND&#xff09;的存儲扇區分…

界面控件DevExpress WinForms中文教程:Banded Grid View - API

DevExpress WinForms擁有180組件和UI庫&#xff0c;能為Windows Forms平臺創建具有影響力的業務解決方案。DevExpress WinForms能完美構建流暢、美觀且易于使用的應用程序&#xff0c;無論是Office風格的界面&#xff0c;還是分析處理大批量的業務數據&#xff0c;它都能輕松勝…

4G物聯網模塊實現廢氣處理全流程數據可視化監控配置

一、項目背景 隨著工業化進程的加速&#xff0c;工業廢氣的排放對環境造成了嚴重影響&#xff0c;廢氣處理廠應運而生。然而&#xff0c;廢氣處理廠中的設備眾多且分散&#xff0c;傳統的人工巡檢和數據記錄方式效率低下&#xff0c;難以及時發現問題。為了實現對廢氣處理設備…

Kubernetes控制平面組件:Kubelet詳解(四):gRPC 與 CRI gRPC實現

云原生學習路線導航頁&#xff08;持續更新中&#xff09; kubernetes學習系列快捷鏈接 Kubernetes架構原則和對象設計&#xff08;一&#xff09;Kubernetes架構原則和對象設計&#xff08;二&#xff09;Kubernetes架構原則和對象設計&#xff08;三&#xff09;Kubernetes控…

【數據結構】線性表--隊列

【數據結構】線性表--隊列 一.什么是隊列二.隊列的實現1.隊列結構定義&#xff1a;2.隊列初始化函數&#xff1a;3.隊列銷毀函數&#xff1a;4.入隊列函數&#xff08;尾插&#xff09;&#xff1a;5.出隊列函數&#xff08;頭刪&#xff09;&#xff1a;6.取隊頭元素&#xff…

C語言—再學習(結構體)

一、建立結構體 用戶自己建立由不同類型數據組成的組合型的數據結構&#xff0c;它稱為結構體。 struct Student { int num; //學號char name[20]; //名字為字符串char sex; //性別int age; //年紀float score; //分數char addr[30]; 地址為字符…

【前端基礎】10、CSS的偽元素(::first-line、::first-letter、::before、::after)【注:極簡描述】

一、偽元素的作用 選取某個特定的元素。 二、::first-line、::first-letter ::first-line&#xff1a;針對首行文本設置屬性 ::first-letter&#xff1a;針對首字母設置屬性 三、::before、::after 在一個元素之前&#xff08;::before&#xff09;或者之后&#xff08;…