533 lines
18 KiB
Markdown
533 lines
18 KiB
Markdown
---
|
|
title: 自定义右键菜单
|
|
categories: 建站手札
|
|
tags: 网站
|
|
series: webcustom
|
|
abbrlink: 8bdb35fb
|
|
cover: https://pic.biss.click/image/9c4021c3-3111-4e19-acca-52ec899aa0b4.webp
|
|
summary: >-
|
|
这篇文章介绍了如何在自定义右键菜单中添加各种功能,包括返回、前进、刷新、滚动到页面不同位置、复制文本、搜索页面、打开链接、粘贴内容、复制本文地址、在新窗口打开链接、保存图片、随机文章浏览、切换深色模式、繁简转换、阅读模式以及隐私声明、Cookie协议和版权声明等。同时,文章还提供了创建Pug文件和JavaScript文件的步骤,详细说明了如何编写右键菜单的HTML结构和交互逻辑。
|
|
date: 2025-08-11 16:02:12
|
|
---
|
|
|
|
# 演示
|
|
|
|
本站右键即可查看,和原有菜单相比比较美观
|
|
|
|
# 新建pug文件
|
|
|
|
在 `\themes\butterfly\layout\includes`新建 `rightmenu.pug`
|
|
|
|
```pug
|
|
#rightMenu.js-pjax
|
|
.rightMenu-group.rightMenu-small
|
|
a.rightMenu-item(href="javascript:window.history.back();")
|
|
i.fa.fa-arrow-left
|
|
a.rightMenu-item(href="javascript:window.history.forward();")
|
|
i.fa.fa-arrow-right
|
|
a.rightMenu-item(href="javascript:window.location.reload();")
|
|
i.fa.fa-refresh
|
|
a.rightMenu-item(href="javascript:window.scrollTo(0, 0);")
|
|
i.fa.fa-arrow-up
|
|
.rightMenu-group.rightMenu-line.hide#menu-text
|
|
a.rightMenu-item(href="javascript:rmf.copySelect();")
|
|
i.fa.fa-copy
|
|
span='复制'
|
|
a.rightMenu-item(href="javascript:rmf.searchinThisPage();")
|
|
i.fas.fa-search
|
|
span='站内搜索'
|
|
.rightMenu-group.rightMenu-line.hide#menu-too
|
|
a.rightMenu-item(href="javascript:window.open(window.getSelection().toString());window.location.reload();")
|
|
i.fa.fa-link
|
|
span='转到链接'
|
|
.rightMenu-group.rightMenu-line.hide#menu-paste
|
|
a.rightMenu-item(href='javascript:rmf.paste()')
|
|
i.fa.fa-copy
|
|
span='粘贴'
|
|
.rightMenu-group.rightMenu-line.hide#menu-post
|
|
a.rightMenu-item(href="javascript:rmf.copyWordsLink()")
|
|
i.fa.fa-link
|
|
span='复制本文地址'
|
|
.rightMenu-group.rightMenu-line.hide#menu-to
|
|
a.rightMenu-item(href="javascript:rmf.openWithNewTab()")
|
|
i.fa.fa-window-restore
|
|
span='新窗口打开'
|
|
a.rightMenu-item(href="javascript:rmf.open()")
|
|
i.fa.fa-link
|
|
span='转到链接'
|
|
a.rightMenu-item(href="javascript:rmf.copyLink()")
|
|
i.fa.fa-copy
|
|
span='复制链接'
|
|
.rightMenu-group.rightMenu-line.hide#menu-img
|
|
a.rightMenu-item(href="javascript:rmf.saveAs()")
|
|
i.fa.fa-download
|
|
span='保存图片'
|
|
a.rightMenu-item(href="javascript:rmf.openWithNewTab()")
|
|
i.fa.fa-window-restore
|
|
span='在新窗口打开'
|
|
a.rightMenu-item(href="javascript:rmf.click()")
|
|
i.fa.fa-arrows-alt
|
|
span='全屏显示'
|
|
a.rightMenu-item(href="javascript:rmf.copyLink()")
|
|
i.fa.fa-copy
|
|
span='复制图片链接'
|
|
.rightMenu-group.rightMenu-line
|
|
a.rightMenu-item(href="javascript:randomPost()")
|
|
i.fa.fa-paper-plane
|
|
span='随便逛逛'
|
|
a.rightMenu-item(href="javascript:rmf.switchDarkMode();")
|
|
i.fa.fa-moon
|
|
span='昼夜切换'
|
|
a.rightMenu-item(href="javascript:rmf.translate();")
|
|
i.iconfont.icon-fanti
|
|
span='繁简转换'
|
|
if is_post()||is_page()
|
|
a.rightMenu-item(href="javascript:rmf.switchReadMode();")
|
|
i.fa.fa-book
|
|
span='阅读模式'
|
|
a.rightMenu-item(href="javascript:pjax.loadUrl(\"/privacy/\");")
|
|
i.fa.fa-info-circle
|
|
span='隐私声明'
|
|
a.rightMenu-item(href="javascript:pjax.loadUrl(\"/cookie/\");")
|
|
i.fa.fa-info-circle
|
|
span='Cookie协议'
|
|
a.rightMenu-item(href="javascript:pjax.loadUrl(\"/cc/\");")
|
|
i.fa.fa-info-circle
|
|
span='版权声明'
|
|
```
|
|
|
|
# 新建js文件
|
|
|
|
创建 `\themes\butterfly\source\js\rightmenu.js`
|
|
|
|
```js
|
|
function setMask() {//设置遮罩层
|
|
if (document.getElementsByClassName("rmMask")[0] !== undefined) {
|
|
return document.getElementsByClassName("rmMask")[0];
|
|
}
|
|
mask = document.createElement('div');
|
|
mask.className = "rmMask";
|
|
mask.style.width = window.innerWidth + 'px';
|
|
mask.style.height = window.innerHeight + 'px';
|
|
mask.style.background = '#fff';
|
|
mask.style.opacity = '.0';
|
|
mask.style.position = 'fixed';
|
|
mask.style.top = '0';
|
|
mask.style.left = '0';
|
|
mask.style.zIndex = 998;
|
|
document.body.appendChild(mask);
|
|
document.getElementById("rightMenu").style.zIndex = 19198;
|
|
return mask;
|
|
}
|
|
|
|
function insertAtCursor(myField, myValue) {
|
|
|
|
//IE 浏览器
|
|
if (document.selection) {
|
|
myField.focus();
|
|
sel = document.selection.createRange();
|
|
sel.text = myValue;
|
|
sel.select();
|
|
}
|
|
|
|
//FireFox、Chrome等
|
|
else if (myField.selectionStart || myField.selectionStart === '0') {
|
|
var startPos = myField.selectionStart;
|
|
var endPos = myField.selectionEnd;
|
|
|
|
// 保存滚动条
|
|
var restoreTop = myField.scrollTop;
|
|
myField.value = myField.value.substring(0, startPos) + myValue + myField.value.substring(endPos, myField.value.length);
|
|
|
|
if (restoreTop > 0) {
|
|
myField.scrollTop = restoreTop;
|
|
}
|
|
|
|
myField.focus();
|
|
myField.selectionStart = startPos + myValue.length;
|
|
myField.selectionEnd = startPos + myValue.length;
|
|
} else {
|
|
myField.value += myValue;
|
|
myField.focus();
|
|
}
|
|
}
|
|
|
|
let rmf = {};
|
|
rmf.showRightMenu = function (isTrue, x = 0, y = 0) {
|
|
let $rightMenu = $('#rightMenu');
|
|
$rightMenu.css('top', x + 'px').css('left', y + 'px');
|
|
|
|
if (isTrue) {
|
|
$rightMenu.show();
|
|
} else {
|
|
$rightMenu.hide();
|
|
}
|
|
}
|
|
rmf.switchDarkMode = function () {
|
|
const nowMode = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light'
|
|
if (nowMode === 'light') {
|
|
activateDarkMode()
|
|
saveToLocal.set('theme', 'dark', 2)
|
|
GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.day_to_night)
|
|
} else {
|
|
activateLightMode()
|
|
saveToLocal.set('theme', 'light', 2)
|
|
GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.night_to_day)
|
|
}
|
|
// handle some cases
|
|
typeof utterancesTheme === 'function' && utterancesTheme()
|
|
typeof FB === 'object' && window.loadFBComment()
|
|
window.DISQUS && document.getElementById('disqus_thread').children.length && setTimeout(() => window.disqusReset(), 200)
|
|
switchPostChart();
|
|
};
|
|
|
|
rmf.copyWordsLink = function () {
|
|
const decodedUrl = decodeURIComponent(window.location.href); // 解码 URL
|
|
navigator.clipboard.writeText(decodedUrl)
|
|
.then(() => {
|
|
Snackbar.show({
|
|
text: '链接复制成功!快去分享吧!',
|
|
pos: 'top-right',
|
|
showAction: false
|
|
});
|
|
})
|
|
};
|
|
|
|
rmf.switchReadMode = function () {
|
|
const $body = document.body
|
|
$body.classList.add('read-mode')
|
|
const newEle = document.createElement('button')
|
|
newEle.type = 'button'
|
|
newEle.className = 'fas fa-sign-out-alt exit-readmode'
|
|
$body.appendChild(newEle)
|
|
|
|
function clickFn() {
|
|
$body.classList.remove('read-mode')
|
|
newEle.remove()
|
|
newEle.removeEventListener('click', clickFn)
|
|
}
|
|
|
|
newEle.addEventListener('click', clickFn)
|
|
}
|
|
|
|
//复制选中文字
|
|
rmf.copySelect = function () {
|
|
navigator.clipboard.writeText(document.getSelection().toString()).then(() => {
|
|
Snackbar.show({
|
|
text: '已复制选中文字!',
|
|
pos: 'top-right',
|
|
showAction: false,
|
|
});
|
|
});
|
|
}
|
|
|
|
//回到顶部
|
|
rmf.scrollToTop = function () {
|
|
document.getElementsByClassName("menus_items")[1].setAttribute("style", "");
|
|
document.getElementById("name-container").setAttribute("style", "display:none");
|
|
btf.scrollToDest(0, 500);
|
|
}
|
|
rmf.translate = function () {
|
|
document.getElementById("translateLink").click();
|
|
}
|
|
rmf.searchinThisPage = () => {
|
|
let mask = setMask(); // 确保 mask 元素存在于 document.body 中
|
|
document.getElementsByClassName("local-search-box--input")[0].value = window.getSelection().toString();
|
|
document.getElementsByClassName("search")[0].click();
|
|
var evt = document.createEvent("HTMLEvents");
|
|
evt.initEvent("input", false, false);
|
|
document.getElementsByClassName("local-search-box--input")[0].dispatchEvent(evt);
|
|
|
|
// 在尝试移除 mask 元素之前检查它是否存在于 document.body 中
|
|
if (document.body.contains(mask)) {
|
|
document.body.removeChild(mask);
|
|
}
|
|
}
|
|
|
|
document.body.addEventListener('touchmove', function (e) {
|
|
|
|
}, {passive: false});
|
|
|
|
function popupMenu() {
|
|
//window.oncontextmenu=function(){return false;}
|
|
window.oncontextmenu = function (event) {
|
|
Snackbar.show({
|
|
text: '按住 Ctrl 再点击右键,即可恢复原界面哦',
|
|
pos: 'bottom-left',
|
|
showAction: false
|
|
});
|
|
if (event.ctrlKey || document.body.clientWidth < 900) return true;
|
|
$('.rightMenu-group.hide').hide();
|
|
if (document.getSelection().toString()) {
|
|
$('#menu-text').show();
|
|
}
|
|
if (document.getElementById('post')) {
|
|
$('#menu-post').show();
|
|
} else {
|
|
if (document.getElementById('page')) {
|
|
$('#menu-post').show();
|
|
}
|
|
}
|
|
var el = window.document.body;
|
|
el = event.target;
|
|
var a = /^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w.-]+)+[\w\-._~:\/?#[\]@!$&'*+,;=]+$/
|
|
if (a.test(window.getSelection().toString()) && el.tagName !== "A") {
|
|
$('#menu-too').show()
|
|
}
|
|
if (el.tagName === 'A') {
|
|
$('#menu-to').show()
|
|
rmf.open = function () {
|
|
if (el.href.indexOf("http://") === -1 && el.href.indexOf("https://") === -1 || el.href.indexOf("blog.june-pj.cn") !== -1) {
|
|
pjax.loadUrl(el.href)
|
|
} else {
|
|
location.href = el.href
|
|
}
|
|
}
|
|
rmf.openWithNewTab = function () {
|
|
window.open(el.href);
|
|
// window.location.reload();
|
|
}
|
|
rmf.copyLink = function () {
|
|
const url = el.href;
|
|
navigator.clipboard.writeText(url);
|
|
Snackbar.show({
|
|
text: '链接复制成功!快去分享吧!',
|
|
pos: 'top-right',
|
|
showAction: false
|
|
});
|
|
};
|
|
}
|
|
if (el.tagName === 'IMG') {
|
|
$('#menu-img').show()
|
|
rmf.openWithNewTab = function () {
|
|
window.open(el.src);
|
|
// window.location.reload();
|
|
}
|
|
rmf.click = function () {
|
|
el.click()
|
|
}
|
|
rmf.copyLink = function () {
|
|
const url = el.src
|
|
navigator.clipboard.writeText(url);
|
|
Snackbar.show({
|
|
text: '链接复制成功!快去分享吧!',
|
|
pos: 'top-right',
|
|
showAction: false
|
|
});
|
|
}
|
|
rmf.saveAs = function () {
|
|
var a = document.createElement('a');
|
|
a.href = el.src;
|
|
// 获取图片的文件名部分
|
|
a.download = el.src.split('/').pop(); // 使用图片的文件名作为下载文件名
|
|
a.style.display = 'none'; // 隐藏下载链接
|
|
document.body.appendChild(a);
|
|
a.click();
|
|
document.body.removeChild(a);
|
|
}
|
|
} else if (el.tagName === "TEXTAREA" || el.tagName === "INPUT") {
|
|
$('#menu-paste').show();
|
|
// rmf.paste=function(){
|
|
// input.addEventListener('paste', async event => {
|
|
// event.preventDefault();
|
|
// const text = await navigator.clipboard.readText();
|
|
// el.value+=text;
|
|
// });
|
|
// }
|
|
rmf.paste = function () {
|
|
navigator.permissions
|
|
.query({
|
|
name: 'clipboard-read'
|
|
})
|
|
.then(result => {
|
|
if (result.state === 'granted' || result.state === 'prompt') {
|
|
//读取剪贴板
|
|
navigator.clipboard.readText().then(text => {
|
|
console.log(text)
|
|
insertAtCursor(el, text)
|
|
})
|
|
} else {
|
|
Snackbar.show({
|
|
text: '请允许读取剪贴板!',
|
|
pos: 'top-center',
|
|
showAction: false,
|
|
})
|
|
}
|
|
})
|
|
}
|
|
}
|
|
let pageX = event.clientX + 10;
|
|
let pageY = event.clientY;
|
|
let rmWidth = $('#rightMenu').width();
|
|
let rmHeight = $('#rightMenu').height();
|
|
if (pageX + rmWidth > window.innerWidth) {
|
|
pageX -= rmWidth + 10;
|
|
}
|
|
if (pageY + rmHeight > window.innerHeight) {
|
|
pageY -= pageY + rmHeight - window.innerHeight;
|
|
}
|
|
mask = setMask();
|
|
window.onscroll = () => {
|
|
rmf.showRightMenu(false);
|
|
window.onscroll = () => {
|
|
}
|
|
if (document.body.contains(mask)) {
|
|
document.body.removeChild(mask);
|
|
}
|
|
}
|
|
|
|
$(".rightMenu-item").click(() => {
|
|
if (document.body.contains(mask)) {
|
|
document.body.removeChild(mask);
|
|
}
|
|
});
|
|
|
|
$(window).resize(() => {
|
|
rmf.showRightMenu(false);
|
|
if (document.body.contains(mask)) {
|
|
document.body.removeChild(mask);
|
|
}
|
|
});
|
|
|
|
mask.onclick = () => {
|
|
if (document.body.contains(mask)) {
|
|
document.body.removeChild(mask);
|
|
}
|
|
};
|
|
|
|
rmf.showRightMenu(true, pageY, pageX);
|
|
return false;
|
|
};
|
|
|
|
window.addEventListener('click', function () {
|
|
rmf.showRightMenu(false);
|
|
});
|
|
}
|
|
|
|
if (!(navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) {
|
|
popupMenu()
|
|
}
|
|
const box = document.documentElement
|
|
|
|
function addLongtabListener(target, callback) {
|
|
let timer = 0 // 初始化timer
|
|
|
|
target.ontouchstart = () => {
|
|
timer = 0 // 重置timer
|
|
timer = setTimeout(() => {
|
|
callback();
|
|
timer = 0
|
|
}, 380) // 超时器能成功执行,说明是长按
|
|
}
|
|
|
|
target.ontouchmove = () => {
|
|
clearTimeout(timer) // 如果来到这里,说明是滑动
|
|
timer = 0
|
|
}
|
|
|
|
target.ontouchend = () => { // 到这里如果timer有值,说明此触摸时间不足380ms,是点击
|
|
if (timer) {
|
|
clearTimeout(timer)
|
|
}
|
|
}
|
|
}
|
|
|
|
addLongtabListener(box, popupMenu)
|
|
```
|
|
|
|
# 创建css
|
|
|
|
创建 `\themes\butterfly\source\css\rightmenu.css`
|
|
|
|
```css
|
|
/* rightMenu */
|
|
[data-theme='light'] #rightMenu{
|
|
display: none;
|
|
position: fixed;
|
|
width: 160px;
|
|
height: fit-content;
|
|
top: 10%;
|
|
left: 10%;
|
|
background-color: var(--card-bg);
|
|
border: 1px solid rgb(210,210,210);;
|
|
border-radius: 8px;
|
|
z-index: 100;
|
|
box-shadow: 3px 3px 5px #88888894;
|
|
background-color: var(--june-white-acrylic1);
|
|
backdrop-filter: blur(30px);
|
|
}
|
|
[data-theme='dark'] #rightMenu{
|
|
display: none;
|
|
position: fixed;
|
|
width: 160px;
|
|
height: fit-content;
|
|
top: 10%;
|
|
left: 10%;
|
|
background-color: var(--card-bg);
|
|
border: 1px solid rgb(210,210,210);;
|
|
border-radius: 8px;
|
|
z-index: 100;
|
|
box-shadow: 3px 3px 5px #88888894;
|
|
background-color: var(--june-black-acrylic1);
|
|
backdrop-filter: blur(30px);
|
|
}
|
|
#rightMenu .rightMenu-group{
|
|
padding: 7px 6px;
|
|
}
|
|
#rightMenu .rightMenu-group:not(:nth-last-child(1)){
|
|
border-bottom: 1px solid rgb(180,180,180);
|
|
}
|
|
#rightMenu .rightMenu-group.rightMenu-small{
|
|
display: flex;
|
|
justify-content: space-between;
|
|
}
|
|
#rightMenu .rightMenu-group .rightMenu-item{
|
|
height: 30px;
|
|
line-height: 30px;
|
|
border-radius: 8px;
|
|
transition: 0.3s;
|
|
color: var(--font-color);
|
|
}
|
|
#rightMenu .rightMenu-group.rightMenu-line .rightMenu-item{
|
|
display: flex;
|
|
height: 40px;
|
|
line-height: 40px;
|
|
padding: 0 4px;
|
|
}
|
|
#rightMenu .rightMenu-group .rightMenu-item:hover{
|
|
background-color: var(--text-bg-hover);
|
|
box-shadow: 0px 0px 5px var(--june-border);
|
|
}
|
|
#rightMenu .rightMenu-group .rightMenu-item i{
|
|
display: inline-block;
|
|
text-align: center;
|
|
line-height: 30px;
|
|
width: 30px;
|
|
height: 30px;
|
|
padding: 0 5px;
|
|
}
|
|
#rightMenu .rightMenu-group .rightMenu-item span{
|
|
line-height: 30px;
|
|
}
|
|
#rightMenu:hover{
|
|
border: 1px solid var(--june-theme);
|
|
}
|
|
#rightMenu .rightMenu-group.rightMenu-line .rightMenu-item *{
|
|
height: 40px;
|
|
line-height: 40px;
|
|
}
|
|
.rightMenu-group.hide{
|
|
display: none;
|
|
}
|
|
.rightMenu-item:hover{
|
|
color:white!important;
|
|
background-color:var(--june-theme)!important;
|
|
}
|
|
```
|
|
|
|
# 引入
|
|
|
|
```yml
|
|
- <script type="text/javascript" src="/js/rightmenu.js"></script>
|
|
- <link rel="stylesheet" href="/css/rightmenu.css">
|
|
``` |