国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁 > news >正文

臺(tái)州網(wǎng)站建設(shè)優(yōu)化深圳seo推廣

臺(tái)州網(wǎng)站建設(shè)優(yōu)化,深圳seo推廣,可以做婚禮視頻的網(wǎng)站,安陽青峰網(wǎng)站建設(shè)前言: 最近在公司 PC 端的項(xiàng)目中使用到了右鍵出現(xiàn)菜單選項(xiàng)這樣的一個(gè)工作需求,并且自己現(xiàn)在也在實(shí)現(xiàn)一個(gè)偶然迸發(fā)的 idea( 想用前端實(shí)現(xiàn)一個(gè) windows 系統(tǒng)從開機(jī)到桌面的 UI),其中也要用到右鍵彈出菜單這樣的一個(gè)功能,…

前言: 最近在公司 PC 端的項(xiàng)目中使用到了右鍵出現(xiàn)菜單選項(xiàng)這樣的一個(gè)工作需求,并且自己現(xiàn)在也在實(shí)現(xiàn)一個(gè)偶然迸發(fā)的 idea( 想用前端實(shí)現(xiàn)一個(gè) windows 系統(tǒng)從開機(jī)到桌面的 UI),其中也要用到右鍵彈出菜單這樣的一個(gè)功能,個(gè)人覺得這個(gè)實(shí)現(xiàn)還不錯(cuò),特來分享🎁。

tips: 我個(gè)人是喜歡使用圖文來講解知識點(diǎn)的,相比于直接講概念,我個(gè)人更傾向于使用費(fèi)曼學(xué)習(xí)法來講解某一個(gè)功能的實(shí)現(xiàn)過程,因?yàn)槲乙彩莿倧囊恢徊锁B走過來,所以我更加清楚一個(gè)新手在去學(xué)習(xí)一個(gè)全新的知識的時(shí)候,他其實(shí)不是需要你給他講實(shí)現(xiàn)原理,而是你需要作為一個(gè) “引路人” 讓他先簡單知道這個(gè)知識是用來干什么的,后面隨著他自己一步一步的深入了解,他會(huì)自己慢慢領(lǐng)悟其中的原理。

一. 前期準(zhǔn)備

  1. 我們需要清楚的認(rèn)識到,這種用戶點(diǎn)擊右鍵然后彈出菜單的動(dòng)作行為是非常不適合將組件寫死在頁面上,然后通過使用 v-show 或者 v-if 去控制它的出現(xiàn)和消失的,我們需要想辦法使用函數(shù)式去控制它的行為。

  2. 在此之前,你需要準(zhǔn)備兩個(gè)文件來和我一起實(shí)現(xiàn)這個(gè)右鍵菜單。
    image.png

  3. 預(yù)覽圖:
    333.gif

二. 右鍵菜單的樣式

  1. 菜單樣式的書寫不是我們本文的重點(diǎn),你可以快速在 Menu.vue 里簡單書寫你自己喜歡的一個(gè)簡單 div 即可,我們的重點(diǎn)是在于如何右鍵彈出它。你也可以在下方的源碼標(biāo)題中直接復(fù)制我書寫的樣式,不過你需要使用 UnoCSS 來支持內(nèi)斂樣式屬性。

  2. 如果你不知道如何使用 Unocss,你可以參考這篇文章的內(nèi)容 手把手教你實(shí)現(xiàn)一個(gè)代碼倉庫里面有詳細(xì)的過程來幫助你去完成代碼倉庫的構(gòu)建,其中包括了 Unocss 如何引入和使用。)
    image.png

三. h 函數(shù) 和 render 函數(shù)的使用

  1. 現(xiàn)在我們已經(jīng)完成了 Menu.vue,文件的內(nèi)容,接下來我們需要轉(zhuǎn)頭去書寫 index.ts 內(nèi)的內(nèi)容。

  2. 在此之前,我們需要引入兩個(gè) vue 暴露給我們的,十分重要的函數(shù)。h,和 render。
    image.png

  3. 如果你之前讀過我另外三篇文章,我相信你對這兩個(gè)函數(shù)的使用一定不陌生,但是為了照顧之前沒有了解過的讀者,我還是會(huì)在接下來的內(nèi)容中簡單介紹一下。不過我還是建議你去看一看下面的實(shí)現(xiàn)方式,你一定會(huì)有不一樣的收獲。

  • Vue3 如何實(shí)現(xiàn)一個(gè) Toast 小彈窗
  • Vue3 如何實(shí)現(xiàn)一個(gè)全局搜索框
  • Vue3 如何實(shí)現(xiàn)一個(gè)Dialog
  1. 接下來我簡單的介紹一下,這兩個(gè)函數(shù)的使用方式。你需要知道一個(gè)前提知識,我們在 template 標(biāo)簽里書寫的樣式,最終都會(huì)被轉(zhuǎn)變成虛擬 dom。
    image.png
    這里面書寫的 div 其實(shí)是和我們在瀏覽器里看到的 div “并不是同一個(gè)” div,只不過經(jīng)過 vue 幫我們進(jìn)行了處理,讓它們的表現(xiàn)形式顯得一樣了。

  2. template 是經(jīng)過了怎樣的處理呢?其實(shí)就是經(jīng)過了 h 函數(shù)。然后 h 函數(shù)會(huì)返回一個(gè)特殊的 JS 對象,這個(gè)特殊的對象就是我們所說的虛擬dom。

  3. 那我們在這個(gè)場景怎么使用呢?首先你需要在 index.ts 文件內(nèi)引入我們剛剛書寫的右鍵菜單的樣式。然后將這個(gè)組件作為 h 函數(shù)的第一個(gè)參數(shù)放入,對,就是這么簡單。這個(gè) vnode 就是我們需要用到的虛擬 dom。
    image.png

  4. 有了虛擬 dom 還不行,我們得告訴 vue 我們要把這個(gè)虛擬 dom 渲染到什么地方,這時(shí)候就需要用到 render 函數(shù)。render 函數(shù)要做的事情比較復(fù)雜,不過在這里你只需要簡單的知道。render 函數(shù)會(huì)將一個(gè) 虛擬dom 轉(zhuǎn)換成一個(gè)真實(shí)的 dom 節(jié)點(diǎn)。既然需要一個(gè)虛擬 dom,那我剛剛正好用 h 函數(shù)轉(zhuǎn)換了得到了一個(gè),于是我們自然而然可以寫出下面的代碼。
    image.png

  5. 怎么回事?怎么還報(bào)錯(cuò)了呢?
    image.png
    我們看一下報(bào)錯(cuò)信息,發(fā)現(xiàn)這個(gè) render 函數(shù)需要兩個(gè)參數(shù),我們只給了一個(gè)。那么第二個(gè)參數(shù)是什么呢?我們思考一下,現(xiàn)在這個(gè) dom 已經(jīng)被轉(zhuǎn)換成真實(shí)的 dom 節(jié)點(diǎn)了,但是目前它不知道自己應(yīng)該被渲染到哪里,什么意思呢?其實(shí)理解起來很簡單。
    就好比你現(xiàn)在是一個(gè)外賣員,你到了餐廳取餐,餐廳人員說你去吧,你端著手上的一份外賣餐一臉茫然,我去哪啊?
    就對應(yīng)著,vue 幫你處理好了這個(gè)虛擬節(jié)點(diǎn),但是你沒告訴它應(yīng)該在哪里去渲染。

  6. 知道原因就好辦了,我們直接創(chuàng)建一個(gè)空的 div,先讓 render 用著。
    image.png

四. 右鍵彈出菜單的實(shí)現(xiàn)

  1. 在進(jìn)行下面的功能之前,你需要知道一個(gè)前提知識。
    右鍵.gif
    如上面的 gif 所示,我們可以看到,瀏覽器本身是存在默認(rèn)的右鍵點(diǎn)擊事件的。在這里我們需要取消瀏覽器自身的右鍵彈出菜單事件。

  2. 我們再具體一點(diǎn)講,其實(shí)我們需要做的就是替換掉瀏覽器默認(rèn)的右鍵事件。通過查閱 MDN 我們可以得知,window 對象存在一個(gè)叫做 contextMenus 的事件。
    image.png

  3. 那接下來就好辦了,我們直接替換這個(gè)事件為我們的自定義事件即可。(這里阻止默認(rèn)事件需要調(diào)用 e.preventDefault 方法。)
    image.png
    然后我們在隨便一個(gè)全屏的組件引入這個(gè)函數(shù),我們來測試一下,看看效果
    2.gif

  4. 嗯,現(xiàn)在已經(jīng)不會(huì)彈出瀏覽器默認(rèn)的菜單了。那么接下來要做的就是如何讓我們寫好的菜單呈現(xiàn)到頁面上。首先第一點(diǎn),我們需要明確告訴這個(gè)組件你的父元素是誰
    我們上面只是臨時(shí)創(chuàng)造了一個(gè)簡單的 div,但是目前我們還是沒告訴它應(yīng)該渲染到哪里。處理方法也很簡單,這里我提前創(chuàng)建好了一個(gè)很簡單的頁面,并且設(shè)置好了一個(gè)唯一 ID。
    image.png

  5. 那么我們就可以非常輕松的獲得這個(gè)元素。
    image.png

  6. 現(xiàn)在父元素也有了,只需要將我們的 containerEl 元素放入到 scope 里即可。
    不過你需要知道的是,我們這個(gè)元素是不應(yīng)該出現(xiàn)在正常的文檔流里的,因?yàn)樗奈恢檬遣还潭ǖ?#xff0c;所以我們在放進(jìn)去 scope 元素之前,應(yīng)該給它處理成絕對定位類型的元素。
    image.png

  7. 對了,這里需要注意,我們需要給 scope 設(shè)置一個(gè) relative 屬性,來告訴我們的 containerEl 它要在誰的范圍內(nèi)是絕對定位。
    image.png

  8. 接下來我們進(jìn)入到我們的 scope 組件內(nèi)引入這個(gè)函數(shù),調(diào)用一下看看效果。

    image.png
    2.gif
    ok,現(xiàn)在已經(jīng)實(shí)現(xiàn)我們的右鍵彈出菜單的基本功能了。

五. 菜單位置出現(xiàn)的位置

  1. 在這里我們需要用到 clientX,和 clientY 這兩個(gè)屬性。
    image.png

  2. 如果你是第一次看到這個(gè)屬性,那么我簡單介紹一下。
    image.png
    假設(shè)我在屏幕的上點(diǎn)擊了一下(類比上圖的紅點(diǎn)出),那么此時(shí)這個(gè)點(diǎn)到屏幕最左邊的距離就是 clientX,同理到屏幕頂部的距離就是 clientY

  3. 聰明的你一定想到了,那我此時(shí)將 containerEltopleft 的值分別設(shè)置成這兩個(gè)屬性的值,不就恰好會(huì)讓菜單出現(xiàn)在我們的右邊嗎?我們試一下。
    image.png
    然后看看效果:
    3.gif

  4. 目前看起來一切正常,但是我們需要考慮一個(gè)邊界情況。
    image.png
    當(dāng)我們距離屏幕右側(cè)過近的時(shí)候,此時(shí)右鍵會(huì)導(dǎo)致有部分內(nèi)容被遮擋。所以我們要想辦法解決這個(gè)邊界情況。

六. 解決右側(cè)過近的問題

  1. 不要覺得很難,其實(shí)目前我們要做的事情很簡單。
    image.png

  2. 如上圖,我們僅僅只需要去判斷
    scope 的 clientWidth 的長度 - clientX 的長度= 是否大于containerEl 的 offsetWidth ?
    如果大于,則調(diào)轉(zhuǎn) left 的方向?yàn)?right ,并設(shè)置 right=0px 即可。

  3. 如果上面所說的 offsetWidthclientWidth 你還不了解。我強(qiáng)烈建議你請點(diǎn)擊這篇博文先去了解清楚這幾個(gè) width 屬性到底代表著什么意思,因?yàn)閷τ谇岸碎_發(fā)來說,這是極其重要的幾個(gè)屬性。如果你之后要接觸移動(dòng)端,那么這是你必須掌握的知識點(diǎn)。
    你必須知道的 clientWdith,scrollWidth,offsetWidth

  4. 既然知道了原理,那么代碼寫起來就非常簡單了,在此之前在這里我們需要調(diào)整一下 scope.appendChild 的執(zhí)行時(shí)機(jī)。
    image.png
    我們測試一下效果。
    4.gif

七. 增強(qiáng)該函數(shù)的健壯性

  1. 目前這個(gè)框我們無法確保它的唯一性,所以我們還需要改造一下這個(gè)函數(shù)。

  2. 增加一個(gè)變量 isShow ,我們需要知道當(dāng)前的 Menu 菜單是否正在展示。
    image.png

  3. containerElconst 聲明變?yōu)?let 聲明。并將創(chuàng)造時(shí)機(jī)延遲到調(diào)用右鍵時(shí)再創(chuàng)建,這樣我們就能保證每次右鍵制造的這個(gè) Menu 組件是都是全新的。(不然就會(huì)出現(xiàn)沿用上一次 css 屬性,導(dǎo)致樣式錯(cuò)亂的 bug )
    image.png

  4. 獲取 scope 元素的時(shí)機(jī)也推遲到用戶點(diǎn)擊右鍵的時(shí)候再獲取。(因?yàn)橄旅娴?close 函數(shù)也需要用到這個(gè)變量)
    image.png

  5. 拆分兩個(gè)函數(shù),一個(gè)打開 openMenu 函數(shù),一個(gè)關(guān)閉函數(shù) closeMenu。

    image.png
    image.png

  6. 最后在 window.oncontextmenu 的匿名函數(shù)里去調(diào)取這兩個(gè)函數(shù)。
    image.png

  7. 然后我們將這三個(gè)變量暴露出去。
    image.png

八. 右鍵菜單的使用方法

  1. 我們進(jìn)到 scope.vue 組件內(nèi),引入。
    image.png

  2. 這樣我們既可以通過右鍵創(chuàng)建這個(gè)菜單欄,也可以自己在合適的時(shí)間去做一些邏輯判斷手動(dòng)打開。

  3. 效果如下
    5.gif

源碼

  1. Menu.vue 的源碼。
<script lang="ts" setup>
import { ref } from "vue"const menuItemsGroup = [{name: "查看(V)",arrow: true,action: () => {console.log("查看")},},{name: "排序方式(O)",arrow: false,action: () => {console.log("刷新")},},{name: "刷新(E)",arrow: false,action: () => {console.log("刷新")},},{name: "粘貼(P)",arrow: false,action: () => {console.log("刷新")},},{name: "粘貼快捷方式(S)",arrow: false,action: () => {console.log("刷新")},},{name: "新建(W)",arrow: false,action: () => {console.log("刷新")},},{name: "個(gè)性化(R)",arrow: false,action: () => {console.log("刷新")},},
]
</script>
<template><divclass="w-17rem bg-#ECECEC flex flex-col py-0.5rem shadow-[4px_4px_5px_2px_rgba(0,0,0,0.3)]"><divv-for="(item, i) in menuItemsGroup":key="i"@click="item.action"class="w-full h-2.5rem px-3rem text-1.5rem leading-2.5rem text-black hover:bg-white mb-0.3rem":class="[3, 5, 6].includes(i) ? `b-t-1px b-gray` : `static`"><span>{{ item.name }}</span></div></div>
</template>
  1. 這是 openContextMenus 的源碼。
import { h, render } from "vue"import Menu from "./Menu.vue"export function openContextMenus() {let isShow = falselet scope: HTMLElement | null // 拿到桌面元素let containerEl: HTMLDivElement // 創(chuàng)建一個(gè)容器元素,給 render 先用著window.oncontextmenu = function (e: MouseEvent) {e.preventDefault()if (isShow) closeMenu()openMenu(e)}//tips: open the menufunction openMenu(e: MouseEvent) {scope = document.getElementById("PCDesktop")containerEl = document.createElement("div")const vnode = h(Menu)render(vnode, containerEl) //將 vnode 傳遞給 render 函數(shù)containerEl.style.position = "absolute"scope?.appendChild(containerEl) // 1. 為了拿到 offsetWidth,因?yàn)橹挥谐霈F(xiàn)在瀏覽器才會(huì)產(chǎn)生 offsetWidth 屬性值,我們需要先渲染出真實(shí) domconst { offsetWidth } = containerEl //2 .取出 containerEl 的真實(shí)寬度const { clientWidth } = scope! //3. 獲取父元素的 clientWidth 準(zhǔn)備進(jìn)行計(jì)算const { clientX, clientY } = e //4. 取出 click 時(shí)鼠標(biāo)的坐標(biāo)const _X = clientWidth - clientX > offsetWidth ? "left" : "right" //調(diào)整方向const _X_offset = clientWidth - clientX // 如果是需要顯示在左邊,則需要獲取當(dāng)前的差值containerEl.style.top = `${clientY}px`containerEl.style[_X] = _X === "left" ? `${clientX}px` : `${_X_offset}px`isShow = true}//tips: close the menufunction closeMenu() {if (isShow) {render(null, containerEl)scope?.removeChild(containerEl)console.log("清楚")isShow = false}}return {isShow,openMenu,closeMenu,}
}

結(jié)語

最近在實(shí)現(xiàn)一個(gè) window 的全套 UI ,代碼開源到了 github。
image.png
我會(huì)在之后一直更新類似的內(nèi)容,包括拖拽的實(shí)現(xiàn)。
如果你覺得本文對你有幫助,還希望點(diǎn)個(gè)贊

贈(zèng)人玫瑰,手有余香🌹

http://aloenet.com.cn/news/47808.html

相關(guān)文章:

  • 金華專業(yè)做網(wǎng)站建站推廣
  • 互聯(lián)網(wǎng)金融網(wǎng)站設(shè)計(jì)百度收錄查詢工具
  • 模型下載網(wǎng)站開發(fā)流程廣州網(wǎng)頁制作
  • 網(wǎng)站建設(shè)月總結(jié)怎么做百度關(guān)鍵詞排名
  • 網(wǎng)站首頁的動(dòng)態(tài)視頻怎么做的公司seo排名優(yōu)化
  • 給網(wǎng)站做插畫分辨率seo也成搜索引擎優(yōu)化
  • 北京網(wǎng)站建設(shè)天下公司網(wǎng)絡(luò)營銷品牌
  • 公司怎么建網(wǎng)站做推廣日本疫情最新數(shù)據(jù)
  • 棗莊三合一網(wǎng)站開發(fā)百度安裝應(yīng)用
  • 實(shí)時(shí)視頻網(wǎng)站怎么做網(wǎng)站百度推廣
  • 新鄉(xiāng)網(wǎng)站開發(fā)的公司電話在線服務(wù)器網(wǎng)站
  • 黃金網(wǎng)站網(wǎng)址免費(fèi)百度網(wǎng)訊科技有限公司官網(wǎng)
  • 做網(wǎng)站好處小程序制作一個(gè)需要多少錢
  • 簡單做網(wǎng)站的價(jià)格網(wǎng)頁設(shè)計(jì)一般用什么軟件
  • 北京網(wǎng)站優(yōu)化排名推廣站長工具網(wǎng)站查詢
  • 個(gè)人適合建什么網(wǎng)站廈門seo關(guān)鍵詞
  • 垡頭做網(wǎng)站的公司2021年網(wǎng)絡(luò)熱點(diǎn)輿論
  • 四川綿陽網(wǎng)站建設(shè)百度認(rèn)證證書
  • 自己做的網(wǎng)站怎么上網(wǎng)百度站長平臺(tái)快速收錄
  • 專業(yè)做鞋子網(wǎng)站百度競價(jià)排名是什么
  • 中小學(xué)學(xué)校網(wǎng)站建設(shè)seo入門教程seo入門
  • 便宜的網(wǎng)站設(shè)計(jì)企業(yè)查詢官網(wǎng)入口
  • 遂寧網(wǎng)站開發(fā)廣告軟文小故事800字
  • 做社交網(wǎng)站有哪些全世界足球排名前十位
  • 小程序平臺(tái)商城seo搜索引擎優(yōu)化實(shí)戰(zhàn)
  • 建設(shè)企業(yè)網(wǎng)站目的查看域名每日ip訪問量
  • 中工信融營銷型網(wǎng)站建設(shè)百度精準(zhǔn)獲客平臺(tái)
  • 做外貿(mào)翻譯用哪個(gè)網(wǎng)站好百度app安裝免費(fèi)下載
  • 南昌淘寶網(wǎng)站制作公司百度競價(jià)排名廣告定價(jià)
  • 建設(shè)網(wǎng)站目的是什么成人用品哪里進(jìn)貨好