博客的右键菜单,本质上很简单,就是在当前 Html 界面劫持右键单击事件,禁止默认右键弹出,把自己的右键菜单在当前鼠标位置展示出来。
实现思路
- 核心技术:自定义网页右键菜单
- 实现流程:
- 建立右键菜单:通过 hexo 注入定义,自定义 css 实现样式管理
- 劫持右键单击事件: js 实现,关闭默认行为,展示自定义的菜单
- 原始右键功能:为了方便有需要的朋友,将
Ctrl 右键
作为原始右键提供出来 - 展示提示信息:记录当前右键单击次数,在一定次数时展示提示信息以方便需要使用原始右键菜单的访客
实现过程
建立右键菜单
为了不影响正常数据加载,我决定在 BodyEnd 注入该代码段
在 source/_inject
文件夹创建 bodyEnd.ejs
文件,在 scripts/page.js
中引入该注入文件:
hexo.extend.filter.register('theme_inject', function(injects) {
injects.bodyEnd.file('default', "source/_inject/bodyEnd.ejs");
});
bodyEnd.ejs
文件写入
<div id="tooltip-rightmenu" class="tooltip-rightmenu">如需原始右键菜单请按下 <strong>Ctrl 右键</strong></div>
<div id="rightmenu-wrapper" style="">
<ul class="list-v rightmenu" id="rightmenu-content">
<li class="navigation menuNavigation-Content">
<a class="nav icon-only fix-cursor-default" onclick="history.back()"><i class="iconfont icon-zuojiantou1"></i></a>
<a class="nav icon-only fix-cursor-default" onclick="history.forward()"><i class="iconfont icon-youjiantou1"></i></a>
<a class="nav icon-only fix-cursor-default" onclick="window.location.reload()"><i class="iconfont icon-shuaxin"></i></a>
<a aria-label="TOP" href="#" role="button"><i class="iconfont icon-xiangshang"></i></a>
</li>
<hr class="menuLoad-Content" style="display: block;">
<li class="menuLoad-Content" style="display: block;">
<a class="vlts-menu fix-cursor-default" target="_self" href="javascript:;" data-toggle="modal" data-target="#modalSearch" aria-label="Search">
<span>
<i class="iconfont icon-sousuo1 rightmenu-icon"></i>
站内搜索
</span>
</a>
</li>
<li class="menuLoad-Content" style="display: block;">
<a class="vlts-menu fix-cursor-default" href="https://www.zywvvd.com/messagebd/" data-group="link">
<span>
<i class="iconfont icon-yangshi_icon_tongyong_chat rightmenu-icon"> </i>
留言吐槽
</span>
</a>
</li>
<li class="menuLoad-Content" style="display: block;">
<a class="vlts-menu fix-cursor-default" id="help" target="_blank" rel="noopener" href="https://www.foreverblog.cn/go.html" data-group="link">
<span>
<i class="iconfont icon-a-BlackHole rightmenu-icon"></i>
虫洞穿梭
</span>
</a>
</li>
<a id="scroll-top-button" aria-label="TOP" href="#" role="button" style="bottom: 20px; right: 52.6364px;">
<i class="iconfont icon-xiangshangjiantou" aria-hidden="true"></i>
</a>
<hr class="menuLoad-Content" style="display: block;">
</ul>
</div>
<link href="/css/custom.css"type="text/css"rel="stylesheet"/>
<script src="/vvd_js/right_menu.js" type="text/javascript"></script>
<link href="/css/right_menu.css"type="text/css"rel="stylesheet"/>
代码作为示例,事实上需要按照自己需求调整,核心目的是建立右键菜单。
定义右键菜单样式
在 source/css/custom.css
中添加图标 (我是放在这里的)
@font-face {
font-family: "iconfont"; /* Project id 3859637 */
src: url('//at.alicdn.com/t/c/font_3859637_jxuiuw0et3.woff2?t=1705932159225') format('woff2'),
url('//at.alicdn.com/t/c/font_3859637_jxuiuw0et3.woff?t=1705932159225') format('woff'),
url('//at.alicdn.com/t/c/font_3859637_jxuiuw0et3.ttf?t=1705932159225') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-xiangshang:before {
content: "e601";
}
.icon-zuojiantou:before {
content: "e64e";
}
.icon-xiangshang2:before {
content: "e76e";
}
.icon-xiangyoujiantou:before {
content: "e65f";
}
.icon-youjiantou:before {
content: "e62d";
}
.icon-sousuo1:before {
content: "e665";
}
.icon-shuaxin:before {
content: "e6b2";
}
.icon-youjiantou1:before {
content: "e644";
}
.icon-youjiantou2:before {
content: "e678";
}
.icon-shuaxin1:before {
content: "ec08";
}
.icon-zuojiantou1:before {
content: "e642";
}
.icon-sousuo2:before {
content: "e612";
}
.icon-zuojiantou2:before {
content: "e629";
}
.icon-xiangshang1:before {
content: "e645";
}
.icon-sousuo3:before {
content: "e6c7";
}
.icon-quanxianfuzhi:before {
content: "e62b";
}
.icon-icon-1:before {
content: "e62c";
}
.icon-xiangshangjiantou:before {
content: "e61f";
}
.icon-liaotianjilu:before {
content: "e663";
}
.icon-24gf-bubblesDots6:before {
content: "e95d";
}
.icon-24gf-bubblesDots4:before {
content: "e95e";
}
.icon-yangshi_icon_tongyong_chat:before {
content: "e664";
}
.icon-41shuoshuo:before {
content: "e658";
}
.icon-git:before {
content: "e799";
}
.icon-duomeit:before {
content: "e621";
}
.icon-meiti:before {
content: "e636";
}
.icon-xuniyingpan:before {
content: "ea6c";
}
.icon-guanyuwomen:before {
content: "e61e";
}
.icon-dingyue:before {
content: "e600";
}
.icon-pengyoufill:before {
content: "e745";
}
.icon-diqiu:before {
content: "e7b9";
}
.icon-wangzhan:before {
content: "e628";
}
.icon-chuansong:before {
content: "e602";
}
.icon-icon-:before {
content: "e62a";
}
.icon-lianjie:before {
content: "eadc";
}
.icon-sousuo:before {
content: "eafe";
}
.icon-jiankong:before {
content: "eb37";
}
.icon-geren:before {
content: "e670";
}
.icon-shuji1:before {
content: "e6b7";
}
.icon-momo:before {
content: "e8d9";
}
.icon-tongji2:before {
content: "e61a";
}
.icon-tongjifenxi-xiangmubiaogetongji:before {
content: "e626";
}
.icon-train1:before {
content: "e742";
}
.icon-ic_fly:before {
content: "e6bb";
}
.icon-a-BlackHole:before {
content: "e95a";
}
在 source/css/right_menu.css
中定义右键菜单样式:
代码语言:text复制重点参考 黑兔小九 大佬
div#rightmenu-wrapper {
display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
display: none;
position: fixed;
z-index: 2147483648;
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
}
ul.list-v.rightmenu {
display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
display: block;
background-color: var(--board-bg-color);
max-width: 240px;
overflow: hidden;
}
ul.list-v {
z-index: 1;
display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
display: none;
position: absolute;
background: var(--color-card);
box-shadow: 0 2px 4px 0px rgba(0,0,0,0.08), 0 4px 8px 0px rgba(0,0,0,0.08), 0 8px 16px 0px rgba(0,0,0,0.08);
-webkit-box-shadow: 0 2px 4px 0px rgba(0,0,0,0.08), 0 4px 8px 0px rgba(0,0,0,0.08), 0 8px 16px 0px rgba(0,0,0,0.08);
margin-top: -6px;
border-radius: 4px;
-webkit-border-radius: 4px;
padding: 8px 0;
}
ul.list-v.rightmenu li.navigation, ul.list-v.rightmenu li.music {
display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
display: -ms-flexbox /* TWEENER - IE 10 */;
display: -webkit-flex /* NEW - Chrome */;
display: flex /* NEW, Spec - Opera 12.1, Firefox 20 */;
display: flex;
justify-content: space-between;
-webkit-justify-content: space-between;
-khtml-justify-content: space-between;
-moz-justify-content: space-between;
-o-justify-content: space-between;
-ms-justify-content: space-between;
}
ul.list-v >li {
white-space: nowrap;
word-break: keep-all;
}
ul.list-v hr {
margin-top: 8px;
margin-bottom: 8px;
}
ul.list-v.rightmenu li.navigation a.nav i, ul.list-v.rightmenu li.music a.nav i {
margin: 0;
width: 32px;
line-height: 32px;
}
ul.list-v >li {
white-space: nowrap;
word-break: keep-all;
}
ul.list-v.rightmenu li.navigation a.nav:first-child, ul.list-v.rightmenu li.music a.nav:first-child {
margin-left: 3px;
}
ul.list-v.rightmenu a.vlts-menu {
text-overflow: ellipsis;
overflow: hidden;
line-height: 36px;
font-weight: normal;
}
.rightmenu-icon{
margin: 0 11px 0 8px;
}
ul.list-v >li>a {
transition: all 0.28s ease;
-webkit-transition: all 0.28s ease;
-khtml-transition: all 0.28s ease;
-moz-transition: all 0.28s ease;
-o-transition: all 0.28s ease;
-ms-transition: all 0.28s ease;
display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
display: block;
color: var(--text-color);
font-size: 1rem;
font-weight: bold;
line-height: 36px;
padding: 0 8px 0 8px;
text-overflow: ellipsis;
margin: 0 4px;
border-radius: 4px;
-webkit-border-radius: 4px;
}
ul.list-v >li>a :hover{
color: var(--link-hover-color)
}
ul.list-v.rightmenu a {
cursor: default;
}
/* 信息提示框 */
.tooltip-rightmenu {
position: fixed;
top: 10%;
left: 50%;
transform: translate(-50%, -50%); /* 居中 */
background: var(--text-color);
color: #fff;
padding: 10px 25px;
border-radius: 5px;
opacity: 0;
z-index: 99;
transition: opacity 1s ease-in-out;
}
.show-tooltip {
opacity: 0.8;
}
js 事件劫持
在 source/vvd_js
中创建 right_menu.js
var right_cilck_num = 0;
window.oncontextmenu = function(e){
// 检查是否按下了Ctrl键
if (e.ctrlKey) {
return true;
}
e.preventDefault(); //阻止浏览器自带的右键菜单显示
var menu = document.getElementById("rightmenu-wrapper");
menu.style.display = "block"; //将自定义的“右键菜单”显示出来
menu.style.left = e.clientX "px"; //设置位置,跟随鼠标
menu.style.top = e.clientY "px";
right_cilck_num = right_cilck_num 1;
if(right_cilck_num %7== 1){
const tooltip = document.getElementById('tooltip-rightmenu');
tooltip.classList.add('show-tooltip');
// 3秒后隐藏提示框
setTimeout(() => {
tooltip.classList.remove('show-tooltip');
}, 3000);
}
}
window.onclick = function(e){ //点击窗口,右键菜单隐藏
var menu = document.getElementById("rightmenu-wrapper");
menu.style.display = "none";
}
效果示例
参考资料
- https://yywen.top/
- https://www.zywvvd.com/notes/coding/web/front-end/html-rightclick-replace/html-rightclick-replace/