uni-app用css編寫族譜樹家譜樹

需求背景:公司接到一個項目,是需要做一個族譜微信小程序,需要有族譜樹,且可以添加家族人員。

靈感來源:在插件市場中下載了作者 羊羊不想寫代碼 的插件tree-list族譜,樹形列表,可縮放滑動 - DCloud 插件市場,根據作者的代碼邏輯增加了橫向的樹結構,使用簡單。

父組件引用:(數據在用的時候從后端請求)

<template><view class=""><view class="switch-btn" @click="switchRow">{{switchName}}</view><!-- 人物關系圖 --><template><view class="genealogy-tree"><movable-area :style="{height: '100vh',width: '100vw'}"><movable-view @scale="changeScale" :scale="true" :scale-max="1" :scale-min="0.5" class="max" direction="all":style="{width: `${treeConfig.width}px`,height: `${treeConfig.height}px`}"><div class="tree-content"><columnTreeList v-if="switchName == '豎向'" :tree-data="treeData" :tree-first="true" /><rowTreeList v-else :tree-data="treeData" :tree-first="true" /></div></movable-view></movable-area></view></template></view>
</template><script setup>import {ref,provide,nextTick,watch,getCurrentInstance,onMounted} from 'vue';import columnTreeList from '@/components/column-tree-list.vue'import rowTreeList from '@/components/row-tree-list.vue';const switchName = ref('橫向')let scale = ref(1); // 縮放倍率const instance = getCurrentInstance(); // 獲取組件實例let treeConfig = ref({ // movable-view移動區域大小width: 0,height: 800})/*** 獲取元素信息* @param {String} domID dom元素id* */const getDomInfo = (domID) => {return new Promise((resolve, reject) => {const bar = uni.createSelectorQuery().in(instance);bar.select(domID).boundingClientRect(res => {if (res) resolve(res);else reject()}).exec();})}// 樹形結構數據let treeData = ref([{id: 1,name: '祖宗',child: [{id: 2,name: '爺爺',spouse: {id: 2001,name: '奶奶',},child: [{id: 3,name: '父親',spouse: {id: 3001,name: '媽媽',},child: [{id: 4,name: '自己',},{id: 9,name: '妹妹',}]},{id: 5,name: '二伯',},]},{id: 6,name: '二大爺',child: [{id: 7,name: '大叔',},{id: 8,name: '二叔',},]}]}])// 刪除provide('delItem', (item) => {treeData.value = deleteNodeById(treeData.value, item.id);})/*** 添加子級* @param { object } item 當前點擊的對象* */provide('addItem', (item) => {const data = {id: Math.floor(Math.random() * 1000), // 唯一鍵后續自行設置name: '新增子級',}handleData(item.id, treeData.value, data, 1)})/*** 添加配偶* @param { object } item 當前點擊的對象* */provide('addSpouse', (item) => {console.log(31231, item);const data = {id: Math.floor(Math.random() * 100), // 唯一鍵后續自行設置name: '配偶',}handleData(item.id, treeData.value, data, 2)})/*** 遞歸對樹形結構添加節點* @param {number | string} id 唯一鍵* @param { Array } 樹形結構數組* @param { Object } obj 添加的數據 {id,name,...}* @param { number } type 添加的類型 1:子級,2:配偶* */const handleData = (id, data, obj, type) => {data.forEach(item => {if (item.id === id) {// 在這里處理新增子級還是配偶if (type === 1) {item.child ? item.child.push(obj) : item.child = [obj]} else if (type === 2) {// 如果存在配偶這里賦值將進行替換// 如需多配偶需自行改為數組形式(tree-list里的spouse也需要同步修改為數組)item.spouse = obj;}} else {if (item.child) {handleData(id, item.child, obj, type)}}})return data}/*** 遞歸刪除樹形結構元素* @param { Array } tree 樹形結構數據* @param { number | string } id 唯一鍵* */const deleteNodeById = (tree, targetId) => {for (let i = 0; i < tree.length; i++) {const node = tree[i];if (node.id === targetId) {console.log('找到了', node);// 使用 splice 刪除節點tree.splice(i, 1);return tree; // 返回新的數組}if (node.child && node.child.length > 0) {// 遞歸查找子節點node.child = deleteNodeById(node.child, targetId);}}return tree; // 沒有找到目標節點,返回原數組}// 設置移動縮放大小const setTreeConfig = () => {nextTick(() => {setTimeout(() => {getDomInfo('.tree-content').then(res => {treeConfig.value = {width: res.width / scale.value,height: res.height / scale.value}console.log('返回值',res);})}, 200)})}const changeScale = (e) => {scale.value = e.detail.scale;console.log('縮放',e.detail)}// 轉換const switchRow = () => {switchName.value = switchName.value == '橫向' ? '豎向' : '橫向'}// 監聽樹形結構數據變化watch(treeData.value, (newVal, oldVal) => {setTreeConfig()})onMounted(() => {setTreeConfig()})
</script><style lang="scss" scoped>.genealogy-tree {min-height: 100%;min-width: 100vw;position: relative;overflow-x: scroll;// overflow: hidden;.tree-content {position: absolute;top: 0;left: 0;transition: all .3s;}}::v-deep .uni-table-th {color: #000 !important;}::v-deep .uni-table-td {color: #000 !important;}.th-bg {background-color: #d9d9d9;}.switch-btn {position: fixed;top: 30rpx;right: 30rpx;height: 50rpx;width: 100rpx;border-radius: 20rpx;background-color: #f8f8f8;box-shadow: 0 6rpx 0rpx 4rpx #00000080;font-size: 20rpx;line-height: 50rpx;text-align: center;z-index: 99;}
</style>

子組件:子組件自我遞歸調用(原作者代碼---豎向樹結構)

<template><view class="card"><view class="ul"><view class="li" v-for="(item,index) in treeData" :key="index"><view class="item" :class="{'line-left': index !== 0, 'line-right': index != treeData.length - 1}"><view class="item-name" :class="{'line-bottom':item.child && item.child.length > 0,'line-top':!treeFirst}"><view class="content"><image src="@/static/logo.png" mode="widthFix" style="width: 40rpx;height: auto;border-radius: 50%;"></image><text class="name">{{item.name}}</text><button class="btn" @click="addItem(item)">添加子級</button><button class="btn" @click="addSpouse(item)">添加配偶</button><button class="btn" @click="delItem(item)">刪除當前</button></view><!-- 配偶 --><view class="content-2" v-if="item.spouse"><image src="@/static/logo.png" mode="widthFix" style="width: 40rpx;height: auto;border-radius: 50%;"></image><text class="name">{{item.spouse.name}}</text></view></view></view><column-tree-list v-if="item.child && item.child.length > 0" :tree-data="item.child"></column-tree-list></view></view></view>
</template><script setup name="column-tree-list">import columnTreeList from '@/components/column-tree-list.vue'import {inject} from 'vue'const delItem = inject('delItem')const addItem = inject('addItem')const addSpouse = inject('addSpouse')defineProps(['treeData', 'treeFirst'])
</script><style lang="scss" scoped>$line-length: 20px; //線長$spacing: 20px; //間距$extend: calc(#{$spacing}); //延長線// 線樣式@mixin line {content: "";display: block;width: 1px;height: $line-length;position: absolute;left: 0;right: 0;margin: auto;background: #e43934;}.card {.ul {display: flex;justify-content: center;.li {.item {display: flex;justify-content: center;align-items: center;position: relative;&-name {position: relative;display: flex;justify-content: center;align-items: center;margin: $spacing 10rpx;.content,.content-2 {display: flex;flex-direction: column;align-items: center;background: #fff;padding: 20rpx;border-radius: 16rpx;box-sizing: border-box;box-shadow: 0px 5rpx 30rpx 5rpx rgba(0, 0, 0, 0.08);.name {margin: 10rpx 0 18rpx;color: #222;font-size: 20rpx;}}.content-2 {display: flex;flex-direction: column;align-self: flex-start;margin-left: 10rpx;}}}}}// 向下的線.line-bottom {&::after {@include line();bottom: -$line-length;}}// 向上的線.line-top {&::before {@include line();top: -$line-length;}}// 向左的線.line-left {&::after {@include line();width: calc(50% + #{$spacing});height: 1px;left: calc(-50% - #{$extend});top: 0;}}// 向右的線.line-right {&::before {@include line();width: calc(50% + #{$spacing});height: 1px;right: calc(-50% - #{$extend});top: 0;}}}.btn {font-size: 18rpx;width: 116rpx;height: 45rpx;}
</style>

橫向樹結構:

<template><view class="vmPage"><view class="sub-branch" v-for="(item,index) in treeData" :key="index"><view class="item" :class="{'line-top': index !== 0, 'line-bottom': index !== treeData.length - 1}"><view class="item-name" :class="{'line-right':item.child && item.child.length > 0,'line-left':!treeFirst}"><view class="content"><image src="@/static/logo.png" mode="widthFix" style="width: 40rpx;height: auto;border-radius: 50%;"></image><text class="name">{{item.name}}</text><view class="btn" @click="addItem(item)">添加子級</view><view class="btn" @click="addSpouse(item)">添加配偶</view><view class="btn" @click="delItem(item)">刪除當前</view></view><!-- 配偶 --><view class="content-2" v-if="item.spouse"><image src="@/static/logo.png" mode="widthFix" style="width: 40rpx;height: auto;border-radius: 50%;"></image><text class="name">{{item.spouse.name}}</text></view></view></view><row-tree-list v-if="item.child && item.child.length > 0" :tree-data="item.child"></row-tree-list></view></view>
</template><script setup name="row-tree-list">import {ref,inject} from 'vue'import rowTreeList from '@/components/row-tree-list.vue';const delItem = inject('delItem')const addItem = inject('addItem')const addSpouse = inject('addSpouse')defineProps(['treeData', 'treeFirst'])
</script><style lang="scss" scoped>$line-length: 30rpx;$spacing: 30rpx;$extend: calc(#{$spacing});$line-color: #e43934;// 線樣式@mixin line {content: "";display: block;width: 1rpx;height: $line-length;position: absolute;top: 0;bottom: 0;margin: auto;background: #e43934;}@mixin flex-center {display: flex;justify-content: center;align-items: center;}.vmPage {display: flex;justify-content: center;flex-direction: column;.sub-branch {display: flex;.item {@include flex-center();position: relative;.item-name {position: relative;flex-direction: column;@include flex-center();align-items: flex-start;margin: 10rpx $spacing;}}}}.content,.content-2 {@include flex-center();background: #fff;padding: 20rpx;box-sizing: border-box;border-radius: 16rpx;box-shadow: 0px 5rpx 30rpx 5rpx rgba(0, 0, 0, 0.08);.name {display: inline-block;font-size: 20rpx;margin: 0 8rpx 0 20rpx;width: 30rpx;}.btn {font-size: 18rpx;width: 30rpx;text-align: center;padding: 8rpx;background-color: #f8f8f8;border: 1px solid rgba(0, 0, 0, .2);border-radius: 6rpx;}}// 向右的線.line-right {&::after {@include line();right: - $line-length;width: $line-length;height: 1rpx;}}// 向左的線.line-left {&::before {@include line();left: - $line-length;width: $line-length;height: 1rpx;}}// 向上的線.line-top {&::after {@include line();height: calc(50% + $line-length);left: 0;top: calc(-50% - $line-length);}}// 向下的線.line-bottom {&::before {@include line();height: calc(50% + $line-length);left: 0;bottom: calc(-50% - $line-length);}}
</style>

注:該文章所用代碼多是復用原作者羊羊不想寫代碼 的個人主頁 - DCloud問答?的插件tree-list族譜,樹形列表,可縮放滑動 - DCloud 插件市場?中的代碼,只是在橫向樹結構中修改了部分代碼。

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

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

相關文章

思途JSP學習 0731

繼0730&#xff0c;我們對項目做最后的升級一、刪除功能1、新增復選框輔助刪除條目的選擇修改我們的list.jsp和list.js在列表的第一列增加一列選擇框2、給復選框添加全選與行點擊選擇功能在行選擇功能中&#xff0c;因為此時的選擇框還未生成&#xff0c;所以我們將事件委托給他…

某訊視頻風控參數逆向分析

文章目錄1. 寫在前面2. 接口分析3. 加密分析4. 扣JS代碼【&#x1f3e0;作者主頁】&#xff1a;吳秋霖 【&#x1f4bc;作者介紹】&#xff1a;擅長爬蟲與JS加密逆向分析&#xff01;Python領域優質創作者、CSDN博客專家、阿里云博客專家、華為云享專家。一路走來長期堅守并致力…

[Broken IOS] 配置CLI | 終端用戶界面TUI

鏈接&#xff1a;https://palera.in/ docs&#xff1a;palera1n palera1n 是一款專為 Jailbroken蘋果設備 設計的強大工具&#xff0c;支持運行 iOS/iPadOS/tvOS 15.0 及更新系統 的 iPhone、iPad 和 Apple TV。 該工具通過 DFU 模式 下的底層 USB 通信引導設備&#xff0c;…

論文閱讀|ArxiV 2024|Mamba進一步研究|VSSD

論文地址&#xff1a;pdf 代碼地址&#xff1a;code 文章目錄1.研究背景與動機2. 核心方法2.1 預備知識:mamba-ssm2.2 非因果狀態空間對偶性2.3 視覺狀態空間對偶性模型3. 實驗結果3.1 圖像分類任務3.2 目標檢測任務3.3 語義分割任務3.4 消融實驗4.局限性與結論4.1 局限性4.2 結…

Flutter中 Provider 的基礎用法超詳細講解(二)之ChangeNotifierProvider

目錄 前言 一、什么是ChangeNotifierProvider? 二、ChangeNotifier的簡單用法 1.定義狀態類 2.使用ChangeNotifierProvider提供狀態 3.獲取狀態并監聽更新 1.Consumer 2.通過API方式獲取 1.Provider.of (context) 2.context.watch () 3.context.read () 4.各種獲…

2025電商CPS分銷與推客系統小程序開發:趨勢、架構與實戰解析

一、行業趨勢&#xff1a;CPS模式與社交電商的深度融合1.1 電商行業新趨勢根據《2025年電子商務行業發展趨勢預測報告》&#xff0c;社交電商與內容營銷已成為核心增長點。消費者行為呈現三大特征&#xff1a;消費習慣轉變&#xff1a;線上購物占比超70%&#xff0c;Z世代用戶更…

Conda環境下配置的基本命令

功能命令創建環境conda create -n myenv python3.11激活環境conda activate myenv刪除環境conda env remove -n myenv復制環境conda create -n newenv --clone myenv列出所有環境conda env list列出環境所有包conda list徹底清除某個 Conda 環境中的所有已安裝包&#xff08;但…

Ps2025

快捷鍵CShs保存CSw存儲為S選取疊加選取,A選取減去選區C回車保存路徑內容識別 SF5 ADel填充前景色CDel填充背景色A上下 上下行間距A左右 左右字間距C左鍵絲滑放大縮小CASE蓋印圖層C}上移一格CG新建組sF6羽化像素鋼筆工具打上抹點&#xff0c;按住shift水平拉調增弧度左右兩個手柄…

ceph sc 設置文件系統格式化參數

前言 默認的 sc 文件系統 inode 太少,對于小文件場景,往往會出現容量沒滿,inode 已經用盡的情況,本文說明如何設置 inode。 說明 本文使用的是 rook-ceph 部署的 ceph 作為存儲后端。 xfs 文件系統 sc 創建帶格式化參數的 xfs 文件系統的 sc allowVolumeExpansion: t…

【LY88】ubuntu下的常用操作

vscode 下載安裝包 在安裝包所處文件夾空白區域右鍵調出終端 輸入下行命令安裝 c后接tab自動補全安裝包名稱&#xff08;前提是該文件夾中僅這一個c開頭文件&#xff0c;否則得再輸點字母&#xff0c;保證其可唯一索引到&#xff09; sudo dpkg -i ctab安裝完畢后輸入code&…

web應用從服務器主動推動數據到客戶端的方式

html5 websocket 全雙工交互 全雙工通信&#xff1a;建立持久連接&#xff0c;服務端和客戶端可隨時互相發送消息 低延遲&#xff1a;適合實時應用&#xff08;聊天、游戲、股票行情等&#xff09; socket協議是與HTTP協議平級的&#xff0c;websocket協議是建立在TCP協議之上的…

基于Spring Boot實現中醫醫學處方管理實踐

基于Spring Boot實現中醫醫學處方管理 以下是基于Spring Boot實現中醫醫學處方管理的相關示例和資源整理,涵蓋基礎架構、功能模塊及實際應用案例: 基礎項目結構 Spring Boot中醫處方系統通常采用MVC分層設計: 實體類:定義處方、藥材、患者等JPA實體 @Entity public clas…

從“人工核驗”到“智能鑒防”:護照鑒偽設備的科技革命

“一本偽造護照的查獲成本從72小時降至3秒&#xff0c;背后是光學傳感、量子加密與多模態AI的十年協同進化。”2025年全球邊檢口岸查獲偽假護照近500份&#xff0c;其中芯片偽造占比首超40%。當造假技術逼近分子級仿制&#xff0c;傳統肉眼鑒別徹底失效&#xff0c;多光譜成像、…

無人機飛控系統3D (C++)實踐

大疆無人機飛控系統3D模型開發 大疆無人機飛控系統3D模型開發(C++) 核心架構設計 大疆無人機的飛控系統通常采用分層架構,分為硬件抽象層(HAL)、中間件層和應用層。HAL負責與傳感器/執行器直接交互,中間件處理數據融合和通信協議,應用層實現核心控制算法。 典型代碼結…

ES6中import與export的用法詳解

目錄 一、ES6模塊化的核心概念 1. 模塊化的基本規則 二、export的用法 1. 命名導出&#xff08;Named Export&#xff09; 示例&#xff1a; 2. 默認導出&#xff08;Default Export&#xff09; 示例&#xff1a; 默認導出函數或類&#xff1a; 3. 導出語句的統一聲明…

硬核技術協同:x86 生態、機密計算與云原生等技術如何為產業數字化轉型筑底賦能

在產業數字化轉型的浪潮中&#xff0c;x86 生態構建、機密計算與 AI 融合、高性能網卡突破、云原生 OS 實踐、國產數據庫優化等技術領域的突破&#xff0c;正成為支撐數字化基礎設施升級與業務創新的核心引擎。以下從技術深度與產業實踐角度&#xff0c;系統性解析各領域的最新…

Java項目:基于SSM框架實現的網絡財務管理系統【ssm+B/S架構+源碼+數據庫+畢業論文+遠程部署】

摘 要 現代經濟快節奏發展以及不斷完善升級的信息化技術&#xff0c;讓傳統數據信息的管理升級為軟件存儲&#xff0c;歸納&#xff0c;集中處理數據信息的管理方式。本網絡財務管理系統就是在這樣的大環境下誕生&#xff0c;其可以幫助管理者在短時間內處理完畢龐大的數據信息…

1.5.Vue v-for 和 指令修飾符

vue v-for當你使用 v-for 指令來渲染列表時&#xff0c;為每個元素提供一個唯一的 key 屬性是非常重要的。key 是用來給 Vue 一個提示&#xff0c;以便它能夠追蹤每個節點的身份&#xff0c;從而更高效地更新虛擬 DOM。key 的作用唯一標識&#xff1a;key 應該是每項數據的唯一…

(RedmiBook)上禁用觸摸板或自帶鍵盤

在紅米筆記本&#xff08;RedmiBook&#xff09;上禁用觸摸板或自帶鍵盤&#xff0c;可以通過以下幾種方法實現&#xff1a; 方法一&#xff1a;通過設備管理器禁用&#xff08;Windows 系統&#xff09; 禁用觸摸板 打開設備管理器 按 Win X → 選擇 “設備管理器”或 Win …

15 - 多模態大語言模型 — 圖文 “牽線” 系統 “成長記”:借 CLIP 練本領,從圖像與文字里精準 “搭鵲橋” 的全過程 (呆瓜版 - 2 號)

目錄 1、基礎&#xff1a;它到底是個啥&#xff1f; 1. 1、一句話理解核心 1.2、 為啥厲害&#xff1f; 1.3、怎么發展來的&#xff1f; 2、架構&#xff1a;它的 “身體構造” 是啥樣的&#xff1f; 2.1、視覺語言模型架構&#xff1a;讓 AI “看懂” 世界的核心系統 2…