VUE實現多個彈窗優先級變化實現思路

在開發復雜的單頁應用(SPA)時,我們經常會遇到需要管理多個浮動窗口(或稱“彈窗”、“面板”)的場景。一個核心的用戶體驗要求是:用戶當前操作的窗口應該總是在最頂層。本文將結合代碼示例,總結一種在 Vue 3 (Composition API) 和 TypeScript 環境下,實現這一功能的清晰、可擴展的思路。

核心思路

該功能的實現主要依賴于三個關鍵部分:

  • 集中式狀態管理:使用一個響應式對象統一管理所有窗口的?z-index?層級。
  • 點擊置頂:當用戶點擊某個窗口時,動態提升其?z-index?到最高。
  • 新窗口置頂:當一個新窗口被打開時,自動將其?z-index?設置為最高

實現步驟詳解

1. 狀態設計:統一管理?z-index

首先,我們需要一個地方來存儲和跟蹤所有浮動窗口的層級狀態。在?Vue 3 的?setup?函數中,使用?reactive?API 是一個絕佳的選擇,因為它創建了一個響應式對象,任何對此對象的修改都會自動觸發?UI 更新。

import { reactive } from 'vue';// --- 浮動窗口層級管理 ---
const windowZIndices = reactive<Record<string, number>>({cockpitBox: 10,realTimeWarning: 10,monitorBox: 10,historyEvent: 10,sampleNorth: 10,blackAndWhiteList: 10,shipList: 10,// ... 其他窗口
});
  • reactive:確保了當?z-index?值變化時,視圖能夠自動重新渲染。
  • Record<string, number>:這是一個?TypeScript 類型,定義了一個鍵是字符串(窗口名)、值是數字(z-index)的對象。
  • 初始值:所有窗口的初始?z-index?都設為 10,表示它們在初始狀態下層級相同

接著,在模板中,我們將每個窗口組件的?style?屬性與這個?reactive?對象中的相應值進行綁定

<!-- 模板部分 -->
<div class="cockpitBox" @mousedown="(e) => bringToFront(e, 'cockpitBox')":style="{ zIndex: windowZIndices['cockpitBox'] }"><!-- ... -->
</div><RealTimeWarning v-if="store.showRealTimeWarning"@mousedown="(e) => bringToFront(e, 'realTimeWarning')":style="{ zIndex: windowZIndices['realTimeWarning'] }" /><ShipList class="shipList" v-if="store.showShipList"@mousedown="(e) => bringToFront(e, 'shipList')":style="{ zIndex: windowZIndices['shipList'] }" /><!-- ... 其他窗口組件 -->

2. 核心邏輯:bringWindowToFront?函數

這是實現“點擊置頂”功能的核心。當一個窗口需要被置頂時,我們需要找到當前所有窗口中的最大?z-index,然后將目標窗口的?z-index?設置為這個最大值加一。

/*** 將指定名稱的窗口置于頂層(z-index 最高)。* @param windowName 要置頂的窗口名稱*/
const bringWindowToFront = (windowName: keyof typeof windowZIndices) => {// 1. 獲取當前所有 z-index 值的最大值const maxZIndex = Math.max(...Object.values(windowZIndices));// 2. 將目標窗口的 z-index 設為最大值 + 1windowZIndices[windowName] = maxZIndex + 1;
};

為了在用戶點擊時調用它,我們為每個窗口綁定了?@mousedown?事件,該事件會調用一個簡單的包裝函數?bringToFront

const bringToFront = (event: MouseEvent, windowName: keyof typeof windowZIndices) => {bringWindowToFront(windowName);
};

3. 自動管理:新開窗口置頂

除了點擊置頂,新打開的窗口也應該自動顯示在最前面。這個功能通過?watch?API 來實現,我們偵聽控制每個窗口可見性的狀態(通常是 Pinia store 中的一個布爾值)。

import { watch } from 'vue';const setupWindowManagement = () => {// 定義需要管理的窗口及其對應的 store 狀態const windowsToManage: Record<string, () => boolean> = {realTimeWarning: () => store.showRealTimeWarning,monitorBox: () => store.showMonitor,historyEvent: () => store.showHistory,// ... 其他由 store 控制顯隱的窗口};// 遍歷并為每個窗口設置 watch 偵聽器
//Object.prototype.hasOwnProperty.call用于判斷一個屬性是否是對象自身的屬性for (const windowName in windowsToManage) {if (Object.prototype.hasOwnProperty.call(windowsToManage, windowName)) {const typedWindowName = windowName as keyof typeof windowZIndices;watch(windowsToManage[typedWindowName], (newValue, oldValue) => {// 當窗口從“不顯示”變為“顯示”時if (newValue && !oldValue) {// 調用置頂函數bringWindowToFront(typedWindowName);}});}}
};

最后,在?onMounted生命周期鉤子中調用?setupWindowManagement(),即可在組件掛載后激活這些偵聽器。

總結

通過結合?reactive?狀態、事件處理和?watch?偵聽器,我們構建了一個清晰、高效且易于維護的浮動窗口層級管理系統:

  • reactive?對象:作為單一數據源,集中管理所有窗口的?z-index。
  • @mousedown?事件:響應用戶的直接交互,提供即時的“點擊置頂”反饋。
  • watch?偵聽器:自動化處理程序狀態變化(如窗口的顯示/隱藏),確保新窗口始終擁有最高優先級。

這種方法不僅代碼結構清晰,而且擴展性強。當需要添加新的浮動窗口時,只需在?windowZIndices?對象和?windowsToManage?映射中增加相應的條目即可,無需改動核心邏輯。




tips

1.for...in?循環

  • 定義:for...in?是 JavaScript 中用于遍歷對象屬性的一種循環。它會遍歷一個對象上所有可枚舉的屬性(包括自有屬性和從原型鏈上繼承的屬性)。
  • 作用:在這個場景下,它會依次遍歷?windowsToManage?對象的每一個鍵(key)。
  • 第一次循環,windowName?的值是字符串?'realTimeWarning'。
  • 第二次循環,windowName?的值是字符串?'monitorBox'。
  • ...以此類推,直到所有窗口都遍歷完。
  • 目的:通過這個循環,我們可以為每一個在?windowsToManage?中配置的窗口都應用上相同的邏輯(也就是給它們都設置一個?watch?偵聽器)。

2.?Object.prototype.hasOwnProperty.call()

hasOwnProperty?是什么?

  • 每個 JavaScript 對象都有一個?hasOwnProperty('propertyName')?方法,它用來判斷一個屬性是對象自身的屬性,還是從原型鏈上繼承來的。如果是自身的,返回?true;如果是繼承的,返回?false。
  • 為什么需要它?
  • for...in?循環有一個特點,它不僅會遍歷對象自身的屬性,還會遍歷其原型鏈上的屬性。在絕大多數情況下,我們只關心對象自身的屬性。這個?if?判斷就是為了過濾掉那些可能存在的、我們不關心的繼承屬性。
  • 為什么不直接寫?windowsToManage.hasOwnProperty(windowName)?
  • 直接寫?windowsToManage.hasOwnProperty(...)?在?99% 的情況下是沒問題的。但?Object.prototype.hasOwnProperty.call(...)?是一個更安全、更健壯的寫法,主要為了防止兩種極端情況:
  1. 對象重寫了?hasOwnProperty:如果?windowsToManage?對象恰好有一個自己的屬性也叫?hasOwnProperty,那么直接調用就會執行被重寫的版本,可能導致非預期的結果。
  1. 對象沒有?hasOwnProperty?方法:如果一個對象是通過?Object.create(null)?創建的,那么它沒有任何原型,也就不存在?hasOwnProperty?方法,直接調用會報錯。
  • .call()?的作用:
  • call?允許我們調用一個函數,并且手動指定這個函數內部的?this?指向。
  • Object.prototype.hasOwnProperty.call(windowsToManage, windowName)?的意思是:
  1. 找到?Object?原型上最原始、最正宗的那個?hasOwnProperty?方法。
  1. 通過?.call()?來執行它。
  1. 第一個參數?windowsToManage?是告訴?hasOwnProperty:“請把?this?當作是?windowsToManage?對象來執行”。
  1. 第二個參數?windowName?是傳遞給?hasOwnProperty?的參數。
  • 這樣就保證了無論?windowsToManage?對象本身是什么樣,我們調用的始終是正確、安全的?hasOwnProperty?方法。這在編寫高質量的庫或框架代碼時是一個非常重要的最佳實踐。

typeof? 和 keyof typeof

typeof?(在類型上下文中使用)

? ? ? 功能:獲取一個變量或對象的類型。它允許我們基于已存在的 JavaScript 代碼(值)來? ? ? 創建 TypeScript 類型。(從變量提取類型,函數返回值類型推斷)

? ? ? ? const person = { name: "Alice", age: 30 };// typeof person 的結果是類型:type PersonType = typeof person;?//相對于type PersonType = { name: string, age: number }

keyof(直接操作類型)

? ?功能:獲取一個類型的所有鍵(key),并創建一個由這些鍵組成的聯合類型 (Union Type)

(我有個類型,想知道它有哪些屬性)

        type PersonType = { name: string, age: number };// keyof PersonType 的結果是類型:type PersonKeys = keyof PersonType; //相對于 type PersonKeys="name" | "age"

keyof typeof (?通過值獲取類型再獲取鍵名)

則會進一步獲取這個類型的所有鍵,形成一個聯合類型(我有個變量,想知道它有哪些屬性)

// 先有變量(值)
const person = {name: "Alice",age: 30,email: "alice@example.com"
};// 通過變量獲取類型,再獲取鍵名
type PersonKeys = keyof typeof person;
// 結果: "name" | "age" | "email"

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

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

相關文章

集成算法和kmeans

一、集成算法&#xff08;Ensemble Learning&#xff09; 1. 基本概念 集成學習通過構建并結合多個學習器&#xff08;基分類器/回歸器&#xff09;來完成學習任務&#xff0c;旨在通過集體決策提升模型性能&#xff0c;類似于“多個專家的綜合判斷優于單個專家”。 2. 結合策略…

圖數據庫性能與可擴展性評估

圖數據庫的性能與可擴展性直接決定業務場景&#xff08;如實時風控、知識圖譜分析&#xff09;的落地效果&#xff0c;需結合業務場景特性&#xff08;OLTP/OLAP&#xff09;、技術指標&#xff08;響應時間、吞吐量&#xff09;和擴展能力&#xff08;數據量/節點擴展&#xf…

樹莓派常用的國內鏡像源列表以及配置方法

1. 常用的鏡像源使用下來發現清華源經常訪問不到&#xff0c;阿里源比較好用。其他源還未測試。源名稱URL清華源https://pypi.tuna.tsinghua.edu.cn/simple阿里云https://mirrors.aliyun.com/pypi/simple/中科大https://pypi.mirrors.ustc.edu.cn/simple/華為云https://repo.hu…

Transformer在文本、圖像和點云數據中的應用——經典工作梳理

摘要 最近在整一些3D檢測和分割的任務&#xff0c;接觸了一下ptv3&#xff0c;在之前梳理的工作owlv2中用到了vit&#xff0c;去年年假閱讀《多模態大模型&#xff1a;算法、應用與微調》&#xff08;劉兆峰&#xff09;時學習了Transformer網絡架構及其在文本數據中的應用&am…

訓練后數據集后部署PaddleOCR轉trt流程

訓練后的模型部署&#xff0c;首先要進行訓練 0.訓練流程見文章 PaddleOCR字符識別&#xff0c;訓練自己的數據集全流程&#xff08;環境、標注、訓練、推理&#xff09;-CSDN博客文章瀏覽閱讀1.6k次&#xff0c;點贊53次&#xff0c;收藏23次。PaddleOCR是基于百度飛槳框架的…

《MLB美職棒》美國國球是橄欖球還是棒球·棒球5號位

USAs National Sport Showdown: MLB?? vs NFL Ultimate Guide!從商業價值到文化基因&#xff0c;360解析美國體育王座之爭&#xff01;添加圖片注釋&#xff0c;不超過 140 字&#xff08;可選&#xff09;? 歷史定位 Historical Roots?? MLB&#xff1a;The "Classi…

常見 Linux 網絡命令梳理

在日常運維和排障工作中&#xff0c;網絡相關命令是最常用的一類工具。無論是檢查網絡連通性&#xff0c;還是定位路由問題&#xff0c;又或是分析端口和服務占用&#xff0c;熟悉這些命令都能讓我們更高效地解決問題。本文將從幾個常見的維度來梳理 Linux 下的網絡命令&#x…

Docker 搭建 Gitlab 實現自動部署Vue項目

1、配置要求: 硬件要求: CPU:雙核或以上 內存:4GB或以上 軟件要求:Centos6 或更高版本 2、gitlab鏡像: # 中文版倉庫 #docker pull twang2218/gitlab-ce-zh docker pull gitlab/gitlab-ce 3、gitlab部署目錄 說明:為了跟其他容器區分,gitlab相關容…

如何解決機器翻譯的“幻覺“問題(Hallucination)?

更多內容請見: 機器翻譯修煉-專欄介紹和目錄 文章目錄 一、數據層面優化 二、模型架構改進 三、訓練策略調整 四、評估與迭代 五、前沿方向與挑戰 六、案例:WMT2023幻覺緩解方案 機器翻譯中的“幻覺”(Hallucination)指模型生成與源文本語義無關、邏輯矛盾或事實錯誤的翻譯…

基于STM32+NBIOT設計的宿舍安防控制系統_264

文章目錄 1.1 項目介紹 【1】開發背景 【2】實現需求 【3】項目硬件模塊組成 【4】設計意義 【5】國內外研究現狀 【6】摘要 1.2 系統總體設計 【1】系統功能需求分析 【2】系統總體方案設計 【3】系統工作原理 1.3 系統框架圖 1.4 系統功能總結 1.5 系統原理圖 1.6 實物圖 1.7…

SLAM文獻之-Globally Consistent and Tightly Coupled 3D LiDAR Inertial Mapping

一、簡介 該論《Globally Consistent and Tightly Coupled 3D LiDAR Inertial Mapping》是日本先進工業科學技術研究所&#xff08;AIST&#xff09;的Koide等人于2022年在IEEE國際機器人與自動化會議&#xff08;ICRA&#xff09;上發表的一篇論文。該研究提出了一種基于全局…

【STM32】HAL庫中的實現(七):DMA(直接存儲器訪問)

DMA 是什么&#xff1f; DMA&#xff08;Direct Memory Access&#xff09;是 外設直接和內存之間數據搬運的機制&#xff0c;不需要 CPU 參與。 ? 舉個例子&#xff1a;傳統方式&#xff1a; ADC → CPU → RAM 使用 DMA&#xff1a;ADC → DMA → RAM&#xff08;CPU 不需干…

【LeetCode熱題100道筆記+動畫】字母異位詞分組

題目描述 給你一個字符串數組,請你將 字母異位詞 組合在一起。可以按任意順序返回結果列表。 示例 1: 輸入: strs = [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”] 輸出: [[“bat”],[“nat”,“tan”],[“ate”,“eat”,“tea”]] 解釋: 在 strs 中沒有字符串可…

【Kafka】常見簡單八股總結

為什么使用消息隊列&#xff1f; 解耦&#xff1a; 我以我的一段開發經驗舉例&#xff1a; 【Kafka】登錄日志處理的三次階梯式優化實踐&#xff1a;從同步寫入到Kafka多分區批處理 我做過一個登錄日志邏輯&#xff0c;就是在登錄邏輯末尾&#xff0c;加一段寫進數據庫登錄日志…

微信小程序連接到阿里云物聯網平臺

目錄準備階段阿里云配置下載mqtt.min.js文件小程序實現注意小程序配置服務器域名概述&#xff1a;介紹使用微信小程序連接到阿里云平臺的快捷方法和完整過程。 阿里云平臺建立設備&#xff0c;提供mqtt連接參數&#xff0c;小程序借助mqtt.min.js&#xff0c;也就是基于Github下…

2-3〔O?S?C?P? ? 研記〕? 漏洞掃描?AppScan(WEB掃描)

鄭重聲明&#xff1a; 本文所有安全知識與技術&#xff0c;僅用于探討、研究及學習&#xff0c;嚴禁用于違反國家法律法規的非法活動。對于因不當使用相關內容造成的任何損失或法律責任&#xff0c;本人不承擔任何責任。 如需轉載&#xff0c;請注明出處且不得用于商業盈利。 …

LeetCode 刷題【47. 全排列 II】

47. 全排列 II 自己做 解1&#xff1a;檢查重復 class Solution { public:void circle(vector<int> nums, vector<vector<int>> &res,int start){int len nums.size();if(start len - 1){ //到頭了//檢查重復bool is_exist fa…

Https之(一)TLS介紹及握手過程詳解

文章目錄簡介 TLSTLS第一次握手1.Client HelloTLS第二次握手2.Server Hello3.Certificate4.Server Hello DoneTLS第三次握手5.Client Key Exchange6.Change Cipher Spec7.Encrypted Handshake MessageTLS第四次握手8.New Session Ticket9.Change Cipher Spec10.Encrypted Hands…

【WEB 】從零實現一個交互輪播圖(附源碼)

文章目錄 一、輪播圖整體功能規劃二、HTML結構深度解析三、CSS樣式實現細節1. 定位系統詳解2. 顯示/隱藏機制3. 按鈕交互效果實現4. 純CSS箭頭實現5. 指示器&#xff1a;當前位置可視化 四、JavaScript邏輯深入解析1. 核心變量與DOM獲取2. 圖片切換函數&#xff08;核心邏輯&am…

機器學習--PCA降維

一核心部分 1解決的問題&#xff1a;應對高維數據帶來的計算量大、冗余信息多、易出現過擬合等問題&#xff0c;在減少數據維度的同時盡可能保留原始數據的關鍵信息。2核心思想&#xff1a…