Compare commits

...

1 Commits

Author SHA1 Message Date
scout
0bb1ddbf88 翻译 2024-11-13 11:55:14 +08:00
9 changed files with 972 additions and 32 deletions

View File

@ -1,56 +1,85 @@
# 丰链工具箱 Chrome 扩展
一个实用的 Chrome 扩展工具集合,目前包含二维码生成器和 Word 转 HTML 功能。
一个实用的 Chrome 扩展工具集合,集成了二维码生成、Word 转 HTML、中英文翻译等实用功能。
## 功能特性
### 二维码生成器 🔲
- 自动获取当前标签页 URL 并生成二维码
- 支持手动输入文本/链接生成二维码
- 高清晰度二维码输出
- 生成高清晰度二维码,支持长文本
- 即时预览生成结果
### Word 转 HTML 转换器 📄
- 支持 .docx 文件转换为 HTML
- 保留原文档格式和样式
- 实时预览转换结果
- 保留文档格式和样式
- 支持下载转换后的 HTML 文件
- 支持一键下载转换后的 HTML 文件
- 自动处理图片和表格
### 中英文翻译 🔤
- 支持 Windows(Ctrl+Q) 和 Mac(Command+Q) 快捷键激活
- 框选任意区域中文文本进行翻译
- 支持中英互译和繁体转换
- 翻译结果即时显示在选区旁边
- 点击任意位置关闭翻译结果
## 系统要求
- Chrome 88+ 或其他基于 Chromium 的浏览器
- Windows/MacOS/Linux 系统均可运行
## 安装方法
### 从 Chrome 商店安装
1. 访问 Chrome 网上应用店
2. 搜索"丰链工具箱"
3. 点击"添加至 Chrome"
### 开发者模式安装
1. 下载本项目代码
2. 打开 Chrome 浏览器,进入扩展程序页面 (chrome://extensions/)
3. 开启"开发者模式"
3. 开启右上角的"开发者模式"
4. 点击"加载已解压的扩展程序"
5. 选择项目文件夹即可完成安装
## 使用方法
1. 点击 Chrome 工具栏中的扩展图标打开工具箱
2. 选择需要使用的功能标签页
3. 根据需要使用相应功能
### 二维码生成
- 自动显示当前页面的二维码
- 可以在输入框中输入其他文本/链接并点击"生成二维码"
1. 点击扩展图标打开工具箱
2. 默认显示当前页面的二维码
3. 可在输入框中输入任意文本/链接
4. 点击"生成二维码"按钮即可
### Word 转 HTML
- 点击选择文件上传 Word 文档
- 等待转换完成后预览效果
- 点击"下载 HTML"保存转换结果
1. 点击"Word转HTML"标签页
2. 点击选择或拖拽上传 Word 文档
3. 等待转换完成后可预览效果
4. 点击"下载HTML"保存文件
### 翻译功能
1. 点击"翻译设置"标签页开启功能
2. 选择目标语言(英文/繁体中文)
3. 在任意页面按下快捷键(Ctrl+Q/Command+Q)
4. 框选需要翻译的文本
5. 翻译结果会显示在选区旁边
## 技术栈
- HTML5
- CSS3
- JavaScript
- HTML5/CSS3
- JavaScript ES6+
- Chrome Extension API
- QRCode.js
- Mammoth.js
- QRCode.js - 二维码生成
- Mammoth.js - Word 文档转换
- 百度翻译 API - 文本翻译
## 开发者
Made by Scout
## 许可证
## 更新日志
[添加许可证类型]
### v1.0.0
- 初始版本发布
- 实现基础功能二维码生成、Word转HTML、翻译
- 支持 Windows/Mac 快捷键

342
background.js Normal file
View File

@ -0,0 +1,342 @@
// 存储注入状态
let injectedTabs = new Set();
// 监听快捷键命令
chrome.commands.onCommand.addListener(async (command) => {
if (command === 'trigger-select') {
try {
const result = await chrome.storage.sync.get(['translateEnabled']);
console.log('Translation enabled status:', result.translateEnabled);
// 只有当明确设置为 false 时才禁用
if (result.translateEnabled === false) {
console.log('Translation is disabled');
return;
}
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
if (tab) {
await injectScriptsIfNeeded(tab.id);
}
} catch (error) {
console.error('Error checking translation status:', error);
}
}
});
// 处理翻译请求
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === 'translate') {
handleTranslation(request.text)
.then(sendResponse)
.catch(error => {
console.error('Translation error:', error);
sendResponse({ error: 'Translation failed' });
});
return true;
}
});
// 注入脚本的函数
async function injectScriptsIfNeeded(tabId) {
try {
// 如果已经注入过,直接发送消息
if (injectedTabs.has(tabId)) {
await chrome.tabs.sendMessage(tabId, { action: 'startSelection' });
return;
}
// 注入 CSS
await chrome.scripting.insertCSS({
target: { tabId },
files: ['content.css']
});
// 先注入 MD5
await chrome.scripting.executeScript({
target: { tabId },
files: ['md5.js']
});
// 再注入 content script
await chrome.scripting.executeScript({
target: { tabId },
files: ['content.js']
});
// 记录已注入状态
injectedTabs.add(tabId);
// 等待一小段时间确保脚本加载完成
await new Promise(resolve => setTimeout(resolve, 100));
// 发送消息
await chrome.tabs.sendMessage(tabId, { action: 'startSelection' });
} catch (error) {
console.error('Injection error:', error);
}
}
// 监听标签页更新,清除注入状态
chrome.tabs.onUpdated.addListener((tabId, changeInfo) => {
if (changeInfo.status === 'loading') {
injectedTabs.delete(tabId);
}
});
// 监听标签页移除,清除注入状态
chrome.tabs.onRemoved.addListener((tabId) => {
injectedTabs.delete(tabId);
});
// 添加 MD5 函数
function md5(string) {
function md5_RotateLeft(lValue, iShiftBits) {
return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
}
function md5_AddUnsigned(lX, lY) {
var lX4, lY4, lX8, lY8, lResult;
lX8 = (lX & 0x80000000);
lY8 = (lY & 0x80000000);
lX4 = (lX & 0x40000000);
lY4 = (lY & 0x40000000);
lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
if (lX4 & lY4) {
return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
}
if (lX4 | lY4) {
if (lResult & 0x40000000) {
return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
} else {
return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
}
} else {
return (lResult ^ lX8 ^ lY8);
}
}
function md5_F(x, y, z) { return (x & y) | ((~x) & z); }
function md5_G(x, y, z) { return (x & z) | (y & (~z)); }
function md5_H(x, y, z) { return (x ^ y ^ z); }
function md5_I(x, y, z) { return (y ^ (x | (~z))); }
function md5_FF(a, b, c, d, x, s, ac) {
a = md5_AddUnsigned(a, md5_AddUnsigned(md5_AddUnsigned(md5_F(b, c, d), x), ac));
return md5_AddUnsigned(md5_RotateLeft(a, s), b);
}
function md5_GG(a, b, c, d, x, s, ac) {
a = md5_AddUnsigned(a, md5_AddUnsigned(md5_AddUnsigned(md5_G(b, c, d), x), ac));
return md5_AddUnsigned(md5_RotateLeft(a, s), b);
}
function md5_HH(a, b, c, d, x, s, ac) {
a = md5_AddUnsigned(a, md5_AddUnsigned(md5_AddUnsigned(md5_H(b, c, d), x), ac));
return md5_AddUnsigned(md5_RotateLeft(a, s), b);
}
function md5_II(a, b, c, d, x, s, ac) {
a = md5_AddUnsigned(a, md5_AddUnsigned(md5_AddUnsigned(md5_I(b, c, d), x), ac));
return md5_AddUnsigned(md5_RotateLeft(a, s), b);
}
function md5_ConvertToWordArray(string) {
var lWordCount;
var lMessageLength = string.length;
var lNumberOfWords_temp1 = lMessageLength + 8;
var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64;
var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
var lWordArray = Array(lNumberOfWords - 1);
var lBytePosition = 0;
var lByteCount = 0;
while (lByteCount < lMessageLength) {
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
lBytePosition = (lByteCount % 4) * 8;
lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition));
lByteCount++;
}
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
lBytePosition = (lByteCount % 4) * 8;
lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
return lWordArray;
}
function md5_WordToHex(lValue) {
var WordToHexValue = "", WordToHexValue_temp = "", lByte, lCount;
for (lCount = 0; lCount <= 3; lCount++) {
lByte = (lValue >>> (lCount * 8)) & 255;
WordToHexValue_temp = "0" + lByte.toString(16);
WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length - 2, 2);
}
return WordToHexValue;
}
function md5_Utf8Encode(string) {
string = string.replace(/\r\n/g, "\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if ((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
} else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
}
var x = Array();
var k, AA, BB, CC, DD, a, b, c, d;
var S11 = 7, S12 = 12, S13 = 17, S14 = 22;
var S21 = 5, S22 = 9, S23 = 14, S24 = 20;
var S31 = 4, S32 = 11, S33 = 16, S34 = 23;
var S41 = 6, S42 = 10, S43 = 15, S44 = 21;
string = md5_Utf8Encode(string);
x = md5_ConvertToWordArray(string);
a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;
for (k = 0; k < x.length; k += 16) {
AA = a; BB = b; CC = c; DD = d;
a = md5_FF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
d = md5_FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
c = md5_FF(c, d, a, b, x[k + 2], S13, 0x242070DB);
b = md5_FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
a = md5_FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
d = md5_FF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
c = md5_FF(c, d, a, b, x[k + 6], S13, 0xA8304613);
b = md5_FF(b, c, d, a, x[k + 7], S14, 0xFD469501);
a = md5_FF(a, b, c, d, x[k + 8], S11, 0x698098D8);
d = md5_FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
c = md5_FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
b = md5_FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
a = md5_FF(a, b, c, d, x[k + 12], S11, 0x6B901122);
d = md5_FF(d, a, b, c, x[k + 13], S12, 0xFD987193);
c = md5_FF(c, d, a, b, x[k + 14], S13, 0xA679438E);
b = md5_FF(b, c, d, a, x[k + 15], S14, 0x49B40821);
a = md5_GG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
d = md5_GG(d, a, b, c, x[k + 6], S22, 0xC040B340);
c = md5_GG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
b = md5_GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
a = md5_GG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
d = md5_GG(d, a, b, c, x[k + 10], S22, 0x2441453);
c = md5_GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
b = md5_GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
a = md5_GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
d = md5_GG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
c = md5_GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
b = md5_GG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
a = md5_GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
d = md5_GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);
c = md5_GG(c, d, a, b, x[k + 7], S23, 0x676F02D9);
b = md5_GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);
a = md5_HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);
d = md5_HH(d, a, b, c, x[k + 8], S32, 0x8771F681);
c = md5_HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);
b = md5_HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);
a = md5_HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);
d = md5_HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);
c = md5_HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);
b = md5_HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);
a = md5_HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);
d = md5_HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);
c = md5_HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);
b = md5_HH(b, c, d, a, x[k + 6], S34, 0x4881D05);
a = md5_HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);
d = md5_HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);
c = md5_HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);
b = md5_HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);
a = md5_II(a, b, c, d, x[k + 0], S41, 0xF4292244);
d = md5_II(d, a, b, c, x[k + 7], S42, 0x432AFF97);
c = md5_II(c, d, a, b, x[k + 14], S43, 0xAB9423A7);
b = md5_II(b, c, d, a, x[k + 5], S44, 0xFC93A039);
a = md5_II(a, b, c, d, x[k + 12], S41, 0x655B59C3);
d = md5_II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);
c = md5_II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);
b = md5_II(b, c, d, a, x[k + 1], S44, 0x85845DD1);
a = md5_II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);
d = md5_II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);
c = md5_II(c, d, a, b, x[k + 6], S43, 0xA3014314);
b = md5_II(b, c, d, a, x[k + 13], S44, 0x4E0811A1);
a = md5_II(a, b, c, d, x[k + 4], S41, 0xF7537E82);
d = md5_II(d, a, b, c, x[k + 11], S42, 0xBD3AF235);
c = md5_II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);
b = md5_II(b, c, d, a, x[k + 9], S44, 0xEB86D391);
a = md5_AddUnsigned(a, AA);
b = md5_AddUnsigned(b, BB);
c = md5_AddUnsigned(c, CC);
d = md5_AddUnsigned(d, DD);
}
return (md5_WordToHex(a) + md5_WordToHex(b) + md5_WordToHex(c) + md5_WordToHex(d)).toLowerCase();
}
async function handleTranslation(text) {
try {
// 获取目标语言设置
const { targetLang } = await chrome.storage.sync.get(['targetLang']);
const to = targetLang || 'en';
const appid = '20241112002200806';
const key = 'preM0becByYCdotRTP_a';
const salt = Date.now().toString();
const from = 'zh';
const str1 = appid + text + salt + key;
const sign = md5(str1);
const params = new URLSearchParams({
q: text,
from: from,
to: to,
appid: appid,
salt: salt,
sign: sign
});
const url = 'https://api.fanyi.baidu.com/api/trans/vip/translate';
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: params.toString()
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
console.log('Translation result:', result);
if (result.error_code) {
throw new Error(result.error_msg || 'Translation failed');
}
return result;
} catch (error) {
console.error('Translation error:', error);
return {
error: true,
message: error.message || 'Translation failed',
trans_result: [{
dst: 'Translation failed: ' + (error.message || 'Unknown error')
}]
};
}
}
// 监听扩展安装或更新
chrome.runtime.onInstalled.addListener(() => {
console.log('Extension installed/updated');
});

30
content.css Normal file
View File

@ -0,0 +1,30 @@
.selection-overlay {
position: fixed;
border: 2px dashed #4285f4;
background: rgba(66, 133, 244, 0.1);
z-index: 10000;
pointer-events: none;
}
.translation-popup {
position: fixed;
background: white;
padding: 10px;
border-radius: 4px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
z-index: 10001;
max-width: 300px;
font-size: 14px;
line-height: 1.4;
}
.page-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.1);
z-index: 9999;
cursor: crosshair;
}

359
content.js Normal file
View File

@ -0,0 +1,359 @@
// 检查是否已经初始化
if (window.translationToolInitialized) {
throw new Error('Translation tool already initialized');
}
window.translationToolInitialized = true;
let isSelecting = false;
let startX, startY;
let selectionElement = null;
let translationPopup = null;
// 监听来自background的消息
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === 'startSelection') {
startSelectionMode();
}
});
function startSelectionMode() {
if (isSelecting) return;
isSelecting = true;
const overlay = document.createElement('div');
overlay.className = 'page-overlay';
document.body.appendChild(overlay);
selectionElement = document.createElement('div');
selectionElement.className = 'selection-overlay';
document.body.appendChild(selectionElement);
document.addEventListener('mousedown', handleMouseDown);
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
document.addEventListener('keydown', handleKeyDown);
}
function handleMouseDown(e) {
if (!isSelecting) return;
startX = e.clientX;
startY = e.clientY;
updateSelectionBox(e);
}
function handleMouseMove(e) {
if (!isSelecting || !startX) return;
updateSelectionBox(e);
}
function handleMouseUp(e) {
if (!isSelecting) return;
const selectedText = getTextFromArea(
Math.min(startX, e.clientX),
Math.min(startY, e.clientY),
Math.abs(e.clientX - startX),
Math.abs(e.clientY - startY)
);
if (selectedText.trim()) {
translateText(selectedText.trim(), e.clientX, e.clientY);
}
cleanup();
}
function updateSelectionBox(e) {
const left = Math.min(startX, e.clientX);
const top = Math.min(startY, e.clientY);
const width = Math.abs(e.clientX - startX);
const height = Math.abs(e.clientY - startY);
selectionElement.style.left = left + 'px';
selectionElement.style.top = top + 'px';
selectionElement.style.width = width + 'px';
selectionElement.style.height = height + 'px';
}
function getTextFromArea(left, top, width, height) {
const elements = document.elementsFromPoint(left + width/2, top + height/2);
for (const element of elements) {
if (element.textContent && element !== selectionElement) {
return element.textContent;
}
}
return '';
}
async function translateText(text, x, y) {
try {
// 通过 chrome.runtime.sendMessage 发送翻译请求
const result = await chrome.runtime.sendMessage({
action: 'translate',
text: text
});
if (result && result.trans_result && result.trans_result[0]) {
showTranslation(result.trans_result[0].dst, x, y);
} else {
showTranslation('Translation failed', x, y);
}
} catch (error) {
console.error('Translation failed:', error);
showTranslation('Translation failed', x, y);
}
}
function showTranslation(translatedText, x, y) {
if (translationPopup) {
translationPopup.remove();
}
translationPopup = document.createElement('div');
translationPopup.className = 'translation-popup';
translationPopup.textContent = translatedText;
translationPopup.style.left = x + 'px';
translationPopup.style.top = (y + 20) + 'px';
document.body.appendChild(translationPopup);
// 点击其他地方关闭翻译框
document.addEventListener('click', function closePopup(e) {
if (e.target !== translationPopup) {
translationPopup.remove();
document.removeEventListener('click', closePopup);
}
});
}
function cleanup() {
isSelecting = false;
const overlay = document.querySelector('.page-overlay');
if (overlay) {
overlay.remove();
}
if (selectionElement) {
selectionElement.remove();
selectionElement = null;
}
startX = startY = null;
document.removeEventListener('mousedown', handleMouseDown);
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
document.removeEventListener('keydown', handleKeyDown);
}
function handleKeyDown(e) {
// 检测 Mac 和 Windows 的按键
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
const triggerKey = isMac ? e.metaKey : e.ctrlKey;
if (e.key === 'Escape' || (triggerKey && e.key === 'q')) {
cleanup();
}
}
// 添加 MD5 函数
function md5(string) {
function md5_RotateLeft(lValue, iShiftBits) {
return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
}
function md5_AddUnsigned(lX, lY) {
var lX4, lY4, lX8, lY8, lResult;
lX8 = (lX & 0x80000000);
lY8 = (lY & 0x80000000);
lX4 = (lX & 0x40000000);
lY4 = (lY & 0x40000000);
lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
if (lX4 & lY4) {
return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
}
if (lX4 | lY4) {
if (lResult & 0x40000000) {
return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
} else {
return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
}
} else {
return (lResult ^ lX8 ^ lY8);
}
}
function md5_F(x, y, z) {
return (x & y) | ((~x) & z);
}
function md5_G(x, y, z) {
return (x & z) | (y & (~z));
}
function md5_H(x, y, z) {
return (x ^ y ^ z);
}
function md5_I(x, y, z) {
return (y ^ (x | (~z)));
}
function md5_FF(a, b, c, d, x, s, ac) {
a = md5_AddUnsigned(a, md5_AddUnsigned(md5_AddUnsigned(md5_F(b, c, d), x), ac));
return md5_AddUnsigned(md5_RotateLeft(a, s), b);
}
function md5_GG(a, b, c, d, x, s, ac) {
a = md5_AddUnsigned(a, md5_AddUnsigned(md5_AddUnsigned(md5_G(b, c, d), x), ac));
return md5_AddUnsigned(md5_RotateLeft(a, s), b);
}
function md5_HH(a, b, c, d, x, s, ac) {
a = md5_AddUnsigned(a, md5_AddUnsigned(md5_AddUnsigned(md5_H(b, c, d), x), ac));
return md5_AddUnsigned(md5_RotateLeft(a, s), b);
}
function md5_II(a, b, c, d, x, s, ac) {
a = md5_AddUnsigned(a, md5_AddUnsigned(md5_AddUnsigned(md5_I(b, c, d), x), ac));
return md5_AddUnsigned(md5_RotateLeft(a, s), b);
}
function md5_ConvertToWordArray(string) {
var lWordCount;
var lMessageLength = string.length;
var lNumberOfWords_temp1 = lMessageLength + 8;
var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64;
var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
var lWordArray = Array(lNumberOfWords - 1);
var lBytePosition = 0;
var lByteCount = 0;
while (lByteCount < lMessageLength) {
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
lBytePosition = (lByteCount % 4) * 8;
lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition));
lByteCount++;
}
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
lBytePosition = (lByteCount % 4) * 8;
lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
return lWordArray;
}
function md5_WordToHex(lValue) {
var WordToHexValue = "", WordToHexValue_temp = "", lByte, lCount;
for (lCount = 0; lCount <= 3; lCount++) {
lByte = (lValue >>> (lCount * 8)) & 255;
WordToHexValue_temp = "0" + lByte.toString(16);
WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length - 2, 2);
}
return WordToHexValue;
}
function md5_Utf8Encode(string) {
string = string.replace(/\r\n/g, "\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if ((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
} else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
}
var x = Array();
var k, AA, BB, CC, DD, a, b, c, d;
var S11 = 7, S12 = 12, S13 = 17, S14 = 22;
var S21 = 5, S22 = 9, S23 = 14, S24 = 20;
var S31 = 4, S32 = 11, S33 = 16, S34 = 23;
var S41 = 6, S42 = 10, S43 = 15, S44 = 21;
string = md5_Utf8Encode(string);
x = md5_ConvertToWordArray(string);
a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;
for (k = 0; k < x.length; k += 16) {
AA = a; BB = b; CC = c; DD = d;
a = md5_FF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
d = md5_FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
c = md5_FF(c, d, a, b, x[k + 2], S13, 0x242070DB);
b = md5_FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
a = md5_FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
d = md5_FF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
c = md5_FF(c, d, a, b, x[k + 6], S13, 0xA8304613);
b = md5_FF(b, c, d, a, x[k + 7], S14, 0xFD469501);
a = md5_FF(a, b, c, d, x[k + 8], S11, 0x698098D8);
d = md5_FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
c = md5_FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
b = md5_FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
a = md5_FF(a, b, c, d, x[k + 12], S11, 0x6B901122);
d = md5_FF(d, a, b, c, x[k + 13], S12, 0xFD987193);
c = md5_FF(c, d, a, b, x[k + 14], S13, 0xA679438E);
b = md5_FF(b, c, d, a, x[k + 15], S14, 0x49B40821);
a = md5_GG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
d = md5_GG(d, a, b, c, x[k + 6], S22, 0xC040B340);
c = md5_GG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
b = md5_GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
a = md5_GG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
d = md5_GG(d, a, b, c, x[k + 10], S22, 0x2441453);
c = md5_GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
b = md5_GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
a = md5_GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
d = md5_GG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
c = md5_GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
b = md5_GG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
a = md5_GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
d = md5_GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);
c = md5_GG(c, d, a, b, x[k + 7], S23, 0x676F02D9);
b = md5_GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);
a = md5_HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);
d = md5_HH(d, a, b, c, x[k + 8], S32, 0x8771F681);
c = md5_HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);
b = md5_HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);
a = md5_HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);
d = md5_HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);
c = md5_HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);
b = md5_HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);
a = md5_HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);
d = md5_HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);
c = md5_HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);
b = md5_HH(b, c, d, a, x[k + 6], S34, 0x4881D05);
a = md5_HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);
d = md5_HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);
c = md5_HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);
b = md5_HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);
a = md5_II(a, b, c, d, x[k + 0], S41, 0xF4292244);
d = md5_II(d, a, b, c, x[k + 7], S42, 0x432AFF97);
c = md5_II(c, d, a, b, x[k + 14], S43, 0xAB9423A7);
b = md5_II(b, c, d, a, x[k + 5], S44, 0xFC93A039);
a = md5_II(a, b, c, d, x[k + 12], S41, 0x655B59C3);
d = md5_II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);
c = md5_II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);
b = md5_II(b, c, d, a, x[k + 1], S44, 0x85845DD1);
a = md5_II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);
d = md5_II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);
c = md5_II(c, d, a, b, x[k + 6], S43, 0xA3014314);
b = md5_II(b, c, d, a, x[k + 13], S44, 0x4E0811A1);
a = md5_II(a, b, c, d, x[k + 4], S41, 0xF7537E82);
d = md5_II(d, a, b, c, x[k + 11], S42, 0xBD3AF235);
c = md5_II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);
b = md5_II(b, c, d, a, x[k + 9], S44, 0xEB86D391);
a = md5_AddUnsigned(a, AA);
b = md5_AddUnsigned(b, BB);
c = md5_AddUnsigned(c, CC);
d = md5_AddUnsigned(d, DD);
}
return (md5_WordToHex(a) + md5_WordToHex(b) + md5_WordToHex(c) + md5_WordToHex(d)).toLowerCase();
}

View File

@ -16,8 +16,33 @@
"128": "icons/icon128.png"
}
},
"permissions": ["activeTab", "downloads"],
"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'self'"
}
"permissions": [
"activeTab",
"downloads",
"scripting",
"storage",
"tabs"
],
"host_permissions": [
"https://api.fanyi.baidu.com/*",
"<all_urls>"
],
"commands": {
"trigger-select": {
"suggested_key": {
"default": "Ctrl+Q",
"mac": "Command+Q"
},
"description": "触发框选功能"
}
},
"background": {
"service_worker": "background.js",
"type": "module"
},
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["md5.js", "content.js"],
"css": ["content.css"]
}]
}

19
md5.js Normal file
View File

@ -0,0 +1,19 @@
/*
CryptoJS v3.1.2
code.google.com/p/crypto-js
(c) 2009-2013 by Jeff Mott. All rights reserved.
code.google.com/p/crypto-js/wiki/License
*/
var CryptoJS=CryptoJS||function(s,p){var m={},l=m.lib={},n=function(){},r=l.Base={extend:function(b){n.prototype=this;var h=new n;b&&h.mixIn(b);h.hasOwnProperty("init")||(h.init=function(){h.$super.init.apply(this,arguments)});h.init.prototype=h;h.$super=this;return h},create:function(){var b=this.extend();b.init.apply(b,arguments);return b},init:function(){},mixIn:function(b){for(var h in b)b.hasOwnProperty(h)&&(this[h]=b[h]);b.hasOwnProperty("toString")&&(this.toString=b.toString)},clone:function(){return this.init.prototype.extend(this)}},
q=l.WordArray=r.extend({init:function(b,h){b=this.words=b||[];this.sigBytes=h!=p?h:4*b.length},toString:function(b){return(b||t).stringify(this)},concat:function(b){var h=this.words,a=b.words,j=this.sigBytes;b=b.sigBytes;this.clamp();if(j%4)for(var g=0;g<b;g++)h[j+g>>>2]|=(a[g>>>2]>>>24-8*(g%4)&255)<<24-8*((j+g)%4);else if(65535<a.length)for(g=0;g<b;g+=4)h[j+g>>>2]=a[g>>>2];else h.push.apply(h,a);this.sigBytes+=b;return this},clamp:function(){var b=this.words,h=this.sigBytes;b[h>>>2]&=4294967295<<
32-8*(h%4);b.length=s.ceil(h/4)},clone:function(){var b=r.clone.call(this);b.words=this.words.slice(0);return b},random:function(b){for(var h=[],a=0;a<b;a+=4)h.push(4294967296*s.random()|0);return new q.init(h,b)}}),v=m.enc={},t=v.Hex={stringify:function(b){var a=b.words;b=b.sigBytes;for(var g=[],j=0;j<b;j++){var k=a[j>>>2]>>>24-8*(j%4)&255;g.push((k>>>4).toString(16));g.push((k&15).toString(16))}return g.join("")},parse:function(b){for(var a=b.length,g=[],j=0;j<a;j+=2)g[j>>>3]|=parseInt(b.substr(j,
2),16)<<24-4*(j%8);return new q.init(g,a/2)}},a=v.Latin1={stringify:function(b){var a=b.words;b=b.sigBytes;for(var g=[],j=0;j<b;j++)g.push(String.fromCharCode(a[j>>>2]>>>24-8*(j%4)&255));return g.join("")},parse:function(b){for(var a=b.length,g=[],j=0;j<a;j++)g[j>>>2]|=(b.charCodeAt(j)&255)<<24-8*(j%4);return new q.init(g,a)}},u=v.Utf8={stringify:function(b){try{return decodeURIComponent(escape(a.stringify(b)))}catch(g){throw Error("Malformed UTF-8 data");}},parse:function(b){return a.parse(unescape(encodeURIComponent(b)))}},
g=l.BufferedBlockAlgorithm=r.extend({reset:function(){this._data=new q.init;this._nDataBytes=0},_append:function(b){"string"==typeof b&&(b=u.parse(b));this._data.concat(b);this._nDataBytes+=b.sigBytes},_process:function(b){var a=this._data,g=a.words,j=a.sigBytes,k=this.blockSize,m=j/(4*k),m=b?s.ceil(m):s.max((m|0)-this._minBufferSize,0);b=m*k;j=s.min(4*b,j);if(b){for(var l=0;l<b;l+=k)this._doProcessBlock(g,l);l=g.splice(0,b);a.sigBytes-=j}return new q.init(l,j)},clone:function(){var b=r.clone.call(this);
b._data=this._data.clone();return b},_minBufferSize:0});l.Hasher=g.extend({cfg:r.extend(),init:function(b){this.cfg=this.cfg.extend(b);this.reset()},reset:function(){g.reset.call(this);this._doReset()},update:function(b){this._append(b);this._process();return this},finalize:function(b){b&&this._append(b);return this._doFinalize()},blockSize:16,_createHelper:function(b){return function(a,g){return(new b.init(g)).finalize(a)}},_createHmacHelper:function(b){return function(a,g){return(new k.HMAC.init(b,
g)).finalize(a)}}});var k=m.algo={};return m}(Math);
(function(s){function p(a,k,b,h,l,j,m){a=a+(k&b|~k&h)+l+m;return(a<<j|a>>>32-j)+k}function m(a,k,b,h,l,j,m){a=a+(k&h|b&~h)+l+m;return(a<<j|a>>>32-j)+k}function l(a,k,b,h,l,j,m){a=a+(k^b^h)+l+m;return(a<<j|a>>>32-j)+k}function n(a,k,b,h,l,j,m){a=a+(b^(k|~h))+l+m;return(a<<j|a>>>32-j)+k}for(var r=CryptoJS,q=r.lib,v=q.WordArray,t=q.Hasher,q=r.algo,a=[],u=0;64>u;u++)a[u]=4294967296*s.abs(s.sin(u+1))|0;q=q.MD5=t.extend({_doReset:function(){this._hash=new v.init([1732584193,4023233417,2562383102,271733878])},
_doProcessBlock:function(g,k){for(var b=0;16>b;b++){var h=k+b,w=g[h];g[h]=(w<<8|w>>>24)&16711935|(w<<24|w>>>8)&4278255360}var b=this._hash.words,h=g[k+0],w=g[k+1],j=g[k+2],q=g[k+3],r=g[k+4],s=g[k+5],t=g[k+6],u=g[k+7],v=g[k+8],x=g[k+9],y=g[k+10],z=g[k+11],A=g[k+12],B=g[k+13],C=g[k+14],D=g[k+15],c=b[0],d=b[1],e=b[2],f=b[3],c=p(c,d,e,f,h,7,a[0]),f=p(f,c,d,e,w,12,a[1]),e=p(e,f,c,d,j,17,a[2]),d=p(d,e,f,c,q,22,a[3]),c=p(c,d,e,f,r,7,a[4]),f=p(f,c,d,e,s,12,a[5]),e=p(e,f,c,d,t,17,a[6]),d=p(d,e,f,c,u,22,a[7]),
c=p(c,d,e,f,v,7,a[8]),f=p(f,c,d,e,x,12,a[9]),e=p(e,f,c,d,y,17,a[10]),d=p(d,e,f,c,z,22,a[11]),c=p(c,d,e,f,A,7,a[12]),f=p(f,c,d,e,B,12,a[13]),e=p(e,f,c,d,C,17,a[14]),d=p(d,e,f,c,D,22,a[15]),c=m(c,d,e,f,w,5,a[16]),f=m(f,c,d,e,t,9,a[17]),e=m(e,f,c,d,z,14,a[18]),d=m(d,e,f,c,h,20,a[19]),c=m(c,d,e,f,s,5,a[20]),f=m(f,c,d,e,y,9,a[21]),e=m(e,f,c,d,D,14,a[22]),d=m(d,e,f,c,r,20,a[23]),c=m(c,d,e,f,x,5,a[24]),f=m(f,c,d,e,C,9,a[25]),e=m(e,f,c,d,q,14,a[26]),d=m(d,e,f,c,v,20,a[27]),c=m(c,d,e,f,B,5,a[28]),f=m(f,c,
d,e,j,9,a[29]),e=m(e,f,c,d,u,14,a[30]),d=m(d,e,f,c,A,20,a[31]),c=l(c,d,e,f,s,4,a[32]),f=l(f,c,d,e,v,11,a[33]),e=l(e,f,c,d,z,16,a[34]),d=l(d,e,f,c,C,23,a[35]),c=l(c,d,e,f,w,4,a[36]),f=l(f,c,d,e,r,11,a[37]),e=l(e,f,c,d,u,16,a[38]),d=l(d,e,f,c,y,23,a[39]),c=l(c,d,e,f,B,4,a[40]),f=l(f,c,d,e,h,11,a[41]),e=l(e,f,c,d,q,16,a[42]),d=l(d,e,f,c,t,23,a[43]),c=l(c,d,e,f,x,4,a[44]),f=l(f,c,d,e,A,11,a[45]),e=l(e,f,c,d,D,16,a[46]),d=l(d,e,f,c,j,23,a[47]),c=n(c,d,e,f,h,6,a[48]),f=n(f,c,d,e,u,10,a[49]),e=n(e,f,c,d,
C,15,a[50]),d=n(d,e,f,c,s,21,a[51]),c=n(c,d,e,f,A,6,a[52]),f=n(f,c,d,e,q,10,a[53]),e=n(e,f,c,d,y,15,a[54]),d=n(d,e,f,c,w,21,a[55]),c=n(c,d,e,f,v,6,a[56]),f=n(f,c,d,e,D,10,a[57]),e=n(e,f,c,d,t,15,a[58]),d=n(d,e,f,c,B,21,a[59]),c=n(c,d,e,f,r,6,a[60]),f=n(f,c,d,e,z,10,a[61]),e=n(e,f,c,d,j,15,a[62]),d=n(d,e,f,c,x,21,a[63]);b[0]=b[0]+c|0;b[1]=b[1]+d|0;b[2]=b[2]+e|0;b[3]=b[3]+f|0},_doFinalize:function(){var a=this._data,k=a.words,b=8*this._nDataBytes,h=8*a.sigBytes;k[h>>>5]|=128<<24-h%32;var l=s.floor(b/
4294967296);k[(h+64>>>9<<4)+15]=(l<<8|l>>>24)&16711935|(l<<24|l>>>8)&4278255360;k[(h+64>>>9<<4)+14]=(b<<8|b>>>24)&16711935|(b<<24|b>>>8)&4278255360;a.sigBytes=4*(k.length+1);this._process();a=this._hash;k=a.words;for(b=0;4>b;b++)h=k[b],k[b]=(h<<8|h>>>24)&16711935|(h<<24|h>>>8)&4278255360;return a},clone:function(){var a=t.clone.call(this);a._hash=this._hash.clone();return a}});r.MD5=t._createHelper(q);r.HmacMD5=t._createHmacHelper(q)})(Math);

View File

@ -18,6 +18,10 @@
<span class="icon">📄</span>
Word转HTML
</button>
<button class="tablinks" data-tab="translate">
<span class="icon">🔤</span>
翻译设置
</button>
</div>
<div id="qr" class="tabcontent" style="display:block;">
@ -43,6 +47,25 @@
下载HTML
</button>
</div>
<div id="translate" class="tabcontent" style="display:none;">
<div class="translate-settings">
<div class="setting-item">
<label class="switch">
<input type="checkbox" id="translateEnabled">
<span class="slider"></span>
</label>
<span class="setting-label">启用翻译功能 (Ctrl+Q)</span>
</div>
<div class="setting-item">
<label>目标语言:</label>
<select id="targetLang">
<option value="en">英文</option>
<option value="cht">繁体中文</option>
</select>
</div>
</div>
</div>
</div>
<script src="popup.js"></script>
</body>

View File

@ -10,12 +10,15 @@ document.addEventListener('DOMContentLoaded', function() {
let qr = null;
let convertedHtml = '';
// 加载翻译设置
loadTranslationSettings();
const tabs = document.querySelectorAll('.tablinks');
const tabContents = document.querySelectorAll('.tabcontent');
tabs.forEach(tab => {
tab.addEventListener('click', (e) => {
const tabName = e.target.getAttribute('data-tab');
const tabName = e.currentTarget.getAttribute('data-tab');
tabs.forEach(t => t.classList.remove('active'));
tab.classList.add('active');
@ -131,4 +134,41 @@ document.addEventListener('DOMContentLoaded', function() {
saveAs: true
});
});
// 翻译设置相关
function loadTranslationSettings() {
const translateEnabled = document.getElementById('translateEnabled');
const targetLang = document.getElementById('targetLang');
// 检测操作系统
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
const shortcutText = isMac ? 'Command+Q' : 'Ctrl+Q';
// 更新显示的快捷键文本
const settingLabel = document.querySelector('.setting-label');
if (settingLabel) {
settingLabel.textContent = `启用翻译功能 (${shortcutText})`;
}
// 加载保存的设置
chrome.storage.sync.get(['translateEnabled', 'targetLang'], function(result) {
translateEnabled.checked = result.translateEnabled !== false; // 默认为 true
targetLang.value = result.targetLang || 'en';
});
// 监听设置变更
translateEnabled.addEventListener('change', function(e) {
const enabled = e.target.checked;
chrome.storage.sync.set({ translateEnabled: enabled }, function() {
console.log('Translation enabled:', enabled);
});
});
targetLang.addEventListener('change', function(e) {
const lang = e.target.value;
chrome.storage.sync.set({ targetLang: lang }, function() {
console.log('Target language:', lang);
});
});
}
});

View File

@ -10,7 +10,7 @@ body {
}
.container {
width: 380px;
width: 400px;
padding: 20px;
background: white;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
@ -26,27 +26,30 @@ h1 {
.tab {
display: flex;
gap: 10px;
gap: 8px;
margin-bottom: 20px;
background: #f5f5f5;
padding: 5px;
border-radius: 8px;
min-height: 45px;
}
.tab button {
flex: 1;
padding: 12px;
padding: 8px 4px;
border: none;
background: transparent;
color: #666;
cursor: pointer;
border-radius: 6px;
transition: all 0.3s ease;
font-size: 14px;
font-size: 13px;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
gap: 4px;
white-space: nowrap;
min-width: 80px;
}
.tab button:hover {
@ -148,7 +151,8 @@ button:hover {
}
.icon {
font-size: 18px;
font-size: 16px;
flex-shrink: 0;
}
/* 美化滚动条 */
@ -241,4 +245,73 @@ button:hover {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* 翻译设置样式 */
.translate-settings {
padding: 15px;
}
.setting-item {
margin-bottom: 15px;
display: flex;
align-items: center;
}
.setting-label {
margin-left: 10px;
}
/* 开关按钮样式 */
.switch {
position: relative;
display: inline-block;
width: 50px;
height: 24px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
transition: .4s;
border-radius: 24px;
}
.slider:before {
position: absolute;
content: "";
height: 16px;
width: 16px;
left: 4px;
bottom: 4px;
background-color: white;
transition: .4s;
border-radius: 50%;
}
input:checked + .slider {
background-color: #2196F3;
}
input:checked + .slider:before {
transform: translateX(26px);
}
/* 下拉菜单样式 */
select {
padding: 5px;
border-radius: 4px;
border: 1px solid #ddd;
margin-left: 10px;
}