Acrylic 主题自定义七:自定义鼠标右键菜单
JS 自定义鼠标右键菜单主要是利用鼠标右键点击事件(contextmenu) 来实现
主题配置
在主题配置文件(_config.Acrylic.yml) 中新增配置
菜单结构
在 themes/Acrylic/layout/partial
文件夹下新建 rightMenu.ejs,代码如下👇
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
| <div id="right-menu"> <ul class="right-menu-nav"> <li class="right-menu-nav-item" onclick="history.back()"> <a title="返回"> <i class="fas fa-arrow-left"></i> </a> </li> <li class="right-menu-nav-item" onclick="history.forward()"> <a title="前进"> <i class="fas fa-arrow-right"></i> </a> </li> <li class="right-menu-nav-item" onclick="location.reload()"> <a title="刷新"> <i class="fas fa-redo"></i> </a> </li> <li class="right-menu-nav-item" onclick="acrylic.toTop()"> <a title="回到顶部"> <i class="fas fa-arrow-up"></i> </a> </li> </ul> <hr> <div id="right-menu-img"> <ul class="right-menu-content"> <li id="img-copy" class="right-menu-item"> <a title="复制图片"> <i class="fas fa-copy"></i> <span>复制图片</span> </a> </li> <li id="img-copy-link" class="right-menu-item"> <a title="复制链接"> <i class="fas fa-link"></i> <span>复制链接</span> </a> </li> <li id="img-view" class="right-menu-item"> <a title="新窗口查看"> <i class="fas fa-eye"></i> <span>新窗口查看</span> </a> </li> <li id="img-google-search" class="right-menu-item"> <a title="谷歌搜图"> <i class="fas fa-search"></i> <span>谷歌搜图</span> </a> </li> </ul> </div> <div id="right-menu-link"> <ul class="right-menu-content"> <li id="jump-link" class="right-menu-item"> <a title="跳转链接"> <i class="fas fa-link"></i> <span>跳转链接</span> </a> </li> <li id="copy-link" class="right-menu-item"> <a title="复制链接"> <i class="fas fa-copy"></i> <span>复制链接</span> </a> </li> </ul> </div> <div id="right-menu-post"> <ul class="right-menu-content"> <li class="right-menu-item" onclick="toRandomPost()"> <a title="随便看看"> <i class="fas fa-shuffle"></i> <span>随便看看</span> </a> </li> <li class="right-menu-item"> <a title="博客分类" href="/categories"> <i class="fas fa-cube"></i> <span>博客分类</span> </a> </li> <li class="right-menu-item"> <a title="文章标签" href="/tags"> <i class="fas fa-tags"></i> <span>文章标签</span> </a> </li> <li class="right-menu-item" onclick="acrylic.copyPageUrl()"> <a title="复制地址"> <i class="fas fa-copy"></i> <span>复制地址</span> </a> </li> </ul> </div> <hr> <ul class="right-menu-content"> <li id="right-menu-theme" class="right-menu-item" onclick="acrylic.switchDarkMode()"> <a title=""> <i class="fas"></i> <span></span> </a> </li> <li id="right-menu-comment" class="right-menu-item" onclick="acrylic.toComment()"> <a title="直达评论"> <i class="fas fa-message"></i> <span>直达评论</span> </a> </li> </ul> </div>
|
在 themes/Acrylic/layout/layout.ejs
中引入,需在引入 partial/body
之前引入
1 2 3 4
| <% if(theme.rightMenu){ %> <%- partial('partial/rightMenu', {cache: true}) %> <% } %> <%- partial('partial/body', {cache: true}) %>
|
菜单样式
在 themes/Acrylic/source/css
文件夹下新建 right-menu.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 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
| #right-menu { position: fixed; z-index: 999999; user-select: none; background: var(--ruins-card-bg); box-shadow: var(--ruins-shadow-main); border: var(--style-border); max-width: 240px; overflow: hidden; border-radius: 6px; padding: 0.35rem 0; transition: 0.3s; }
#right-menu:hover { border: var(--style-border-hover); box-shadow: var(--ruins-shadow-theme); }
#right-menu .right-menu-nav { display: flex; justify-content: space-between; text-align: center; line-height: 32px; margin: 0 0.35rem; transition: 0.3s; }
#right-menu .right-menu-nav-item { width: 32px; height: 32px; margin: 0; padding: 0; overflow: hidden; border-radius: 50%; margin: 0 0.1rem; transition: 0.3s; }
#right-menu .right-menu-nav-item > a { cursor: pointer; transition: 0.3s; }
#right-menu .right-menu-nav-item:hover { background-color: var(--ruins-main); box-shadow: var(--ruins-shadow-main); }
#right-menu .right-menu-nav-item:hover a { color: var(--ruins-white); }
#right-menu hr { margin: 8px auto; }
#right-menu .right-menu-content { margin: 0 0.35px; transition: 0.3s; }
#right-menu .right-menu-item { margin: 0.35rem; }
#right-menu .right-menu-item > a { display: block; width: 100%; border-radius: 8px; transition: 0.3s; padding: 0.25rem; cursor: pointer; }
#right-menu .right-menu-item:hover > a { color: var(--ruins-white); background-color: var(--ruins-main); box-shadow: var(--ruins-shadow-main); }
#right-menu .right-menu-item > a i { text-align: center; width: 32px; }
|
在 themes/Acrylic/layout/partial/head.ejs
中引入
1 2 3
| <% if (theme.rightMenu){ %> <link rel="stylesheet" href="/css/right-menu.css"> <% } %>
|
菜单逻辑
在 themes/Acrylic/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
| const node = document.querySelector("#right-menu"); const rightMenuImg = document.querySelector("#right-menu-img"); const imgCopy = document.querySelector("#img-copy"); const imgCopyLink = document.querySelector("#img-copy-link"); const imgView = document.querySelector("#img-view"); const imgSearch = document.querySelector("#img-google-search"); const rightMenuPost = document.querySelector("#right-menu-post"); const comment = document.querySelector("#post-comment"); const rightMenuComment = document.querySelector("#right-menu-comment"); const rightMenuLink = document.querySelector("#right-menu-link"); const jumpLink = document.querySelector("#jump-link"); const copyLink = document.querySelector("#copy-link"); let imgSrc = ""; let linkHref = "";
function initRightMenu() { document.oncontextmenu = function (e) { const event = e || window.event; const tagName = event.target.localName; const pageWidth = window.innerWidth; const pageHeight = window.innerHeight; const x = event.clientX; const y = event.clientY;
show(tagName, event);
const menuWidth = node.offsetWidth; const menuHeight = node.offsetHeight;
node.style = ""; node.style.left = (x < pageWidth - menuWidth * 2 ? x : x - menuWidth) + "px"; node.style.top = (y < pageHeight - menuHeight ? y : y - menuHeight) + "px"; node.style.display = "block"; return false; };
document.onclick = function (e) { if (e.target.id != "right-menu") { node.style = ""; } }; }
function show(tagName, event) { initTheme(); switch (tagName) { case "img": imgSrc = event.target.currentSrc; showImg(); break; case "a": linkHref = event.target.href; showLink(); break; default: showPost(); break; }
addRightMenuClickEvent(); }
function initTheme() { const themeData = sessionStorage.getItem("theme"); const themeTitle = document.querySelector("#right-menu-theme>a"); const themeIcon = document.querySelector("#right-menu-theme>a>i"); const themeText = document.querySelector("#right-menu-theme>a>span"); if (themeData === "light") { themeIcon.classList.remove("fa-sun"); themeIcon.className += " fa-moon"; themeTitle.setAttribute("title", "切换黑暗模式"); themeText.innerHTML = "黑暗模式"; } else { themeIcon.classList.remove("fa-moon"); themeIcon.className += " fa-sun"; themeTitle.setAttribute("title", "切换明亮模式"); themeText.innerHTML = "明亮模式"; } }
function showImg() { rightMenuImg.style.display = "block"; rightMenuPost.style.display = "none"; rightMenuLink.style.display = "none"; }
function showLink() { rightMenuLink.style.display = "block"; rightMenuImg.style.display = "none"; rightMenuPost.style.display = "none"; }
function showPost() { showComent(); rightMenuImg.style.display = "none"; rightMenuPost.style.display = "block"; rightMenuLink.style.display = "none"; }
function showComent() { if (comment) { rightMenuComment.style.display = "block"; } else { rightMenuComment.style.display = "none"; } }
function addRightMenuClickEvent() { imgCopy.addEventListener("click", () => acrylic.copyImage(imgSrc)); imgCopyLink.addEventListener("click", () => acrylic.copyImageLink(imgSrc)); imgView.addEventListener("click", () => window.open(imgSrc)); imgSearch.addEventListener("click", () => window.open(`https://www.google.com.hk/searchbyimage?image_url=${imgSrc}`) ); jumpLink.addEventListener("click", () => window.open(linkHref)); copyLink.addEventListener("click", () => acrylic.copyLink(linkHref)); }
initRightMenu();
|
在 themes/Acrylic/layout/partial/body.ejs
中引入
1 2 3
| <% if(theme.rightMenu){ %> <script type="text/javascript" src="/js/rightMenu.js"></script> <% } %>
|
功能方法
切换黑暗/明亮模式
原有的切换黑暗/明亮模式功能方法需要进行修改,将右键菜单也进行覆盖
代码文件位置:themes/Acrylic/source/js/main.js
将原有的方法代码替换成下面👇的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| static switchDarkMode() { let rightMenuThemeTitle = document.querySelector("#right-menu-theme>a"); let rightMenuThemeIcon = document.querySelector("#right-menu-theme>a>i"); let rightMenuThemeText = document.querySelector("#right-menu-theme>a>span"); const nowMode = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light' if (nowMode === 'light') { document.documentElement.setAttribute('data-theme', 'dark') sessionStorage.setItem('theme', 'dark') utils.snackbarShow(GLOBALCONFIG.lang.theme.dark, false, 2000) rightMenuThemeIcon.classList.remove("fa-moon"); rightMenuThemeIcon.className += " fa-sun"; rightMenuThemeTitle.setAttribute("title", "切换明亮模式"); rightMenuThemeText.innerHTML = "明亮模式"; } else { document.documentElement.setAttribute('data-theme', 'light') sessionStorage.setItem('theme', 'light') utils.snackbarShow(GLOBALCONFIG.lang.theme.light, false, 2000) rightMenuThemeIcon.classList.remove("fa-sun"); rightMenuThemeIcon.className += " fa-moon"; rightMenuThemeTitle.setAttribute("title", "切换黑暗模式"); rightMenuThemeText.innerHTML = "黑暗模式"; } }
|
直达评论
新增直达评论功能
代码文件位置:themes/Acrylic/source/js/main.js
代码如下👇
1 2 3 4 5 6 7
| static toComment() { window.scrollTo({ top: document.getElementById("post-comment").offsetTop, left: 0, behavior: "smooth", }); }
|
复制图片
新增复制图片功能
复制图片需要将图片转成二进制数据进行处理,所以我们需要先封装图片转二进制方法
代码文件位置:themes/Acrylic/source/js/utils.js
代码如下👇
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| imageToBlob: (imageURL) => { const img = new Image(); const c = document.createElement("canvas"); const ctx = c.getContext("2d"); img.crossOrigin = "Anonymous"; img.src = imageURL; return new Promise((resolve) => { img.onload = function () { c.width = this.naturalWidth; c.height = this.naturalHeight; ctx.drawImage(this, 0, 0); c.toBlob( (blob) => { resolve(blob); }, "image/png", 0.75 ); }; }); };
|
代码文件位置:themes/Acrylic/source/js/main.js
代码如下👇
1 2 3 4 5 6 7 8 9 10
| static async copyImage(imageURL) { try { const blob = await utils.imageToBlob(imageURL); const item = new ClipboardItem({ "image/png": blob }); navigator.clipboard.write([item]); utils.snackbarShow(GLOBALCONFIG.lang.copy.success, false, 2000); } catch (err) { utils.snackbarShow(GLOBALCONFIG.lang.copy.error, false, 2000); } }
|
复制链接
新增图片和超链接复制链接的功能
代码文件位置:themes/Acrylic/source/js/main.js
代码如下👇
1 2 3 4 5 6
| static copyImageLink(imageURL) { utils.copy(imageURL); } static copyLink(herf) { utils.copy(herf); }
|
文章后期可能会更新