监听鼠标事件与获取选中文本
在内容脚本中监听鼠标释放事件,获取用户选中的文本。使用window.getSelection()
方法获取选中内容,并过滤空值或过短文本。
document.addEventListener('mouseup', (e) => {
const selectedText = window.getSelection().toString().trim();
if (selectedText.length > 0 && selectedText.length < 500) {
chrome.runtime.sendMessage({ type: 'TRANSLATE', text: selectedText });
}
});
后台脚本通信与API调用
后台脚本接收内容脚本消息,调用翻译API。需要提前申请有道或百度翻译的API密钥(免费版足够测试)。
// 示例:有道翻译API调用
async function fetchYoudao(text) {
const appKey = 'YOUR_APP_KEY';
const key = 'YOUR_SECRET_KEY';
const salt = Date.now();
const sign = md5(appKey + text + salt + key);
const res = await fetch(`https://openapi.youdao.com/api?q=${encodeURIComponent(text)}&appKey=${appKey}&salt=${salt}&sign=${sign}`);
return res.json();
}
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.type === 'TRANSLATE') {
fetchYoudao(request.text).then(data => {
sendResponse({ result: data.translation[0] });
});
return true; // 保持消息端口开放
}
});
翻译结果展示样式设计
在内容脚本中动态创建悬浮框,采用固定定位避免干扰页面布局。CSS建议使用position: absolute
配合z-index: 9999
确保悬浮在最上层。
.translation-box {
position: absolute;
background: white;
border: 1px solid #ddd;
padding: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
max-width: 300px;
z-index: 9999;
}
悬浮框位置计算与渲染
根据鼠标事件坐标计算悬浮框位置,避免超出视窗边界。动态插入DOM元素并注入翻译结果。
function showTranslation(text, x, y) {
const box = document.createElement('div');
box.className = 'translation-box';
box.textContent = text;
// 视窗边界检测
const adjustedX = Math.min(x, window.innerWidth - 310);
const adjustedY = Math.min(y, window.innerHeight - 100);
box.style.left = `${adjustedX}px`;
box.style.top = `${adjustedY}px`;
document.body.appendChild(box);
// 点击外部关闭
setTimeout(() => {
document.addEventListener('click', (e) => {
if (!box.contains(e.target)) box.remove();
}, { once: true });
}, 100);
}
错误处理与性能优化
添加API调用失败的回退方案,如切换备用翻译服务或显示错误提示。使用防抖技术避免高频触发。
// 防抖处理(300ms间隔)
let lastCall = 0;
document.addEventListener('mouseup', (e) => {
const now = Date.now();
if (now - lastCall < 300) return;
lastCall = now;
// ...原有逻辑
});
// 错误处理示例
chrome.runtime.sendMessage({ type: 'TRANSLATE', text }, (response) => {
if (chrome.runtime.lastError || !response) {
showTranslation('翻译服务暂不可用', e.clientX, e.clientY);
} else {
showTranslation(response.result, e.clientX, e.clientY);
}
});
扩展打包与发布
在manifest.json
中配置必要权限,包括API域名访问权限和内容脚本注入规则。
{
"permissions": ["https://openapi.youdao.com/"],
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["content.js"]
}]
}
完整项目需包含图标、多语言支持等细节,可通过Chrome开发者模式加载未打包的扩展进行测试。