533 lines
17 KiB
Markdown
533 lines
17 KiB
Markdown
---
|
||
title: 自定义右键菜单
|
||
categories: 建站手札
|
||
tags: 网站
|
||
series: webcustom
|
||
abbrlink: 8bdb35fb
|
||
summary: 自定义右键菜单
|
||
date: 2025-08-11 16:02:12
|
||
---
|
||
{% series webcustom %}
|
||
|
||
# 演示
|
||
|
||
本站右键即可查看,和原有菜单相比比较美观
|
||
|
||
# 新建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">
|
||
```
|