first init
This commit is contained in:
532
source/_posts/custom-right-menu.md
Normal file
532
source/_posts/custom-right-menu.md
Normal file
@@ -0,0 +1,532 @@
|
||||
---
|
||||
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">
|
||||
```
|
||||
Reference in New Issue
Block a user