```
feat(sidepanel): 重构时间戳转换功能并优化用户界面 - 将代码模块化,拆分为 eventHandlers、domUtils 和 timestampUtils 等文件 - 使用 Rollup 配置文件替代内联构建命令,提升可维护性 - 引入页面切换动画与交互反馈动画,增强用户体验 - 更新 HTML 元素 ID 命名以提高语义化和一致性 - 改进 CSS 样式,增加悬停效果、过渡动画和响应式支持 - package.json 中添加 type: module 并升级版本至 1.1 ```
This commit is contained in:
+4
-3
@@ -1,12 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "Chrome Extensions Gemini Demo",
|
"name": "Chrome Extensions Gemini Demo",
|
||||||
"version": "1.0",
|
"version": "1.1",
|
||||||
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "rollup sidepanel/index.js --file dist/sidepanel.bundle.js --format iife"
|
"build": "rollup -c"
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@google/generative-ai": "0.15.0",
|
"@google/generative-ai": "0.15.0",
|
||||||
"rollup": "4.22.4"
|
"rollup": "4.22.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export default {
|
||||||
|
input: 'sidepanel/index.js',
|
||||||
|
output: {
|
||||||
|
file: 'dist/sidepanel.bundle.js',
|
||||||
|
format: 'iife'
|
||||||
|
}
|
||||||
|
};
|
||||||
+93
-30
@@ -1,4 +1,10 @@
|
|||||||
/* sidepanel/style.css */
|
/* sidepanel/style.css */
|
||||||
|
#app {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
.navbar {
|
.navbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
background-color: #f8f9fa;
|
background-color: #f8f9fa;
|
||||||
@@ -13,7 +19,7 @@
|
|||||||
border: none;
|
border: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
transition: background-color 0.2s;
|
transition: all 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-button:hover {
|
.nav-button:hover {
|
||||||
@@ -23,6 +29,8 @@
|
|||||||
.nav-button.active {
|
.nav-button.active {
|
||||||
background-color: #007bff;
|
background-color: #007bff;
|
||||||
color: white;
|
color: white;
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.close-button {
|
.close-button {
|
||||||
@@ -33,6 +41,12 @@
|
|||||||
border-radius: 0.25rem;
|
border-radius: 0.25rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-button:hover {
|
||||||
|
background-color: #c82333;
|
||||||
|
transform: scale(1.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
.datetime-box {
|
.datetime-box {
|
||||||
@@ -40,49 +54,44 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
}
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
@media screen and (max-width: 768px) {
|
|
||||||
.datetime-box {
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: stretch;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-group {
|
.input-group {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin: 0.5rem 0;
|
transition: all 0.3s ease;
|
||||||
min-width: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 768px) {
|
|
||||||
.input-group {
|
|
||||||
min-width: unset;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-text {
|
.input-text {
|
||||||
width: 200px;
|
width: 200px;
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
margin: 0.5rem 0;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
border: 1px solid #ced4da;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
transition: all 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 768px) {
|
.input-text:focus {
|
||||||
.input-text {
|
border-color: #007bff;
|
||||||
width: 100%;
|
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
|
||||||
flex: 1;
|
outline: none;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.select-box {
|
.select-box {
|
||||||
width: 150px;
|
min-width: 150px;
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
margin: 0.5rem 0;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
border: 1px solid #ced4da;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-box:focus {
|
||||||
|
border-color: #007bff;
|
||||||
|
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
|
||||||
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.convert-button {
|
.convert-button {
|
||||||
@@ -94,24 +103,78 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
height: 2rem;
|
height: 2rem;
|
||||||
width: 4rem;
|
width: 4rem;
|
||||||
margin: 0.5rem 0;
|
|
||||||
align-self: flex-start;
|
align-self: flex-start;
|
||||||
|
transition: all 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 768px) {
|
.convert-button:hover {
|
||||||
.convert-button {
|
background-color: #218838;
|
||||||
width: 100%;
|
transform: translateY(-2px);
|
||||||
}
|
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
|
position: relative;
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 页面切换动画 */
|
||||||
.page {
|
.page {
|
||||||
display: none;
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
padding: 1rem;
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(20px);
|
||||||
|
transition: opacity 0.3s ease, transform 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page.active {
|
.page.active {
|
||||||
display: block;
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateX(0);
|
||||||
|
transition: opacity 0.3s ease, transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 按钮点击效果 */
|
||||||
|
.button:active, .convert-button:active, .nav-button:active, .close-button:active {
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 输入框动画 */
|
||||||
|
.input-text, .select-box {
|
||||||
|
transition: all 0.2s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-text:hover, .select-box:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 结果显示动画 */
|
||||||
|
#timestamp-conversion-result, #date-conversion-result, #current-timestamp-value {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
#timestamp-conversion-result:focus, #date-conversion-result:focus, #current-timestamp-value:focus {
|
||||||
|
transform: scale(1.02);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 900px) {
|
||||||
|
.input-group {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-text {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page {
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+18
-18
@@ -11,9 +11,9 @@
|
|||||||
<div id="app">
|
<div id="app">
|
||||||
<!-- 导航栏 -->
|
<!-- 导航栏 -->
|
||||||
<nav class="navbar">
|
<nav class="navbar">
|
||||||
<button id="nav-timestamp" class="nav-button active">时间戳转换</button>
|
<button id="nav-timestamp-btn" class="nav-button active">时间戳转换</button>
|
||||||
<button id="nav-other" class="nav-button">其他工具</button>
|
<button id="nav-other-tools-btn" class="nav-button">其他工具</button>
|
||||||
<button id="close" class="close-button">X</button>
|
<button id="close-panel-btn" class="close-button">X</button>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<!-- 页面内容容器 -->
|
<!-- 页面内容容器 -->
|
||||||
@@ -24,12 +24,12 @@
|
|||||||
<div>
|
<div>
|
||||||
<h2>当前时间戳</h2>
|
<h2>当前时间戳</h2>
|
||||||
<p>
|
<p>
|
||||||
<a href="javascript:;" id="current-timestamp">1762873747965</a>
|
<a href="javascript:;" id="current-timestamp-value">1762873747965</a>
|
||||||
<span id="timestamp-unit">毫秒</span>
|
<span id="current-timestamp-unit">毫秒</span>
|
||||||
<button id="toggle-timestamp-btn">切换单位</button>
|
<button id="toggle-unit-btn">切换单位</button>
|
||||||
<button id="copy-timestamp-btn">复制</button>
|
<button id="copy-timestamp-btn">复制</button>
|
||||||
<button id="stop-timestamp-btn">停止</button>
|
<button id="stop-timer-btn">停止</button>
|
||||||
<button id="start-timestamp-btn" style="display: none">开始</button>
|
<button id="start-timer-btn" style="display: none">开始</button>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -40,24 +40,24 @@
|
|||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
id="input-timestamp"
|
id="timestamp-input"
|
||||||
placeholder="请输入时间戳"
|
placeholder="请输入时间戳"
|
||||||
class="input-text"
|
class="input-text"
|
||||||
/>
|
/>
|
||||||
<select class="select-box">
|
<select id="timestamp-input-unit-select" class="select-box">
|
||||||
<option value="milliseconds">毫秒(ms)</option>
|
<option value="milliseconds">毫秒(ms)</option>
|
||||||
<option value="seconds">秒(s)</option>
|
<option value="seconds">秒(s)</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<button id="convert-timestamp-btn" class="convert-button">转换</button>
|
<button id="convert-timestamp-to-date-btn" class="convert-button">转换</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
id="timestamp-input-result"
|
id="timestamp-conversion-result"
|
||||||
placeholder="转换结果"
|
placeholder="转换结果"
|
||||||
class="input-text"
|
class="input-text"
|
||||||
/>
|
/>
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
id="input-datetime"
|
id="datetime-input"
|
||||||
placeholder="输入日期时间"
|
placeholder="输入日期时间"
|
||||||
class="input-text"
|
class="input-text"
|
||||||
/>
|
/>
|
||||||
@@ -85,17 +85,17 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<button id="convert-datetime-btn" class="convert-button">转换</button>
|
<button id="convert-date-to-timestamp-btn" class="convert-button">转换</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
id="datetime-input-result"
|
id="date-conversion-result"
|
||||||
placeholder="转换结果"
|
placeholder="转换结果"
|
||||||
class="input-text"
|
class="input-text"
|
||||||
/>
|
/>
|
||||||
<select class="select-box">
|
<select id="date-result-unit-select" class="select-box">
|
||||||
<option value="milliseconds">毫秒(ms)</option>
|
<option value="milliseconds">毫秒(ms)</option>
|
||||||
<option value="seconds">秒(s)</option>
|
<option value="seconds">秒(s)</option>
|
||||||
</select>
|
</select>
|
||||||
@@ -105,13 +105,13 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 其他工具页面 -->
|
<!-- 其他工具页面 -->
|
||||||
<div id="page-other" class="page">
|
<div id="page-other-tools" class="page">
|
||||||
<h2>其他工具页面</h2>
|
<h2>其他工具页面</h2>
|
||||||
<p>这里可以放置其他工具的内容。</p>
|
<p>这里可以放置其他工具的内容。</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="index.js"></script>
|
<script src="../dist/sidepanel.bundle.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
+36
-138
@@ -1,147 +1,45 @@
|
|||||||
document.getElementById('close').addEventListener('click', () => {
|
// document.getElementById('close').addEventListener('click', () => {
|
||||||
window.parent.postMessage({ action: 'indexind' }, '*');
|
// window.parent.postMessage({ action: 'indexind' }, '*');
|
||||||
});
|
// });
|
||||||
|
|
||||||
// sidepanel/index.js
|
// sidepanel/index.js
|
||||||
|
import { switchPage } from './utils/domUtils.js';
|
||||||
|
import {
|
||||||
|
initTimestampDisplay,
|
||||||
|
handleToggleUnit,
|
||||||
|
handleStopTimer,
|
||||||
|
handleStartTimer,
|
||||||
|
handleConvertTimestamp,
|
||||||
|
handleConvertDateToTimestamp,
|
||||||
|
handleCopyTimestamp,
|
||||||
|
handleClosePanel
|
||||||
|
} from './modules/eventHandlers.js';
|
||||||
|
import { addEventListenerById } from './utils/domUtils.js';
|
||||||
|
|
||||||
// 页面切换逻辑
|
// 页面切换逻辑
|
||||||
document.getElementById('nav-timestamp').addEventListener('click', () => {
|
addEventListenerById('nav-timestamp-btn', 'click', () => {
|
||||||
switchPage('timestamp');
|
switchPage('timestamp');
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById('nav-other').addEventListener('click', () => {
|
// 计时器页面切换
|
||||||
switchPage('other');
|
addEventListenerById('nav-other-tools-btn', 'click', () => {
|
||||||
|
switchPage('other-tools');
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
// 初始化时间戳显示
|
||||||
* 更新时间戳显示
|
initTimestampDisplay();
|
||||||
*/
|
|
||||||
function updateTimestamp(showMilliseconds = true) {
|
|
||||||
const currentTimestamp = document.getElementById('current-timestamp');
|
|
||||||
const currentTimestampUnit = document.getElementById('timestamp-unit');
|
|
||||||
const timestamp = Date.now();
|
|
||||||
const unit = showMilliseconds ? '毫秒' : '秒';
|
|
||||||
currentTimestamp.textContent = showMilliseconds ? timestamp : Math.floor(timestamp / 1000);
|
|
||||||
currentTimestampUnit.textContent = unit;
|
|
||||||
}
|
|
||||||
|
|
||||||
const toggleTimestampBtn = document.getElementById('toggle-timestamp-btn');
|
// 绑定事件处理器
|
||||||
const stopTimestampBtn = document.getElementById('stop-timestamp-btn');
|
// 绑定时间戳相关按钮事件
|
||||||
const startTimestampBtn = document.getElementById('start-timestamp-btn');
|
addEventListenerById('toggle-unit-btn', 'click', handleToggleUnit);
|
||||||
|
// 绑定计时器相关按钮事件
|
||||||
stopTimestampBtn.addEventListener('click', () => {
|
addEventListenerById('stop-timer-btn', 'click', handleStopTimer);
|
||||||
clearInterval(timestampInterval);
|
addEventListenerById('start-timer-btn', 'click', handleStartTimer);
|
||||||
stopTimestampBtn.style.display = 'none';
|
// 绑定时间戳转换按钮事件
|
||||||
startTimestampBtn.style.display = 'inline-block';
|
addEventListenerById('convert-timestamp-to-date-btn', 'click', handleConvertTimestamp);
|
||||||
});
|
// 绑定日期转换按钮事件
|
||||||
|
addEventListenerById('convert-date-to-timestamp-btn', 'click', handleConvertDateToTimestamp);
|
||||||
startTimestampBtn.addEventListener('click', () => {
|
// 绑定复制时间戳按钮事件
|
||||||
timestampInterval = setInterval(() => updateTimestamp(showMilliseconds), 100);
|
addEventListenerById('copy-timestamp-btn', 'click', handleCopyTimestamp);
|
||||||
startTimestampBtn.style.display = 'none';
|
// 绑定关闭面板按钮事件
|
||||||
stopTimestampBtn.style.display = 'inline-block';
|
addEventListenerById('close-panel-btn', 'click', handleClosePanel);
|
||||||
});
|
|
||||||
|
|
||||||
let showMilliseconds = true;
|
|
||||||
updateTimestamp(showMilliseconds); // 初始化时更新一次时间戳
|
|
||||||
let timestampInterval = setInterval(() => updateTimestamp(showMilliseconds), 100);
|
|
||||||
toggleTimestampBtn.addEventListener('click', () => {
|
|
||||||
showMilliseconds = !showMilliseconds;
|
|
||||||
updateTimestamp(showMilliseconds);
|
|
||||||
});
|
|
||||||
|
|
||||||
const inputTimestamp = document.getElementById('input-timestamp');
|
|
||||||
const convertTimestampBtn = document.getElementById('convert-timestamp-btn');
|
|
||||||
const timestampInputResult = document.getElementById('timestamp-input-result');
|
|
||||||
const timestampUnitSelect = document.querySelector('#page-timestamp select'); // 时间戳单位选择器
|
|
||||||
|
|
||||||
convertTimestampBtn.addEventListener('click', () => {
|
|
||||||
const timestamp = inputTimestamp.value.trim();
|
|
||||||
console.log('输入时间戳:', timestamp);
|
|
||||||
|
|
||||||
if (!timestamp) {
|
|
||||||
timestampInputResult.value = '请输入时间戳';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取选择的时间戳单位(秒或毫秒)
|
|
||||||
const isSeconds = timestampUnitSelect.value === 'seconds';
|
|
||||||
|
|
||||||
// 转换为数字
|
|
||||||
let timestampNum = Number(timestamp);
|
|
||||||
|
|
||||||
// 如果是秒,转换为毫秒
|
|
||||||
if (isSeconds) {
|
|
||||||
timestampNum = timestampNum * 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查是否为有效数字
|
|
||||||
if (isNaN(timestampNum)) {
|
|
||||||
timestampInputResult.value = '请输入有效的时间戳';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建日期对象
|
|
||||||
const date = new Date(timestampNum);
|
|
||||||
|
|
||||||
// 检查日期是否有效
|
|
||||||
if (isNaN(date.getTime())) {
|
|
||||||
timestampInputResult.value = '无效的日期';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('转换日期对象:', date);
|
|
||||||
const year = date.getFullYear();
|
|
||||||
const month = date.getMonth() + 1;
|
|
||||||
const day = date.getDate();
|
|
||||||
const hours = date.getHours();
|
|
||||||
const minutes = date.getMinutes();
|
|
||||||
const seconds = date.getSeconds();
|
|
||||||
|
|
||||||
console.log('转换结果:', `${year}年${month}月${day}日 ${hours}时${minutes}分${seconds}秒`);
|
|
||||||
|
|
||||||
timestampInputResult.value = `${year}年${month}月${day}日 ${hours}时${minutes}分${seconds}秒`;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 复制时间戳到剪贴板
|
|
||||||
const copyTimestampBtn = document.getElementById('copy-timestamp-btn');
|
|
||||||
const currentTimestamp = document.getElementById('current-timestamp');
|
|
||||||
copyTimestampBtn.addEventListener('click', () => {
|
|
||||||
// 获取时间戳文本
|
|
||||||
const timestampText = currentTimestamp.textContent;
|
|
||||||
|
|
||||||
// 检查扩展上下文是否仍然有效
|
|
||||||
if (chrome.runtime && chrome.runtime.sendMessage) {
|
|
||||||
chrome.runtime.sendMessage({ action: 'copyText', data: timestampText }, (res) => {
|
|
||||||
if (chrome.runtime.lastError) {
|
|
||||||
console.error('❌ 传送时间戳文本失败:', chrome.runtime.lastError);
|
|
||||||
} else if (res?.success) {
|
|
||||||
console.log('✅ 已复制:', timestampText);
|
|
||||||
} else {
|
|
||||||
console.error('❌ 复制失败:', res);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function switchPage(pageName) {
|
|
||||||
// 隐藏所有页面
|
|
||||||
document.querySelectorAll('.page').forEach((page) => {
|
|
||||||
page.classList.remove('active');
|
|
||||||
});
|
|
||||||
|
|
||||||
// 移除所有导航按钮的 active 状态
|
|
||||||
document.querySelectorAll('.nav-button').forEach((button) => {
|
|
||||||
button.classList.remove('active');
|
|
||||||
});
|
|
||||||
|
|
||||||
// 显示目标页面
|
|
||||||
document.getElementById(`page-${pageName}`).classList.add('active');
|
|
||||||
|
|
||||||
// 激活对应的导航按钮
|
|
||||||
document.getElementById(`nav-${pageName}`).classList.add('active');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 关闭按钮逻辑 (使用消息传递)
|
|
||||||
document.getElementById('close').addEventListener('click', () => {
|
|
||||||
// 向父页面发送消息请求关闭
|
|
||||||
window.parent.postMessage({ action: 'closeSidebar' }, '*');
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -0,0 +1,176 @@
|
|||||||
|
import { updateTimestamp, convertTimestampToDate } from '../utils/timestampUtils.js';
|
||||||
|
import { getElementById } from '../utils/domUtils.js';
|
||||||
|
|
||||||
|
// 定义一个全局变量来保存是否显示毫秒
|
||||||
|
let showMilliseconds = true;
|
||||||
|
// 定义一个全局变量来保存计时器
|
||||||
|
let timestampInterval;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化时间戳显示
|
||||||
|
*/
|
||||||
|
export function initTimestampDisplay() {
|
||||||
|
updateTimestamp(showMilliseconds); // 初始化时更新一次时间戳
|
||||||
|
timestampInterval = setInterval(() => updateTimestamp(showMilliseconds), 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 切换单位按钮事件处理器
|
||||||
|
*/
|
||||||
|
export function handleToggleUnit() {
|
||||||
|
showMilliseconds = !showMilliseconds;
|
||||||
|
updateTimestamp(showMilliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止计时器事件处理器
|
||||||
|
*/
|
||||||
|
export function handleStopTimer() {
|
||||||
|
clearInterval(timestampInterval);
|
||||||
|
const stopTimestampBtn = getElementById('stop-timer-btn');
|
||||||
|
const startTimestampBtn = getElementById('start-timer-btn');
|
||||||
|
stopTimestampBtn.style.display = 'none';
|
||||||
|
startTimestampBtn.style.display = 'inline-block';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始计时器事件处理器
|
||||||
|
*/
|
||||||
|
export function handleStartTimer() {
|
||||||
|
const startTimestampBtn = getElementById('start-timer-btn');
|
||||||
|
const stopTimestampBtn = getElementById('stop-timer-btn');
|
||||||
|
timestampInterval = setInterval(() => updateTimestamp(showMilliseconds), 100);
|
||||||
|
startTimestampBtn.style.display = 'none';
|
||||||
|
stopTimestampBtn.style.display = 'inline-block';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间戳转换事件处理器
|
||||||
|
*/
|
||||||
|
export function handleConvertTimestamp() {
|
||||||
|
const inputTimestamp = getElementById('timestamp-input');
|
||||||
|
const timestampInputResult = getElementById('timestamp-conversion-result');
|
||||||
|
const timestampUnitSelect = document.querySelector(
|
||||||
|
'#page-timestamp #timestamp-input-unit-select'
|
||||||
|
);
|
||||||
|
|
||||||
|
const timestamp = inputTimestamp.value.trim();
|
||||||
|
console.log('输入时间戳:', timestamp);
|
||||||
|
|
||||||
|
if (!timestamp) {
|
||||||
|
timestampInputResult.value = '请输入时间戳';
|
||||||
|
// 添加动画效果
|
||||||
|
timestampInputResult.style.borderColor = '#dc3545';
|
||||||
|
setTimeout(() => {
|
||||||
|
timestampInputResult.style.borderColor = '';
|
||||||
|
}, 1000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取选择的时间戳单位(秒或毫秒)
|
||||||
|
const isSeconds = timestampUnitSelect.value === 'seconds';
|
||||||
|
|
||||||
|
const result = convertTimestampToDate(timestamp, isSeconds);
|
||||||
|
timestampInputResult.value = result;
|
||||||
|
|
||||||
|
// 添加成功反馈动画
|
||||||
|
if (result.includes('无效') || result.includes('请输入')) {
|
||||||
|
timestampInputResult.style.borderColor = '#dc3545';
|
||||||
|
} else {
|
||||||
|
timestampInputResult.style.borderColor = '#28a745';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加闪烁动画效果
|
||||||
|
timestampInputResult.style.transition = 'all 0.3s';
|
||||||
|
timestampInputResult.style.transform = 'scale(1.02)';
|
||||||
|
setTimeout(() => {
|
||||||
|
timestampInputResult.style.transform = 'scale(1)';
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日期转换事件处理器
|
||||||
|
*/
|
||||||
|
export function handleConvertDateToTimestamp() {
|
||||||
|
const inputDate = getElementById('datetime-input');
|
||||||
|
const dateInputResult = getElementById('date-conversion-result');
|
||||||
|
const timestampUnitSelect = document.querySelector('#page-timestamp #date-result-unit-select');
|
||||||
|
|
||||||
|
const dateStr = inputDate.value.trim();
|
||||||
|
console.log('输入日期字符串:', dateStr);
|
||||||
|
|
||||||
|
if (!dateStr) {
|
||||||
|
dateInputResult.value = '请输入日期字符串';
|
||||||
|
// 添加动画效果
|
||||||
|
dateInputResult.style.borderColor = '#dc3545';
|
||||||
|
setTimeout(() => {
|
||||||
|
dateInputResult.style.borderColor = '';
|
||||||
|
}, 1000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const date = new Date(dateStr);
|
||||||
|
if (isNaN(date.getTime())) {
|
||||||
|
dateInputResult.value = '无效的日期字符串';
|
||||||
|
dateInputResult.style.borderColor = '#dc3545';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const timestamp = date.getTime();
|
||||||
|
// 根据选择的单位决定显示秒还是毫秒
|
||||||
|
const isSeconds = timestampUnitSelect.value === 'seconds';
|
||||||
|
const finalTimestamp = isSeconds ? Math.floor(timestamp / 1000) : timestamp;
|
||||||
|
dateInputResult.value = finalTimestamp;
|
||||||
|
|
||||||
|
// 添加成功反馈动画
|
||||||
|
dateInputResult.style.borderColor = '#28a745';
|
||||||
|
|
||||||
|
// 添加闪烁动画效果
|
||||||
|
dateInputResult.style.transition = 'all 0.3s';
|
||||||
|
dateInputResult.style.transform = 'scale(1.02)';
|
||||||
|
setTimeout(() => {
|
||||||
|
dateInputResult.style.transform = 'scale(1)';
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复制时间戳事件处理器
|
||||||
|
*/
|
||||||
|
export function handleCopyTimestamp() {
|
||||||
|
// 获取时间戳文本
|
||||||
|
const currentTimestamp = getElementById('current-timestamp-value');
|
||||||
|
const timestampText = currentTimestamp.textContent;
|
||||||
|
|
||||||
|
// 添加复制反馈动画
|
||||||
|
const originalText = currentTimestamp.textContent;
|
||||||
|
currentTimestamp.textContent = '已复制!';
|
||||||
|
currentTimestamp.style.color = '#28a745';
|
||||||
|
currentTimestamp.style.fontWeight = 'bold';
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
currentTimestamp.textContent = originalText;
|
||||||
|
currentTimestamp.style.color = '';
|
||||||
|
currentTimestamp.style.fontWeight = '';
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
// 检查扩展上下文是否仍然有效
|
||||||
|
if (chrome.runtime && chrome.runtime.sendMessage) {
|
||||||
|
chrome.runtime.sendMessage({ action: 'copyText', data: timestampText }, (res) => {
|
||||||
|
if (chrome.runtime.lastError) {
|
||||||
|
console.error('❌ 传送时间戳文本失败:', chrome.runtime.lastError);
|
||||||
|
} else if (res?.success) {
|
||||||
|
console.log('✅ 已复制:', timestampText);
|
||||||
|
} else {
|
||||||
|
console.error('❌ 复制失败:', res);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭面板事件处理器
|
||||||
|
*/
|
||||||
|
export function handleClosePanel() {
|
||||||
|
// 向父页面发送消息请求关闭
|
||||||
|
window.parent.postMessage({ action: 'closeSidebar' }, '*');
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
/**
|
||||||
|
* DOM工具类函数
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 切换页面显示(带动画效果)
|
||||||
|
* @param {string} pageName - 页面名称
|
||||||
|
*/
|
||||||
|
export function switchPage(pageName) {
|
||||||
|
// 先隐藏当前活跃页面(如果有)
|
||||||
|
const currentPage = document.querySelector('.page.active');
|
||||||
|
if (currentPage) {
|
||||||
|
currentPage.classList.remove('active');
|
||||||
|
|
||||||
|
// 添加离开动画
|
||||||
|
currentPage.style.opacity = '0';
|
||||||
|
currentPage.style.transform = 'translateX(20px)';
|
||||||
|
|
||||||
|
// 等待动画完成后真正隐藏
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!currentPage.classList.contains('active')) {
|
||||||
|
currentPage.style.display = 'none';
|
||||||
|
}
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移除所有导航按钮的 active 状态
|
||||||
|
document.querySelectorAll('.nav-button').forEach((button) => {
|
||||||
|
button.classList.remove('active');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 显示目标页面
|
||||||
|
const targetPage = document.getElementById(`page-${pageName}`);
|
||||||
|
if (targetPage) {
|
||||||
|
targetPage.style.display = 'block';
|
||||||
|
|
||||||
|
// 触发重排以确保display变化生效
|
||||||
|
targetPage.offsetHeight;
|
||||||
|
|
||||||
|
// 添加进入动画
|
||||||
|
targetPage.style.opacity = '0';
|
||||||
|
targetPage.style.transform = 'translateX(-20px)';
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
targetPage.classList.add('active');
|
||||||
|
targetPage.style.opacity = '1';
|
||||||
|
targetPage.style.transform = 'translateX(0)';
|
||||||
|
}, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 激活对应的导航按钮
|
||||||
|
const navButton = document.getElementById(`nav-${pageName}-btn`) || document.getElementById(`nav-${pageName}`);
|
||||||
|
if (navButton) {
|
||||||
|
navButton.classList.add('active');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID获取元素的便捷方法
|
||||||
|
* @param {string} id - 元素ID
|
||||||
|
* @returns {HTMLElement} - DOM元素
|
||||||
|
*/
|
||||||
|
export function getElementById(id) {
|
||||||
|
return document.getElementById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 为元素添加事件监听器
|
||||||
|
* @param {string} id - 元素ID
|
||||||
|
* @param {string} event - 事件类型
|
||||||
|
* @param {Function} handler - 事件处理函数
|
||||||
|
*/
|
||||||
|
export function addEventListenerById(id, event, handler) {
|
||||||
|
const element = getElementById(id);
|
||||||
|
if (element) {
|
||||||
|
element.addEventListener(event, handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
/**
|
||||||
|
* 时间戳工具类函数
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新时间戳显示
|
||||||
|
* @param {boolean} showMilliseconds - 是否显示毫秒
|
||||||
|
*/
|
||||||
|
export function updateTimestamp(showMilliseconds = true) {
|
||||||
|
const currentTimestamp = document.getElementById('current-timestamp-value');
|
||||||
|
const currentTimestampUnit = document.getElementById('current-timestamp-unit');
|
||||||
|
const timestamp = Date.now();
|
||||||
|
const unit = showMilliseconds ? '毫秒' : '秒';
|
||||||
|
currentTimestamp.textContent = showMilliseconds ? timestamp : Math.floor(timestamp / 1000);
|
||||||
|
currentTimestampUnit.textContent = unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换时间戳为日期格式
|
||||||
|
* @param {string} timestamp - 输入的时间戳
|
||||||
|
* @param {boolean} isSeconds - 是否为秒格式
|
||||||
|
* @returns {string} 格式化后的日期字符串
|
||||||
|
*/
|
||||||
|
export function convertTimestampToDate(timestamp, isSeconds) {
|
||||||
|
// 转换为数字
|
||||||
|
let timestampNum = Number(timestamp);
|
||||||
|
|
||||||
|
// 如果是秒,转换为毫秒
|
||||||
|
if (isSeconds) {
|
||||||
|
timestampNum = timestampNum * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否为有效数字
|
||||||
|
if (isNaN(timestampNum)) {
|
||||||
|
return '请输入有效的时间戳';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建日期对象
|
||||||
|
const date = new Date(timestampNum);
|
||||||
|
|
||||||
|
// 检查日期是否有效
|
||||||
|
if (isNaN(date.getTime())) {
|
||||||
|
return '无效的日期';
|
||||||
|
}
|
||||||
|
|
||||||
|
const year = date.getFullYear();
|
||||||
|
const month = date.getMonth() + 1;
|
||||||
|
const day = date.getDate();
|
||||||
|
const hours = date.getHours();
|
||||||
|
const minutes = date.getMinutes();
|
||||||
|
const seconds = date.getSeconds();
|
||||||
|
|
||||||
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换日期格式为时间戳
|
||||||
|
* @param {string} date - 输入的日期字符串
|
||||||
|
* @returns {number|string} 时间戳或错误信息
|
||||||
|
*/
|
||||||
|
export function convertDateToTimestamp(date) {
|
||||||
|
const timestamp = Date.parse(date);
|
||||||
|
return isNaN(timestamp) ? '无效的日期' : timestamp;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user