参考了LYX的方案进行修改
原教程butterfly博客自定义右键菜单升级版

2022.09.20 加入F12弹窗提示
2022.09.22 修复百度搜索和转到链接功能点击后页面刷新的问题

PUG部分

新建[blogRoot]\themes\butterfly\layout\includes\dorakika\rightmenu.pug,编写以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#rightMenu
.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:rmf.scrollToTop();")
i.fa.fa-arrow-up
.rightMenu-group.rightMenu-line.hide#menu-text
a.rightMenu-item(href="javascript:window.open(\"https://www.baidu.com/s?wd=\"+window.getSelection().toString());")
i.iconfont.icon-baidu
span='百度搜索'
a.rightMenu-item(href="javascript:rmf.copySelect();")
i.fa.fa-copy
span='复制'
.rightMenu-group.rightMenu-line.hide#menu-too
a.rightMenu-item(href="javascript:window.open(window.getSelection().toString());")
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="#post-comment")
i.fas.fa-comment
span='空降评论'
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#menu-too(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="./#post-comment")
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:toRandomPost()")
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_home()==false
a.rightMenu-item(href="javascript:rmf.switchReadMode();")
i.fa.fa-book
span='阅读模式'
a.rightMenu-item(href="javascript:window.location.href=\"/about/\";")
i.fa.fa-info-circle
span='关于本站'

注意:如果你的博客没有about界面请修改以下内容中的about字串

1
2
3
a.rightMenu-item(href="javascript:window.location.href=\"/{% about/\";")
i.fa.fa-info-circle
span='关于本站'

然后在[blogRoot]/themes/butterfly/layout/includes/layout.pug中引入(注意缩进,去掉+)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
doctype html
html(lang=config.language data-theme=theme.display_mode class=htmlClassHideAside)
head
include ./head.pug
body
...

else
include ./404.pug

include ./rightside.pug
!=partial('includes/third-party/search/index', {}, {cache: true})
+ !=partial('includes/rightmenu',{}, {cache:true})
include ./additional-js.pug

CSS部分

注意:css一定要放进主题的css文件夹内

新建[blogRoot]/themes/butterfly/source/css/rightmenu.css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/* rightMenu */
#rightMenu{
display: none;
position: fixed;
width: 160px;
height: fit-content;
top: 10%;
left: 10%;
background-color: var(--card-bg);
border: 1px solid var(--font-color);
border-radius: 8px;
z-index: 100;
}
#rightMenu .rightMenu-group{
padding: 7px 6px;
}
#rightMenu .rightMenu-group:not(:nth-last-child(1)){
border-bottom: 1px solid var(--font-color);
}
#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);
}
#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 .rightMenu-group.rightMenu-line .rightMenu-item *{
height: 40px;
line-height: 40px;
}
.rightMenu-group.hide{
display: none;
}

推荐用原版css,LYX的如果不修改,会在友链界面右键不出菜单

然后在主题配置文件中引入css

1
2
3
4
5
6
inject:
head:
- <link rel="stylesheet" href="/css/rightmenu.css">
- ...
bottom:
- ...

JS部分

创建[blogRoot]/themes/butterfly/source/js/rightmenu.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
console.log(
"Codes uses GPL Licence"
)

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)
};
rmf.copyWordsLink = function () {
let url = window.location.href
let txa = document.createElement("textarea");
txa.value = url;
document.body.appendChild(txa)
txa.select();
document.execCommand("Copy");
document.body.removeChild(txa);
swal({
icon: "success",
text: "复制成功,如转载请注明出处!",
button: false,
timer: 1000,
});
}
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 () {
document.execCommand('Copy', false, null);
//这里可以写点东西提示一下 已复制
swal({
icon: "success",
text: "复制成功,如转载请注明出处!",
button: false,
timer: 1000,
});
}

//回到顶部
rmf.scrollToTop = function () {
btf.scrollToDest(0, 500);
}
rmf.translate = function () {
document.getElementById("translateLink").click();
}

// 右键菜单事件
document.onkeydown = function (event) {
event = (event || window.event);
if (event.keyCode == 17) {
console.log("你知道的太多了");
return;
}
}

function popupMenu() {
//window.oncontextmenu=function(){return false;}
window.oncontextmenu = function (event) {
// if(event.ctrlKey)return true; //ctrl右键原界面
console.log(event.keyCode)
$('.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())){
$('#menu-too').show()
}
if (el.tagName == 'A') {
$('#menu-to').show()
rmf.open = function () {
location.href = el.href
}
rmf.openWithNewTab = function () {
window.open(el.href);
}
rmf.copyLink = function () {
let url = el.href
let txa = document.createElement("textarea");
txa.value = url;
document.body.appendChild(txa)
txa.select();
document.execCommand("Copy");
document.body.removeChild(txa);
}
}
if (el.tagName == 'IMG') {
$('#menu-img').show()
rmf.openWithNewTab = function () {
window.open(el.src);
}
rmf.click = function () {
el.click()
}
rmf.copyLink = function () {
let url = el.src
let txa = document.createElement("textarea");
txa.value = url;
document.body.appendChild(txa)
txa.select();
document.execCommand("Copy");
document.body.removeChild(txa);
}
} else if (el.tagName == "TEXTAREA" || el.tagName == "INPUT") {
$('#menu-paste').show();
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 {
swal({
icon: "info",
text: "请允许读取剪贴板!!",
button: false,
timer: 1000,
})
}
})
}
}
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;
}



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)

//F12弹窗提示
document.onkeydown = function () {
if (window.event && window.event.keyCode == 123) {
event.keyCode = 0;
event.returnValue = true; //可选是否开启F12功能
swal({
icon: "success",
text: "开发者模式已打开,请遵守GPL协议",
button: false,
timer: 1000,
});
}
}

在主题配置文件中引入js以及jquery依赖

1
2
3
4
5
6
7
8
inject:
head:
- ...
bottom:
- ...
- <script type="text/javascript" src="https://cdn1.tianli0.top/npm/jquery@latest/dist/jquery.min.js"></script>
- <script type="text/javascript" src="/js/rightmenu.js"></script>
- ...

注意:如果配置后,复制没有弹窗,请导入sweetalert依赖和安装sweetalert

1
2
3
4
5
6
7
8
9
inject:
head:
- ...
bottom:
- ...
- <script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
- <script src="https://cdn.jsdelivr.net/npm/sweetalert"></script>
//unpkg和jsdelivr二选一
- ...
1
npm install sweetalert --save

iconfont图标

因为少部分图标使用iconfont,你需要自己添加,下载LYX的iconfont图标包,然后解压把里面的东西扔到[blogRoot]/themes/butterfly/source/css里面即可