【个人博客网站】博客美化(二):制作右键菜单

本文最后更新于 about 2 years ago,文中所描述的信息可能已发生改变。

TIP提示

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

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

PUG部分

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

pug
#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字串

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

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

pug
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

css
/* 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

yaml
inject:
  head:
  - <link rel="stylesheet" href="/css/rightmenu.css">
  - ...
  bottom:
  - ...

JS部分

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

js
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依赖

yaml
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

yaml
inject:
  head:
  - ...
  bottom:
  - ...
  - <script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
  - <script src="https://fastly.jsdelivr.net/npm/sweetalert"></script>
  //unpkg和jsdelivr二选一
  - ...
shell
npm install sweetalert --save

iconfont图标

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

【白夜极光】Celestite - 第三方DMM Game Player
【个人博客网站】博客美化(一):制作欢迎弹窗