当前位置: 首页 > ds >正文

网页工具箱 --- 一个强大的浏览器脚本工具

在浏览网页时,有时我们希望能够快速并且方便地执行一些常用操作,比如改变背景色、编辑页面内容或者移除广告等。这时,一个自定义的、可拖动的网页工具箱就显得非常实用。本文将介绍如何通过一个用户脚本来创建这样一个工具箱,它不仅支持多种功能,还可以自由移动位置,非常适合日常使用。

1. 功能概览

网页工具箱提供了如下功能:

  • 改变背景色:快速切换网页的背景颜色。
  • 页面可编辑:将网页转换为可编辑模式,方便用户直接在网页上进行文字修改。
  • 移除广告:一键去除网页中的广告元素。
  • 字体替换:允许用户选择或输入字体,应用到整个网页。
  • 暗黑模式:开启或关闭暗黑模式,减轻眼睛疲劳。
  • 颜色选择器:提供一个界面让用户选择颜色,并复制选中的颜色代码。
  • Markdown笔记本:一个简单的Markdown编辑器和预览器,便于记笔记或写草稿。
  • 显示隐藏元素:显示页面中所有被隐藏的元素。
  • 高亮链接:将所有链接高亮,便于识别。
  • 显示密码:将密码输入框中的内容显示出来。
  • 性能分析:显示页面的加载时间等性能相关信息。
  • 阅读模式:优化页面的阅读体验。
  • 禁用右键限制:取消页面上的右键限制,使右键菜单可用。
  • 放大字体:增大页面上的文字大小,改善阅读体验。
  • 显示图片alt:显示所有图片的alt属性。
  • 页面加载分析:详细展示页面加载的各个阶段所需时间。
  • 谷歌翻译:快速将页面内容翻译成其他语言。
  • 显示所有字体:列出页面上使用的所有字体。
  • 显示外部链接:显示所有从当前页面指向外部网站的链接。

2. 技术实现

  1. 使用JavaScript创建DOM元素,构建工具箱UI。
  2. 利用CSS设置样式,确保工具箱美观且易用。
  3. 实现拖拽功能,允许用户自由移动工具箱。
  4. 使用localStorage保存用户设置,如Markdown笔记内容和预览模式状态。
  5. 动态加载外部库(如Marked.js),用于Markdown渲染。

3. 效果预览

笔记本

在这里插入图片描述

暗黑模式

在这里插入图片描述

4. 使用方法

  1. 将脚本安装到Tampermonkey或类似的用户脚本管理器中。
  2. 刷新网页,你会在右上角看到一个"显示工具箱"按钮。
  3. 点击按钮显示工具箱,然后就可以使用各种功能了。

5. 代码亮点

  1. 模块化设计: 每个功能都被封装成一个对象,便于维护和扩展。
  2. 性能优化: 使用事件委托和延迟加载等技术,确保脚本运行高效。
  3. 用户友好: 提供直观的UI和清晰的功能描述,易于使用。

6. 未来展望

  1. 添加更多实用功能,如网页截图、颜色选择器等。
  2. 优化UI设计,提供主题切换功能。
  3. 增加自定义功能的支持,允许用户添加自己的脚本。

这个工具箱脚本展示了如何利用JavaScript增强网页功能。通过这个项目,我们不仅可以提升日常浏览体验,还能学习到很多实用的web开发技巧。希望这个工具箱能够帮助到大家,也欢迎各位贡献自己的想法,让它变得更加强大和实用!


完整代码

// ==UserScript==
// @name         网页工具箱(可拖动)
// @namespace    http://tampermonkey.net/
// @version      0.5
// @description  将网页功能整理成一个可拖动的工具箱,支持分页展示、功能切换和别名
// @match        *://*/*
// @grant        none
// ==/UserScript==(function () {'use strict';// 创建样式const style = document.createElement('style');style.textContent = `#custom-toolbox {position: fixed;top: 20px;left: 20px;background-color: #f8f9fa;border: 1px solid #dee2e6;border-radius: 5px;padding: 15px;z-index: 9999;max-height: 80vh;overflow-y: auto;box-shadow: 0 0 10px rgba(0,0,0,0.1);font-family: Arial, sans-serif;cursor: move;user-select: none;}#custom-toolbox h3 {margin-top: 0;margin-bottom: 15px;color: #343a40;}#custom-toolbox button {margin: 5px;padding: 8px 12px;background-color: #007bff;color: white;border: none;border-radius: 3px;cursor: pointer;transition: background-color 0.3s;}#custom-toolbox button:hover {background-color: #0056b3;}#custom-toolbox button.active {background-color: #28a745;}#toggle-toolbox {position: fixed;top: 10px;left: 10px;z-index: 10000;padding: 8px 12px;background-color: #28a745;color: white;border: none;border-radius: 3px;cursor: pointer;transition: background-color 0.3s;}#toggle-toolbox:hover {background-color: #218838;}.pagination {display: flex;justify-content: center;margin-top: 15px;}.pagination button {margin: 0 5px;}`;document.head.appendChild(style);// 创建工具箱容器const toolbox = document.createElement('div');toolbox.id = 'custom-toolbox';toolbox.style.display = 'none';// 创建工具箱标题const title = document.createElement('div');title.textContent = '网页工具箱';title.style.cssText = `font-size: 18px;font-weight: bold;color: #333;text-align: center;padding: 10px 0;margin-bottom: 10px;border-bottom: 2px solid #007bff;background: linear-gradient(to right, #f8f9fa, #e9ecef);border-radius: 5px 5px 0 0;text-shadow: 1px 1px 2px rgba(0,0,0,0.1);letter-spacing: 1px;user-select: none;cursor: move;
`;toolbox.appendChild(title);// 添加拖动功能let isDragging = false;let currentX;let currentY;let initialX;let initialY;let xOffset = 0;let yOffset = 0;toolbox.addEventListener("mousedown", dragStart);document.addEventListener("mousemove", drag);document.addEventListener("mouseup", dragEnd);function dragStart(e) {initialX = e.clientX - xOffset;initialY = e.clientY - yOffset;if (e.target === toolbox || e.target === title) {isDragging = true;}}function drag(e) {if (isDragging) {e.preventDefault();currentX = e.clientX - initialX;currentY = e.clientY - initialY;xOffset = currentX;yOffset = currentY;setTranslate(currentX, currentY, toolbox);}}function dragEnd(e) {initialX = currentX;initialY = currentY;isDragging = false;}function setTranslate(xPos, yPos, el) {el.style.transform = `translate3d(${xPos}px, ${yPos}px, 0)`;}// 定义功能列表const features = [{id: 'changeBackground', name: '改变背景色', alias: '换背景', action: function () {document.body.style.backgroundColor = document.body.style.backgroundColor === 'lightblue' ? '' : 'lightblue';}},{id: 'editPage', name: '页面可编辑', alias: '编辑模式', action: function () {document.body.contentEditable = document.body.contentEditable === 'true' ? 'false' : 'true';document.designMode = document.designMode === 'on' ? 'off' : 'on';}},{id: 'removeAds', name: '移除广告', alias: '去广告', action: function () {var elems = document.querySelectorAll("*[class*='ad'],*[id*='ad'],*[class*='banner'],*[id*='banner']");for (var i = 0; i < elems.length; i++) {if (!elems[i].className.includes('header') && !elems[i].id.includes('header')) {elems[i].style.display = elems[i].style.display === 'none' ? '' : 'none';}}}},{id: 'fontReplacer', name: '字体替换', alias: '换字体', action: function () {const commonFonts = ['Arial', 'Helvetica', 'Times New Roman', 'Courier', 'Verdana','Georgia', 'Palatino', 'Garamond', 'Bookman', 'Comic Sans MS','Trebuchet MS', 'Arial Black', 'Impact'];const fontSelector = document.createElement('div');fontSelector.style.cssText = `position: fixed;top: 50%;left: 50%;transform: translate(-50%, -50%);background: white;padding: 20px;border-radius: 8px;box-shadow: 0 4px 12px rgba(0,0,0,0.15);z-index: 10000;font-family: Arial, sans-serif;width: 300px;`;fontSelector.innerHTML = `<h3 style="margin-top: 0; margin-bottom: 15px; text-align: center;">选择字体</h3><select id="font-select" style="width: 100%; padding: 8px; margin-bottom: 15px; border: 1px solid #ccc; border-radius: 4px;">${commonFonts.map(font => `<option value="${font}">${font}</option>`).join('')}</select><input type="text" id="custom-font" placeholder="或输入自定义字体" style="width: calc(100% - 18px); padding: 8px; margin-bottom: 15px; border: 1px solid #ccc; border-radius: 4px;"><div style="display: flex; justify-content: space-between;"><button id="apply-font" style="padding: 8px 15px; background-color: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer;">应用</button><button id="cancel-font" style="padding: 8px 15px; background-color: #f44336; color: white; border: none; border-radius: 4px; cursor: pointer;">取消</button></div>`;document.body.appendChild(fontSelector);document.getElementById('apply-font').onclick = function () {const selectedFont = document.getElementById('custom-font').value || document.getElementById('font-select').value;document.body.style.fontFamily = selectedFont;document.body.removeChild(fontSelector);};document.getElementById('cancel-font').onclick = function () {document.body.removeChild(fontSelector);};}},{id: 'darkMode', name: '暗黑模式', alias: '夜间模式', action: function () {const style = document.getElementById('dark-mode-style');if (style) {style.remove();} else {const newStyle = document.createElement('style');newStyle.id = 'dark-mode-style';newStyle.textContent = `body, body *:not(span) {background-color: #1a1a1a !important;color: #e0e0e0 !important;}span {background-color: transparent !important;color: inherit !important;}a, a:visited {color: #6a9fb5 !important;}img, video {filter: brightness(0.8) contrast(1.2);}input, textarea, select {background-color: #2a2a2a !important;color: #e0e0e0 !important;}button, input[type="submit"], input[type="button"] {background-color: #3a3a3a !important;color: #e0e0e0 !important;}button:hover, input[type="submit"]:hover, input[type="button"]:hover {background-color: #4a4a4a !important;}::-webkit-scrollbar {width: 12px;}::-webkit-scrollbar-track {background: #1a1a1a;}::-webkit-scrollbar-thumb {background-color: #4a4a4a;border-radius: 6px;border: 3px solid #1a1a1a;}::selection {background-color: #264f78;color: #ffffff;}[style*="linear-gradient"] {background-image: linear-gradient(to right, #2a2a2a, #3a3a3a) !important;}span[style*="color:"] {color: inherit !important;opacity: 0.9;}span[style*="background"] {background: transparent !important;}/* 边框处理 */*, *::before, *::after {border-color: rgba(255, 255, 255, 0.2) !important;}[style*="border"] {border-color: rgba(255, 255, 255, 0.2) !important;}div {border-color: rgba(255, 255, 255, 0.2) !important;}`;document.head.appendChild(newStyle);}}},{id: 'colorPicker', name: '颜色选择器', alias: '取色器', action: function () {const colorPicker = document.createElement('div');colorPicker.style.cssText = `position: fixed;top: 20px;right: 20px;background: #ffffff;padding: 15px;border-radius: 8px;box-shadow: 0 4px 12px rgba(0,0,0,0.15);z-index: 10000;font-family: Arial, sans-serif;display: flex;flex-direction: column;align-items: center;`;const colorInput = document.createElement('input');colorInput.type = 'color';colorInput.style.cssText = `width: 100px;height: 40px;border: none;border-radius: 4px;margin-bottom: 10px;cursor: pointer;`;const colorValue = document.createElement('input');colorValue.type = 'text';colorValue.value = '#000000';colorValue.style.cssText = `width: 100px;padding: 5px;border: 1px solid #ccc;border-radius: 4px;text-align: center;font-size: 14px;margin-bottom: 10px;`;const buttonContainer = document.createElement('div');buttonContainer.style.cssText = `display: flex;justify-content: space-between;width: 100%;`;const copyButton = document.createElement('button');copyButton.textContent = '复制';copyButton.style.cssText = `padding: 5px 10px;background-color: #4CAF50;color: white;border: none;border-radius: 4px;cursor: pointer;font-size: 14px;`;const closeButton = document.createElement('button');closeButton.textContent = '关闭';closeButton.style.cssText = `padding: 5px 10px;background-color: #f44336;color: white;border: none;border-radius: 4px;cursor: pointer;font-size: 14px;`;colorInput.oninput = function () {colorValue.value = this.value.toUpperCase();};colorValue.oninput = function () {if (/^#[0-9A-F]{6}$/i.test(this.value)) {colorInput.value = this.value;}};copyButton.onclick = function () {navigator.clipboard.writeText(colorValue.value).then(() => {copyButton.textContent = '已复制';setTimeout(() => copyButton.textContent = '复制', 1000);}).catch(err => console.error('复制失败:', err));};closeButton.onclick = function () {document.body.removeChild(colorPicker);};buttonContainer.appendChild(copyButton);buttonContainer.appendChild(closeButton);colorPicker.appendChild(colorInput);colorPicker.appendChild(colorValue);colorPicker.appendChild(buttonContainer);document.body.appendChild(colorPicker);}},{id: 'markdown-notebook', name: 'Markdown笔记本', alias: '笔记', action: function () {const d = document;if (!d.getElementById('custom-markdown-notebook')) {const n = d.createElement('div');n.id = 'custom-markdown-notebook';n.style.cssText = `position: fixed;top: 50px;left: 50px;width: 300px;height: 420px;background: white;border: 1px solid #ccc;box-shadow: 2px 2px 10px rgba(0,0,0,0.2);z-index: 9999;resize: both;overflow: hidden;font-family: Arial, sans-serif;display: flex;flex-direction: column;`;n.innerHTML = `<div id="notebook-header" style="padding: 8px;background: #f0f0f0;cursor: move;user-select: none;display: flex;justify-content: space-between;align-items: center;font-size: 14px;"><span>Markdown笔记本</span><button id="close-notebook" style="cursor: pointer;border: none;background: none;font-size: 16px;">×</button></div><div id="notebook-content" style="flex-grow: 1;display: flex;flex-direction: column;padding: 10px;overflow: hidden;"><textarea id="notebook-textarea" style="flex-grow: 1;width: calc(100% - 12px);border: 1px solid #ddd;resize: none;margin-bottom: 8px;padding: 5px;font-size: 12px;overflow: auto;"></textarea><div id="notebook-preview" style="display: none;flex-grow: 1;width: calc(100% - 12px);border: 1px solid #ddd;padding: 5px;margin-bottom: 8px;font-size: 12px;overflow: auto;"></div><button id="notebook-toggle" style="padding: 5px 10px;cursor: pointer;background-color: #4CAF50;color: white;border: none;border-radius: 3px;font-size: 12px;">预览 Markdown</button></div>`;d.body.appendChild(n);const header = d.getElementById('notebook-header');const textarea = d.getElementById('notebook-textarea');const previewDiv = d.getElementById('notebook-preview');const toggleBtn = d.getElementById('notebook-toggle');// 拖动功能let isDragging = false;let currentX;let currentY;let initialX;let initialY;let xOffset = 0;let yOffset = 0;function dragStart(e) {initialX = e.clientX - xOffset;initialY = e.clientY - yOffset;if (e.target === header) {isDragging = true;}}function drag(e) {if (isDragging) {e.preventDefault();currentX = e.clientX - initialX;currentY = e.clientY - initialY;xOffset = currentX;yOffset = currentY;n.style.transform = `translate(${currentX}px, ${currentY}px)`;}}function dragEnd(e) {initialX = currentX;initialY = currentY;isDragging = false;}header.addEventListener('mousedown', dragStart);d.addEventListener('mousemove', drag);d.addEventListener('mouseup', dragEnd);// 关闭笔记本d.getElementById('close-notebook').onclick = function () {n.remove();};// 切换预览模式let isPreviewMode = JSON.parse(localStorage.getItem('markdown-notebook-preview-mode') || 'false');function updatePreviewMode() {if (isPreviewMode) {textarea.style.display = 'none';previewDiv.style.display = 'block';previewDiv.innerHTML = marked.parse(textarea.value);toggleBtn.textContent = '返回编辑';} else {textarea.style.display = 'block';previewDiv.style.display = 'none';toggleBtn.textContent = '预览 Markdown';}localStorage.setItem('markdown-notebook-preview-mode', JSON.stringify(isPreviewMode));}toggleBtn.onclick = function () {if (!window.marked) {alert('Markdown 解析库还未加载完成,请稍后再试。');return;}isPreviewMode = !isPreviewMode;updatePreviewMode();};// 自动保存功能let timer;textarea.oninput = function () {clearTimeout(timer);timer = setTimeout(function () {localStorage.setItem('markdown-notebook-content', textarea.value);}, 500);};// 加载保存的内容const savedContent = localStorage.getItem('markdown-notebook-content');if (savedContent) {textarea.value = savedContent;}// 加载 Marked 库if (!window.marked) {const script = d.createElement('script');script.src = 'https://cdn.jsdelivr.net/npm/marked/marked.min.js';script.onload = function () {console.log('Marked library loaded');updatePreviewMode(); // 在 Marked 库加载完成后更新预览模式};d.head.appendChild(script);} else {updatePreviewMode(); // 如果 Marked 库已经加载,直接更新预览模式}} else {alert('Markdown笔记本已经打开');}}},{id: 'showHiddenElements', name: '显示隐藏元素', alias: '显隐元素', action: function () {var elements = document.getElementsByTagName("*");for (var i = 0; i < elements.length; i++) {if (window.getComputedStyle(elements[i]).display === 'none') {elements[i].style.display = 'block';} else {elements[i].style.display = '';}}}},{id: 'highlightLinks', name: '高亮链接', alias: '链接高亮', action: function () {var links = document.getElementsByTagName('a');for (var i = 0; i < links.length; i++) {links[i].style.backgroundColor = links[i].style.backgroundColor === 'yellow' ? '' : 'yellow';links[i].style.color = links[i].style.color === 'black' ? '' : 'black';}}},{id: 'showPasswords', name: '显示密码', alias: '密码可见', action: function () {var p = document.getElementsByTagName('input');for (var i = 0; i < p.length; i++) {if (p[i].type === 'password') {p[i].type = p[i].type === 'password' ? 'text' : 'password';}}}},{id: 'performanceAnalysis', name: '性能分析', alias: '性能', action: function () {var t = performance.timing;alert('页面加载时间: ' + (t.loadEventEnd - t.navigationStart) + 'ms\n DOM加载时间: ' + (t.domComplete - t.domLoading) + 'ms');}},{id: 'readingMode', name: '阅读模式', alias: '阅读', action: function () {var style = document.getElementById('reading-mode-style');if (style) {style.remove();} else {style = document.createElement('style');style.id = 'reading-mode-style';style.textContent = 'body{width:60%;margin:0 auto;font-family:Arial,sans-serif;line-height:1.6;padding:20px;background:#f0f0f0;}img{max-width:100%;}';document.head.appendChild(style);}}},{id: 'disableRightClickRestriction', name: '禁用右键限制', alias: '启用右键', action: function () {document.oncontextmenu = null;document.onselectstart = null;document.ondragstart = null;}},{id: 'enlargeFont', name: '放大字体', alias: '大字体', action: function () {document.body.style.fontSize = document.body.style.fontSize === 'larger' ? '' : 'larger';}},{id: 'showImageAlt', name: '显示图片alt', alias: '图片说明', action: function () {var imgs = document.getElementsByTagName('img');for (var i = 0; i < imgs.length; i++) {if (imgs[i].alt) {var altText = document.getElementById('alt-text-' + i);if (altText) {altText.remove();} else {var txt = document.createElement('span');txt.id = 'alt-text-' + i;txt.textContent = imgs[i].alt;txt.style.display = 'block';txt.style.backgroundColor = 'yellow';txt.style.padding = '5px';imgs[i].parentNode.insertBefore(txt, imgs[i]);}}}}},{id: 'pageLoadAnalysis', name: '页面加载分析', alias: '加载分析', action: function () {var t = performance.timing;alert('Page load time: ' + (t.loadEventEnd - t.navigationStart) + 'ms\n' +'DNS lookup: ' + (t.domainLookupEnd - t.domainLookupStart) + 'ms\n' +'TCP connection: ' + (t.connectEnd - t.connectStart) + 'ms\n' +'Server response: ' + (t.responseStart - t.requestStart) + 'ms\n' +'DOM loading: ' + (t.domComplete - t.domLoading) + 'ms');}},{id: 'googleTranslate', name: '谷歌翻译', alias: '翻译', action: function () {var googleTranslateElement = document.getElementById('google_translate_element');if (googleTranslateElement) {googleTranslateElement.remove();} else {var s = document.createElement('script');s.src = 'https://translate.google.com/translate_a/element.js?cb=googleTranslateElementInit';document.body.appendChild(s);window.googleTranslateElementInit = function () {new google.translate.TranslateElement({pageLanguage: 'auto',layout: google.translate.TranslateElement.InlineLayout.SIMPLE}, 'google_translate_element');};var d = document.createElement('div');d.id = 'google_translate_element';d.style.position = 'fixed';d.style.top = '0';d.style.left = '0';d.style.zIndex = '9999';document.body.appendChild(d);}}},{id: 'showAllFonts', name: '显示所有字体', alias: '字体列表', action: function () {var fonts = [];var elements = document.getElementsByTagName('*');for (var i = 0; i < elements.length; i++) {var font = window.getComputedStyle(elements[i]).getPropertyValue('font-family');if (fonts.indexOf(font) === -1) fonts.push(font);}alert('Fonts used on this page:\n\n' + fonts.join('\n'));}},{id: 'showExternalLinks', name: '显示外部链接', alias: '外链', action: function () {var links = document.getElementsByTagName('a');var external = [];for (var i = 0; i < links.length; i++) {if (links[i].hostname !== window.location.hostname) external.push(links[i].href);}if (external.length > 0) alert('External links:\n\n' + external.join('\n'));else alert('No external links found on this page.');}}];// 定义展示顺序(使用别名)const displayOrder = ['换背景', '编辑模式', '去广告', '笔记', '夜间模式', '换字体', '显隐元素', '链接高亮', '密码可见', '性能', '阅读', '启用右键', '大字体', '图片说明', '加载分析', '翻译', '字体列表', '外链', '取色器'];// 每页显示的按钮数量const buttonsPerPage = 5;// 当前页码let currentPage = 1;// 创建分页按钮function createPaginationButtons() {const paginationContainer = document.createElement('div');paginationContainer.className = 'pagination';paginationContainer.style.cssText = `display: flex;justify-content: space-between;padding: 10px;background-color: #f8f9fa;border-top: 1px solid #dee2e6;position: sticky;bottom: 0;`;const prevButton = document.createElement('button');prevButton.textContent = '上一页';prevButton.style.flex = '1';prevButton.addEventListener('click', () => {if (currentPage > 1) {currentPage--;renderButtons();}});const nextButton = document.createElement('button');nextButton.textContent = '下一页';nextButton.style.flex = '1';nextButton.addEventListener('click', () => {if (currentPage < Math.ceil(displayOrder.length / buttonsPerPage)) {currentPage++;renderButtons();}});const closeButton = document.createElement('button');closeButton.textContent = '关闭';closeButton.style.flex = '1';closeButton.addEventListener('click', () => {toolbox.style.display = 'none';toggleButton.style.display = 'block';});paginationContainer.appendChild(prevButton);paginationContainer.appendChild(nextButton);paginationContainer.appendChild(closeButton);toolbox.appendChild(paginationContainer);}// 渲染按钮function renderButtons() {const buttonsContainer = document.getElementById('buttons-container') || document.createElement('div');buttonsContainer.id = 'buttons-container';buttonsContainer.innerHTML = '';const start = (currentPage - 1) * buttonsPerPage;const end = start + buttonsPerPage;for (let i = start; i < end && i < displayOrder.length; i++) {const alias = displayOrder[i];const feature = features.find(f => f.alias === alias);if (feature) {const button = document.createElement('button');button.textContent = feature.name;button.addEventListener('click', () => {feature.action();button.classList.toggle('active');});buttonsContainer.appendChild(button);}}if (!toolbox.contains(buttonsContainer)) {toolbox.insertBefore(buttonsContainer, toolbox.lastChild);}}// 创建切换按钮const toggleButton = document.createElement('button');toggleButton.id = 'toggle-toolbox';toggleButton.textContent = '显示工具箱';toggleButton.addEventListener('click', () => {if (toolbox.style.display === 'none') {toolbox.style.display = 'block';toggleButton.style.display = 'none';} else {toolbox.style.display = 'none';toggleButton.style.display = 'block';}});// 添加元素到页面document.body.appendChild(toolbox);document.body.appendChild(toggleButton);// 创建分页按钮createPaginationButtons();// 初始渲染按钮renderButtons();// 默认隐藏工具箱,只显示切换按钮toolbox.style.display = 'none';toggleButton.style.display = 'block';// 更新工具箱的位置,使其跟随切换按钮function updateToolboxPosition() {const rect = toggleButton.getBoundingClientRect();toolbox.style.top = `${rect.bottom}px`;toolbox.style.left = `${rect.left}px`;}// 在显示工具箱时更新位置toggleButton.addEventListener('click', () => {if (toolbox.style.display === 'none') {updateToolboxPosition();}});// 在窗口大小改变时更新工具箱位置window.addEventListener('resize', () => {if (toolbox.style.display !== 'none') {updateToolboxPosition();}});
})
();
http://www.xdnf.cn/news/3365.html

相关文章:

  • 前端开发 Markdown 编辑器与富文本编辑器详解
  • 长尾关键词SEO优化策略精解
  • Vcpkg C++库管理工具安装
  • Azure AI Foundry实战:从零开始构建智能应用
  • 关于 live555延迟优化之缓存区优化“StreamParser::afterGettingBytes() warning: read”” 的解决方法
  • 晶振:从消费电子到航天领域的时间精度定义者
  • Git仓库目录的所有权问题
  • 2025 新生 DL-FWI 培训
  • Web开发-JavaEE应用SpringBoot栈模版注入ThymeleafFreemarkerVelocity
  • Antd Upload组件连续回车会多次触发文件夹弹窗的bug修复
  • MATLAB绘制饼图(二维/三维)
  • 如何解决服务器文件丢失或损坏的问题
  • linux中systemctl stop 和 kill -9的区别
  • 字节暑期实习-网络运维工程师面经
  • Java学习计划与资源推荐(入门到进阶、高阶、实战)
  • 从 PID 到 Agent:工业控制算法的五代进化史与智能协同革命
  • CentOS网络之network和NetworkManager深度解析
  • 小刚说C语言刷题—1462小明的游泳时间
  • spring中关键字Assert和jdk的assert关键字
  • finereport普通报表设置冻结列后实现点击单元格整行背景变色
  • Kaamel白皮书:MCP安全实践
  • 司南评测集社区 4 月上新一览
  • 宝塔面板运行docker的jenkins
  • openharmony 4.1 运行busybox工具包(保姆教程)
  • HAproxy+keepalived+tomcat部署高可用负载均衡实践
  • 【Python】基于Python的图像分类:从基础CNN到ResNet的全面解析
  • ag-grid-react 列表导出csv列表getDataAsCsv (自定义导出列表配置)自定义新增,修改导出内容
  • 印刷企业绩效考核管理制度与绩效优化路径
  • 在Java中使用Files类的copy()方法复制文件的示例
  • B/S架构:定义、原理及其在软件测试中的应用