本文來自於 神奇的程序員 的分享好文,點擊閱讀原文查看做者的掘金連接。感謝做者的文章✌️css
前言
瀏覽器裏右鍵時會有一個默認的菜單,在個人開源項目中正好有自定義右鍵菜單的需求,在npm庫找了下與之相關的包,發現都是以組件形式實現的,感受那種作法太過繁瑣。html
因而,我就想着能不能像vue的內置指令那樣,綁定到元素上,在這個元素上右鍵就能出現右鍵菜單,這樣作就方便不少了。前端
看了下vue的自定義指令文檔後,通過一番折騰,終於實現個人這個想法,本文就跟你們分享下個人實現思路以及過程,歡迎各位感興趣的開發者閱讀本文。vue
實現思路
Vue中有不少內置指令,例如:v-if
、v-for
、v-model
,它除了這些內置指令外,還容許咱們開發者本身註冊指令,來實現咱們想實現的效果,對Vue自定義指令不熟悉的開發者能夠先看一下文檔:自定義指令。程序員
接下來,就跟你們講一下個人實現思路:web
-
佈局右鍵菜單,編寫樣式vuex
-
將右鍵菜單須要的用到的數據在vuex中進行定義npm
-
全局註冊一個指令,命名爲
rightClick
編程 -
攔截被綁定元素的
oncontextmenu
事件,對組件傳過來的值進行處理json -
更新vuex裏的右鍵菜單數據,觸發右鍵菜單顯示
實現過程
接下來,就跟你們分享下個人實現過程。
佈局右鍵樣式
咱們先來看看這個組件須要哪些數據才能讓其顯示在鼠標所點的位置。
-
它的顯隱狀態,即:元素css的 display
屬性 -
它的位置,即:元素css的 left
、top
屬性 -
它的文本數據,即:右鍵菜單要展現的內容,經過 v-for
來渲染 -
它的事件處理函數,即:右鍵菜單中選項點擊時,要進行的事件處理
咱們在項目中找一個公用組件,確保這個組件會被渲染,在組件的template
中加入下述代碼。
<!--右鍵菜單-->
<div
id="rightMenuDom"
class="right-menu"
:style="{
display: rightMenuStatus,
top: rightMenuTop,
left: rightMenuLeft
}"
>
<ul>
<!--分爲2組渲染-->
<li>
<span
v-for="item in rightMenuList"
:key="item.id"
v-show="item.id <= 3"
@click="item.handler"
>{{ item.text }}
</span>
</li>
<li>
<span
v-for="item in rightMenuList"
:key="item.id"
v-show="item.id > 3"
@click="item.handler"
>{{ item.text }}
</span>
</li>
</ul>
</div>
</div>
隨後,在組件的mounted
生命週期中添加全局點擊事件的監聽,目的是在點擊任意位置後隱藏右鍵菜單。
mounted() {
// 監聽全局點擊事件
document.addEventListener("click", () => {
// 隱藏右鍵菜單
this.$store.commit("updateRightMenuStatus", {
status: "none",
left: "0px",
top: "0px"
});
});
}
緊接着,在組件的computed
中獲取Vuex中定義的數據,用於渲染右鍵菜單。
computed: {
// 右鍵菜單顯隱狀態
rightMenuStatus(): string {
return this.$store.state.rightMenu.status;
},
// 右鍵菜單距離瀏覽器頂部高度
rightMenuTop(): string {
return this.$store.state.rightMenu.top;
},
// 右鍵菜單距離瀏覽器左邊長度
rightMenuLeft(): string {
return this.$store.state.rightMenu.left;
},
// 右鍵菜單列表內容
rightMenuList(): [] {
return this.$store.state.rightMenu.list;
}
}
最後,給它編寫css樣式。
// 右鍵菜單樣式
.right-menu {
position: fixed;
left: 0;
top: 0;
width: 166px;
height: auto;
background-color: rgb(242, 242, 242);
border: solid 1px #C2C1C2;
box-shadow: 0 10px 10px #C2C1C2;
display: none;
border-radius: 5px;
ul {
padding: 0;
margin: 0;
font-size: 15px;
li {
list-style: none;
box-sizing: border-box;
padding: 6px 0;
border-bottom: 1px solid rgb(216, 216, 217);
&:nth-child(1) {
padding-top: 2px;
}
&:nth-last-child(1) {
border-bottom: none;
}
span {
display: block;
height: 20px;
line-height: 20px;
padding-left: 16px;
&:hover {
background-color: #0070F5;
cursor: pointer;
color: #FFFFFF;
}
}
}
}
}
在Vuex中定義數據
在vuex的配置文件中,找到state
屬性,添加下述代碼。
-
status
組件的顯隱狀態 -
top
組件距離瀏覽器可視區域頂部的距離 -
left
距離瀏覽器可視區域左邊的距離 -
list
組件須要的文本數據和與之對應的事件處理函數
rightMenu: {
status: "none",
top: "0px",
left: "0px",
list: []
}
隨後在mutations
中添加更新數據的方法。
// 更新右鍵菜單數據
updateRightMenuStatus(state, menuObj: rightMenuAttribute) {
state.rightMenu.status = menuObj.status;
state.rightMenu.top = menuObj.top;
state.rightMenu.left = menuObj.left;
state.rightMenu.list = menuObj.list;
}
註冊全局指令
咱們在vue的入口文件:main.ts
中,註冊一個全局指令rightClick
。
-
el
爲咱們綁定指令的元素 -
binding
裏包含了指令傳過來的參數
app.directive("rightClick", (el, binding) => {
});
攔截右鍵事件處理指令參數
上面咱們註冊了一個全局指令,咱們須要在它的函數內部爲指令所綁定的元素重寫其點擊事件,處理指令傳過來的參數。
-
將事件對象放進一個數組中 -
將每個右鍵菜單的文本數據和與之對應的時間處理函數放進json數組中 -
獲取鼠標點擊的位置,使用 commit
更新Vuex中的相關數據,渲染頁面
el.oncontextmenu = function(e: MouseEvent) {
const textArray = binding.value.text;
const handlerObj = binding.value.handler;
// 事件處理數組
const handlerArray = [];
// 處理好的右鍵菜單
const menuList = [];
// 將事件處理函數放入數組中
for (const key in handlerObj) {
handlerArray.push(handlerObj[key]);
}
// 追加右鍵菜單數據
for (let i = 0; i < textArray.length; i++) {
// 右鍵菜單對象, 添加名稱
const menuObj = {
text: textArray[i],
handler: handlerArray[i],
id: i + 1
};
menuList.push(menuObj);
}
// 鼠標點的座標
const oX = e.clientX;
const oY = e.clientY;
// 右鍵菜單出現後的位置
store.commit("updateRightMenuStatus", {
status: "block",
left: oX + "px",
top: oY + "px",
list: menuList
});
return false;
};
在組件中使用指令
完成上述操做後,咱們就已經實現了右鍵自定義菜單的指令,接下來,咱們來看看如何在組件中使用咱們註冊的指令。
在你想要綁定右鍵菜單的html
元素上添加v-right-click
,以下所示:
<li
class="row-panel"
v-right-click="rightMenuObj"
>
</li>
在組件的data
中定義右鍵菜單須要的數據,即上面代碼中聲名的rightMenuObj
。
// 右鍵菜單對象,菜單內容和處理事件
rightMenuObj: {
text: [
"查看資料",
"複製用戶id",
"移除該會話",
"在聯繫人中查看",
"在單聊窗口中打開",
"會話置頂"
],
handler: {
checkingData() {
console.log("查看資料點擊事件");
},
copyId() {
console.log("複製用戶id點擊事件");
},
removeItem() {
console.log("移除會話點擊事件");
},
showContact() {
console.log("在聯繫人中查看");
},
showSingleChat() {
console.log("在單聊窗口中打開");
},
topConversation() {
console.log("會話置頂");
}
}
}
隨後,咱們就能夠運行看效果了,以下所示,已經成功實現了咱們想要的效果。
圖片過大,微信沒法加載,可點擊下方閱讀原文進行查看。
代碼地址
本文中演示所用的組件GitHub地址以下:
msg-list.vue
main.ts
main-content.vue
main-content.scss
index.ts
寫在最後
-
公衆號沒法外鏈,若是文中有連接,可點擊下方閱讀原文查看😊
·END·
匯聚精彩的免費實戰教程
喜歡本文,點個「在看」告訴我
![](http://static.javashuo.com/static/loading.gif)
本文分享自微信公衆號 - 圖雀社區(tuture-dev)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。