最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用Vue封裝一個前端通用右鍵菜單組件

 更新時間:2024年02月23日 11:12:36   作者:八股哈希表  
這篇文章主要為大家詳細介紹了如何使用Vue封裝一個前端通用右鍵菜單組件,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下

本文將手把手實現(xiàn)一個基于Vue的通用的前端通用右鍵菜單,具有以下特性:

  • 與業(yè)務代碼完全解耦
  • 支持嵌套元素的右鍵菜單
  • 菜單項可靈活配置

實現(xiàn)了一個小demo,演示地址:contextmenu-murex.vercel.app/

為什么要做右鍵菜單

筆者做過一個思維導圖項目,需要能夠對思維導圖上的節(jié)點和畫布進行操作,如何實現(xiàn)呢?右鍵菜單是一個不錯的選擇,既不占用畫布空間,又有豐富的功能可供選擇。但問題來了,如何實現(xiàn)這樣一個右鍵菜單:

  • 組件使用方便
  • 與業(yè)務代碼解耦
  • 針對不同的目標元素展示不同的右鍵菜單
  • 右鍵菜單如何定位

組件的設計

比較容易想到的是:

ContextMenu組件傳遞一個與其關聯(lián)的容器,右擊這個容器則顯示右鍵菜單,這樣的話需要向ContextMenu傳遞容器的真實DOM元素,這樣的方式不夠優(yōu)雅也影響效率。

<ContextMenu :relation="componentA"/>

在容器組件中嵌套ContextMenu組件,這個方式下容器和右鍵菜單的關聯(lián)關系不明顯,而且更要命的是兩者之間產(chǎn)生了耦合,ContextMenu依賴容器組件的數(shù)據(jù)。

<div class="componentA">
  <ContextMenu :porps=""/>
</div>

那么有沒有既能與業(yè)務組件解耦,且代碼組織優(yōu)雅的設計方案呢?這里筆者參考了開源組件庫里對冒泡(Popover),抽屜(Drawer),下拉菜單(Dropdown)等組件的設計方案,利用插槽將業(yè)務組件置于ContextMenu組件中,然后是右鍵菜單的具體實現(xiàn)。

<!-- ContextMenu 組件使用 -->
<!-- const menu = [
  { label: '部門' },
  { label: '員工' },
  { label: '角色' },
  { label: '權限' },
  { label: '領導' }
] -->
<ContextMenu :menu="menu" @select="console.log($event)">
    <!-- 業(yè)務組件 -->
</ContextMenu>


<!-- ContextMenu -->
<div ref="container">
  <slot></slot>
  <ul class="context-menu">
    <li></li>
    <!-- 菜單組件實現(xiàn) -->
  </ul>
</div>

ContextMenu的使用上,需要提供菜單配置項,是一個數(shù)組,數(shù)組元素為必須包含label屬性的對象,選定菜單中某一項,可監(jiān)聽select事件,然后執(zhí)行相應的業(yè)務邏輯。

組件的布局方式

這個很容易想到,一定是要用固定定位,不管是哪個業(yè)務組件觸發(fā)了右鍵菜單,其位置一定是相對于視口的。

但問題并不是這樣就結束了,要知道默認情況下的固定定位位置相對于視口,但如果其父代中有tranform的元素,那么固定定位的位置是相對于這個元素的而不是視口。如果沒有想到這個特性,就會產(chǎn)生嚴重的布局問題。

我們可以利用 Vue3 內置的<Teleport>組件,將右鍵菜單傳送到body元素,這樣無論如何右鍵菜單的定位位置都是相對于視口的。

<!-- ContextMenu -->
<div ref="container">
  <slot></slot>
  
  <Teleport to="body">
    <ul class="context-menu">
    <li></li>
    <!-- 菜單組件實現(xiàn) -->
  </ul>
  </Teleport>
</div>

菜單組件的位置和可見度

設計好組件了,如何顯示組件,并定位菜單的位置呢?

這里我們可以寫一個useContextMenu的 hook,返回位置坐標xy,以及可見度visible,并接收一個容器參數(shù),因為需要監(jiān)聽各個需要右鍵菜單的容器的contextmenu事件。

這里需要注意位置坐標的要結合菜單height 和 width 來判斷是否會相對視口越界,如果越界則自適應定位位置。

import { ref, onMounted, onUnmounted } from "vue";

export function useContextmenu(container) {
  const visible = ref(false);
  const x = ref(0);
  const y = ref(0);

  onMounted(() => {
    container.value.addEventListener("contextmenu", showMenu);
    // 把事件注冊到捕獲階段,改變觸發(fā)不同元素相同事件的觸發(fā)順序
    window.addEventListener("contextmenu", hideMenu, true);
    window.addEventListener("click", hideMenu);
  });

  onUnmounted(() => {
    container.value.removeEventListener("contextmenu", showMenu);
  });

  function showMenu(e) {
    e.preventDefault();
    e.stopPropagation();
    visible.value = true;

    nextTick(() => {
      const { clientX, clientY } = e;
      const menuContainer = document.querySelector(".context-menu");
      const { clientWidth: menuWidth, clientHeight: menuHeight } =
        menuContainer;
      const isOverPortWidth = clientX + menuWidth > window.innerWidth;
      const isOverPortHeight = clientY + menuHeight > window.innerHeight;

      if (isOverPortWidth) {
        x.value = clientX - menuWidth;
        y.value = clientY;
      }
      if (isOverPortHeight) {
        x.value = clientX;
        y.value = clientY - menuHeight;
      }
      if (!isOverPortHeight && !isOverPortWidth) {
        x.value = clientX;
        y.value = clientY;
      }
    });
  }

  function hideMenu(e) {
    visible.value = false;
  }
  return { visible, x, y };
}

這里控制右鍵菜單的顯示和隱藏還是需要注意一些細節(jié)的,比如需要利用事件捕獲改變事件的觸發(fā)順序,以及阻止冒泡,防止嵌套元素中出現(xiàn)重復右鍵菜單。

組件動畫

這里要實現(xiàn)一個高度由 0 過渡到 h 的效果,利用<Transition>來實現(xiàn),但有一個問題是:過渡效果是無法識別height: auto的,也就是高度無法從 0 過渡到 auto,那么就無法僅通過 CSS 來實現(xiàn)過渡動畫,我們可以利用<Transition>的 JS 鉤子函數(shù),來手動計算子元素撐開的高度,然后在觸發(fā)下一次渲染更新前手動設置height

function handleEnter(el) {
  // 手動計算auto下?lián)伍_的容器高度
  el.style.height = 'auto'
  // 這里需要減去多余的padding
  const h = el.clientHeight - 12
  // 高度回歸為0 否則沒有過渡效果
  el.style.height = 0 + 'px'

  // 渲染下一幀之前,復制過渡和計算出的高度
  requestAnimationFrame(() => {
    el.style.height = h + 'px'
    el.style.transition = '.3s'
  })
}

  // 進入動畫結束后,關閉過渡,否則關閉菜單時有時延
  function handdleAfterEnter(el) {
    el.style.transition = 'none'
  }
</script>

<template>
  <div ref="container">
    
    <slot></slot>
    
    <Teleport to="body">
      <Transition @enter="handleEnter" @after-enter="handdleAfterEnter">
        <ul class="context-menu" >
          <li></li>
        </ul>
      </Transition>
    </Teleport>
  </div>
</template>

總結

好了,以上就是設計一個通用右鍵菜單組件的所有注意要點了,可以看到細節(jié)還是有一些的,比如:

  • 組件的設計方案
  • 固定定位的問題
  • 事件觸發(fā)模型
  • 菜單定位越界控制
  • 組件的auto高度過渡動畫。

其實還有一種設計方案是函數(shù)式組件,利用 Vue API的h函數(shù)將 SFC 渲染為VNode,然后調用render方法將真實dom進行掛載,也支持菜單項的配置和業(yè)務解耦。

最后,奉上源碼:github.com/Jabinuu/contextmenu,如果有用的話歡迎 Star

以上就是使用Vue封裝一個前端通用右鍵菜單組件的詳細內容,更多關于Vue右鍵菜單組件的資料請關注腳本之家其它相關文章!

相關文章

  • Vue中使用表單驗證+CRUD方式

    Vue中使用表單驗證+CRUD方式

    本文介紹了如何在后臺添加數(shù)據(jù)接口,并詳細講解了如何在前端使用表格進行增刪改查操作,包括新增、修改和刪除功能的實現(xiàn),以及如何使用表單驗證確保數(shù)據(jù)的準確性
    2026-03-03
  • Vue2如何支持composition API示例詳解

    Vue2如何支持composition API示例詳解

    這篇文章主要為大家介紹了Vue2如何支持composition API示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-01-01
  • 非Vuex實現(xiàn)的登錄狀態(tài)判斷封裝實例代碼

    非Vuex實現(xiàn)的登錄狀態(tài)判斷封裝實例代碼

    這篇文章主要給大家介紹了關于非Vuex實現(xiàn)的登錄狀態(tài)判斷封裝的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2022-02-02
  • vue表格組件封裝舉例詳解(含完整代碼)

    vue表格組件封裝舉例詳解(含完整代碼)

    在現(xiàn)代前端開發(fā)中,表單組件是業(yè)務系統(tǒng)中不可或缺的重要組成部分,下面這篇文章主要介紹了vue表格組件封裝的相關資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2026-03-03
  • Vue Element-ui實現(xiàn)樹形控件節(jié)點添加圖標詳解

    Vue Element-ui實現(xiàn)樹形控件節(jié)點添加圖標詳解

    這篇文章主要為大家介紹了Element-ui實現(xiàn)樹形控件節(jié)點添加圖標,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2021-11-11
  • vue表單vxe-form多字段聯(lián)動校驗的操作方法(對一個控件校驗多個關聯(lián)字段)

    vue表單vxe-form多字段聯(lián)動校驗的操作方法(對一個控件校驗多個關聯(lián)字段)

    vue表單vxe-form如何多字段聯(lián)動校驗,對一個控件校驗多個關聯(lián)字段,這篇文章給大家介紹vue表單vxe-form如何多字段聯(lián)動校驗,對一個控件校驗多個關聯(lián)字段,感興趣的朋友跟隨小編一起看看吧
    2026-02-02
  • vue2.x中h函數(shù)(createElement)與vue3中的h函數(shù)詳解

    vue2.x中h函數(shù)(createElement)與vue3中的h函數(shù)詳解

    h函數(shù)本質就是createElement(),h函數(shù)其實是createVNode的語法糖,返回的就是一個Js普通對象,下面這篇文章主要給大家介紹了關于vue2.x中h函數(shù)(createElement)與vue3中h函數(shù)的相關資料,需要的朋友可以參考下
    2022-12-12
  • 一文詳解Vue3內置組件的使用

    一文詳解Vue3內置組件的使用

    Vue3內置組件是一組預定義的組件,直接嵌入框架,無需手動導入即可在模板中使用,下面這篇文章主要介紹了Vue3內置組件使用的相關資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2025-09-09
  • webstorm添加*.vue文件支持

    webstorm添加*.vue文件支持

    這篇文章主要介紹了webstorm添加*.vue文件支持,webstorm很多的插件內置,不用安裝插件,下面嘗試用vue和es6做項目,有興趣的可以了解一下
    2018-05-05
  • Vue封裝組件利器之$attrs、$listeners的使用

    Vue封裝組件利器之$attrs、$listeners的使用

    vue通信手段有很多種,props/emit、vuex、event bus、provide/inject等,還有一種通信方式,那就是$attrs和$listeners,下面這篇文章主要給大家介紹了關于Vue封裝組件利器之$attrs、$listeners使用的相關資料,需要的朋友可以參考下
    2021-12-12

最新評論

托克逊县| 英德市| 鄂托克前旗| 化州市| 礼泉县| 衡阳县| 观塘区| 贡嘎县| 盈江县| 台东县| 樟树市| 盘山县| 绥棱县| 叶城县| 策勒县| 富宁县| 秦安县| 台东市| 安宁市| 台北市| 平乐县| 汪清县| 织金县| 阳春市| 库尔勒市| 堆龙德庆县| 金沙县| 河北省| 交口县| 鹿邑县| 道孚县| 收藏| 天柱县| 沾化县| 淮阳县| 修文县| 阜平县| 河曲县| 波密县| 万源市| 浮梁县|