```
feat(router): 引入路由系统并重构页面结构 - 为项目引入基于 hash 的前端路由系统,支持多页面切换与动态加载 - 将原有单一 bundle 拆分为多个入口打包(index.js 和 timestamp.js) - 修改 Rollup 配置以支持多输出文件及插件共享 - 更新 HTML 结构以适配路由容器和页面占位元素 - 调整 CSS 样式,移除旧的页面切换动画,交由路由控制 - 优化 domUtils 工具函数,并迁移部分样式处理逻辑 - 在 timestamp.js 中封装初始化函数以便路由调用 - todolist 页面模板新增,用于后续功能开发 ```
This commit is contained in:
+36
-27
@@ -5,32 +5,41 @@ import json from '@rollup/plugin-json';
|
|||||||
import livereload from 'rollup-plugin-livereload';
|
import livereload from 'rollup-plugin-livereload';
|
||||||
import serve from 'rollup-plugin-serve';
|
import serve from 'rollup-plugin-serve';
|
||||||
|
|
||||||
export default defineConfig({
|
const basePlugins = [resolve(), commonjs(), json()];
|
||||||
input: 'sidepanel/js/index.js',
|
|
||||||
output: {
|
const devPlugins = [
|
||||||
file: 'dist/bundle.js',
|
livereload({
|
||||||
format: 'iife',
|
watch: ['dist', 'sidepanel'],
|
||||||
|
verbose: false,
|
||||||
|
}),
|
||||||
|
serve({
|
||||||
|
open: true,
|
||||||
|
port: 8082,
|
||||||
|
contentBase: ['.', 'sidepanel'],
|
||||||
|
headers: {
|
||||||
|
'Access-Control-Allow-Origin': '*',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
export default defineConfig([
|
||||||
|
{
|
||||||
|
input: 'sidepanel/js/index.js',
|
||||||
|
output: {
|
||||||
|
file: 'dist/index.js',
|
||||||
|
format: 'iife',
|
||||||
|
name: 'MainPage',
|
||||||
|
},
|
||||||
|
plugins: [...basePlugins, ...devPlugins],
|
||||||
},
|
},
|
||||||
plugins: [
|
|
||||||
resolve(),
|
{
|
||||||
commonjs(),
|
input: 'sidepanel/js/timestamp.js',
|
||||||
json(),
|
output: {
|
||||||
livereload({
|
file: 'dist/timestamp.js',
|
||||||
watch: ['dist', 'sidepanel'],
|
format: 'iife',
|
||||||
verbose: false,
|
name: 'TimestampPage',
|
||||||
}),
|
},
|
||||||
serve({
|
plugins: [...basePlugins, ...devPlugins],
|
||||||
open: true,
|
|
||||||
port: 8082,
|
|
||||||
contentBase: ['.', 'sidepanel'],
|
|
||||||
headers: {
|
|
||||||
'Access-Control-Allow-Origin': '*',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
watch: {
|
|
||||||
include: ['sidepanel/**/*'],
|
|
||||||
exclude: ['node_modules/**/*'],
|
|
||||||
clearScreen: false,
|
|
||||||
},
|
},
|
||||||
});
|
]);
|
||||||
|
|||||||
+10
-4
@@ -10,12 +10,18 @@
|
|||||||
<body>
|
<body>
|
||||||
<!-- 导航栏 -->
|
<!-- 导航栏 -->
|
||||||
<nav class="navbar">
|
<nav class="navbar">
|
||||||
<button class="nav-button active">时间戳转换</button>
|
<button class="nav-button active" id="timestamp-jump">时间戳转换</button>
|
||||||
<button class="nav-button">任务清单</button>
|
<button class="nav-button" id="todo-jump">任务清单</button>
|
||||||
<button id="close-panel-btn" class="close-button">X</button>
|
<button id="close-panel-btn" class="close-button">X</button>
|
||||||
</nav>
|
</nav>
|
||||||
<div id="app"></div>
|
<div id="app">
|
||||||
|
<div class="page" hash="/home">
|
||||||
|
<div class="page-content">
|
||||||
|
<div id="home"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="../dist/bundle.js"></script>
|
<script src="../dist/index.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
+54
-13
@@ -1,17 +1,58 @@
|
|||||||
// 导入时间戳工具的初始化函数和事件处理
|
console.log('Before creating router');
|
||||||
import './timestamp.js';
|
import { Router } from '../modules/Router.js';
|
||||||
|
|
||||||
// 导入页面切换功能
|
import * as PageModules from '../../dist/timestamp.js';
|
||||||
import { switchPage } from '../utils/domUtils.js';
|
|
||||||
|
|
||||||
// 页面切换逻辑
|
const config = {
|
||||||
import { addEventListenerById } from '../utils/domUtils.js';
|
routerViewId: 'app', // 路由切换的挂载点 id
|
||||||
|
stackPages: false, // 多级页面缓存
|
||||||
|
animationName: 'fade', // 切换页面时的动画
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: '/home',
|
||||||
|
name: 'home',
|
||||||
|
callback: async () => {
|
||||||
|
// 1. 加载 HTML
|
||||||
|
const html = await fetch('pages/timestamp.html').then((r) => r.text());
|
||||||
|
document.getElementById('home').innerHTML = html;
|
||||||
|
|
||||||
addEventListenerById('nav-timestamp-btn', 'click', () => {
|
// 2. 动态加载对应 JS
|
||||||
switchPage('timestamp');
|
const script = document.createElement('script');
|
||||||
|
script.src = '/dist/timestamp.js'; // IIFE 打包后的文件
|
||||||
|
script.onload = () => {
|
||||||
|
// 3. 执行 IIFE 暴露的全局对象方法
|
||||||
|
TimestampPage.init(); // 假设 timestamp.js 输出 name: 'TimestampPage'
|
||||||
|
};
|
||||||
|
document.body.appendChild(script);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/todo',
|
||||||
|
name: 'todo',
|
||||||
|
callback: async () => {
|
||||||
|
// 1. 加载 HTML
|
||||||
|
const html = await fetch('pages/todolist.html').then((r) => r.text());
|
||||||
|
document.getElementById('todo').innerHTML = html;
|
||||||
|
|
||||||
|
// 2. 动态加载对应 JS
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.src = '/dist/timestamp.js'; // IIFE 打包后的文件
|
||||||
|
script.onload = () => {
|
||||||
|
// 3. 执行 IIFE 暴露的全局对象方法
|
||||||
|
TimestampPage.init(); // 假设 timestamp.js 输出 name: 'TimestampPage'
|
||||||
|
};
|
||||||
|
document.body.appendChild(script);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const router = new Router();
|
||||||
|
console.log('Router created:', router);
|
||||||
|
router.init(config);
|
||||||
|
console.log('Router initialized');
|
||||||
|
|
||||||
|
document.getElementById('todo-jump').addEventListener('click', () => {
|
||||||
|
console.log('Jumping to todo page');
|
||||||
|
window.linkTo('#/todo');
|
||||||
});
|
});
|
||||||
|
|
||||||
// 计时器页面切换
|
|
||||||
addEventListenerById('nav-other-tools-btn', 'click', () => {
|
|
||||||
switchPage('other-tools');
|
|
||||||
});
|
|
||||||
+23
-20
@@ -12,24 +12,27 @@ import {
|
|||||||
} from '../modules/eventHandlers.js';
|
} from '../modules/eventHandlers.js';
|
||||||
import { addEventListenerById } from '../utils/domUtils.js';
|
import { addEventListenerById } from '../utils/domUtils.js';
|
||||||
|
|
||||||
// 初始化时间戳显示
|
export function init() {
|
||||||
initTimestampDisplay();
|
console.log('timestamp init')
|
||||||
|
// 初始化时间戳显示
|
||||||
|
initTimestampDisplay();
|
||||||
|
|
||||||
// 绑定事件处理器
|
// 绑定事件处理器
|
||||||
// 绑定时间戳相关按钮事件
|
// 绑定时间戳相关按钮事件
|
||||||
addEventListenerById('toggle-unit-btn', 'click', handleToggleUnit);
|
addEventListenerById('toggle-unit-btn', 'click', handleToggleUnit);
|
||||||
// 绑定计时器相关按钮事件
|
// 绑定计时器相关按钮事件
|
||||||
addEventListenerById('stop-timer-btn', 'click', handleStopTimer);
|
addEventListenerById('stop-timer-btn', 'click', handleStopTimer);
|
||||||
addEventListenerById('start-timer-btn', 'click', handleStartTimer);
|
addEventListenerById('start-timer-btn', 'click', handleStartTimer);
|
||||||
// 绑定时间戳转换按钮事件
|
// 绑定时间戳转换按钮事件
|
||||||
addEventListenerById('convert-timestamp-to-date-btn', 'click', handleConvertTimestamp);
|
addEventListenerById('convert-timestamp-to-date-btn', 'click', handleConvertTimestamp);
|
||||||
// 绑定日期转换按钮事件
|
// 绑定日期转换按钮事件
|
||||||
addEventListenerById('convert-date-to-timestamp-btn', 'click', handleConvertDateToTimestamp);
|
addEventListenerById('convert-date-to-timestamp-btn', 'click', handleConvertDateToTimestamp);
|
||||||
// 绑定复制时间戳按钮事件
|
// 绑定复制时间戳按钮事件
|
||||||
addEventListenerById('copy-timestamp-btn', 'click', handleCopyTimestamp);
|
addEventListenerById('copy-timestamp-btn', 'click', handleCopyTimestamp);
|
||||||
// 绑定关闭面板按钮事件
|
// 绑定关闭面板按钮事件
|
||||||
addEventListenerById('close-panel-btn', 'click', handleClosePanel);
|
addEventListenerById('close-panel-btn', 'click', handleClosePanel);
|
||||||
// 绑定切换时区事件
|
// 绑定切换时区事件
|
||||||
addEventListenerById('timezone-result', 'change', handleTimezoneResult);
|
addEventListenerById('timezone-result', 'change', handleTimezoneResult);
|
||||||
// 绑定输入时区事件
|
// 绑定输入时区事件
|
||||||
addEventListenerById('timezone-input', 'change', handleTimezoneInput);
|
addEventListenerById('timezone-input', 'change', handleTimezoneInput);
|
||||||
|
}
|
||||||
|
|||||||
+86
-31
@@ -1,12 +1,20 @@
|
|||||||
import {
|
import { getParamsUrl, closure, genKey } from '../utils/routeUtils.js';
|
||||||
RouteUtils,
|
|
||||||
addClass,
|
import { addClass, removeClass, hasClass } from '../utils/domUtils.js';
|
||||||
removeClass,
|
// var config = {
|
||||||
hasClass,
|
// routerViewId: '#routerView', // 路由切换的挂载点 id
|
||||||
getParamsUrl,
|
// stackPages: true, // 多级页面缓存
|
||||||
closure,
|
// animationName: "slide", // 多级页面缓存
|
||||||
genKey,
|
// routes: [
|
||||||
} from '../utils/routeUtils.js';
|
// // {
|
||||||
|
// // path: "/home",
|
||||||
|
// // name: "home",
|
||||||
|
// // callback: function(transition) {
|
||||||
|
// // home()
|
||||||
|
// // }
|
||||||
|
// // }
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
class Router {
|
class Router {
|
||||||
constructor() {
|
constructor() {
|
||||||
// 路由表
|
// 路由表
|
||||||
@@ -32,14 +40,23 @@ class Router {
|
|||||||
}
|
}
|
||||||
|
|
||||||
init(config) {
|
init(config) {
|
||||||
this.routerMap = config ? config.routers : this.routerMap;
|
this.routerMap = config ? config.routes : this.routerMap;
|
||||||
this.routerViewId = config ? config.routerViewId : this.routerViewId;
|
this.routerViewId = config ? config.routerViewId : this.routerViewId;
|
||||||
this.stackPages = config ? config.stackPages : this.stackPages;
|
this.stackPages = config ? config.stackPages : this.stackPages;
|
||||||
|
|
||||||
|
const name = document.querySelector('#app').getAttribute('data-animationName');
|
||||||
|
if (name) {
|
||||||
|
this.animationName = name;
|
||||||
|
}
|
||||||
|
this.animationName = config ? config.animationName : this.animationName;
|
||||||
|
|
||||||
|
this.map();
|
||||||
|
|
||||||
if (!this.routerMap.length) {
|
if (!this.routerMap.length) {
|
||||||
let selector = this.routerViewId + '.page';
|
// 找到routerViewId 节点下的所有page 节点
|
||||||
let pages = document.querySelectorAll(selector);
|
const pages = document.querySelectorAll(this.routerViewId + ' .page');
|
||||||
for (let i = 0; i < pages.length; i++) {
|
for (let i = 0; i < pages.length; i++) {
|
||||||
|
// 遍历所有的page节点
|
||||||
let page = pages[i];
|
let page = pages[i];
|
||||||
let hash = page.getAttribute('hash');
|
let hash = page.getAttribute('hash');
|
||||||
let name = hash.substring(1);
|
let name = hash.substring(1);
|
||||||
@@ -60,13 +77,13 @@ class Router {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener(
|
window.addEventListener('load', (event) => {
|
||||||
'load',
|
this.historyChange(event);
|
||||||
function (event) {
|
});
|
||||||
this.historyChange(event);
|
|
||||||
},
|
window.addEventListener('hashchange', (event) => {
|
||||||
false
|
this.historyChange(event);
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -74,29 +91,41 @@ class Router {
|
|||||||
* @param {*} event
|
* @param {*} event
|
||||||
*/
|
*/
|
||||||
historyChange(event) {
|
historyChange(event) {
|
||||||
|
// {path, query, params}
|
||||||
const currentHash = getParamsUrl();
|
const currentHash = getParamsUrl();
|
||||||
|
// router-#app-history
|
||||||
const nameString = 'router-' + this.routerViewId + '-history';
|
const nameString = 'router-' + this.routerViewId + '-history';
|
||||||
|
|
||||||
this.history = window.sessionStorage[nameString]
|
this.history = window.sessionStorage[nameString]
|
||||||
? JSON.parse(window.sessionStorage[nameString])
|
? JSON.parse(window.sessionStorage[nameString])
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
let back = false,
|
// 返回上一级
|
||||||
refresh = false,
|
let back = false;
|
||||||
forward = false,
|
// 刷新页面
|
||||||
index = 0,
|
let refresh = false;
|
||||||
len = this.history.length;
|
// 前进上一级
|
||||||
|
let forward = false;
|
||||||
|
// 获取当前路由的索引
|
||||||
|
let index = 0;
|
||||||
|
|
||||||
for (let i = 0; i < len; i++) {
|
for (let i = 0; i < this.history.length; i++) {
|
||||||
let h = this.history[i];
|
let h = this.history[i];
|
||||||
|
|
||||||
|
// 判断是否是当前路由
|
||||||
if (h.hash === currentHash.path && h.key === currentHash.query.key) {
|
if (h.hash === currentHash.path && h.key === currentHash.query.key) {
|
||||||
|
// 获取当前路由的索引
|
||||||
index = i;
|
index = i;
|
||||||
if (i === len - 1) {
|
// 判断是否是刷新页面
|
||||||
|
if (i === this.history.length - 1) {
|
||||||
refresh = true;
|
refresh = true;
|
||||||
} else {
|
} else {
|
||||||
|
// 判断是否是返回上一级
|
||||||
back = true;
|
back = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
// 判断是否是前进
|
||||||
forward = true;
|
forward = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -124,18 +153,22 @@ class Router {
|
|||||||
this.urlChange();
|
this.urlChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更改页面
|
||||||
|
* @param {*} currentHash
|
||||||
|
*/
|
||||||
changeView(currentHash) {
|
changeView(currentHash) {
|
||||||
const pages = document.querySelectorAll('.page');
|
const pages = document.querySelectorAll(' .page');
|
||||||
const previousPage = document.querySelector('.' + this.routerViewId + ' .page.active');
|
const previousPage = document.querySelector('.' + this.routerViewId + ' .page.active');
|
||||||
let currentPage = null;
|
let currentPage = null;
|
||||||
let currentHash = null;
|
let currHash = null;
|
||||||
|
|
||||||
for (let i = 0; i < pages.length; i++) {
|
for (let i = 0; i < pages.length; i++) {
|
||||||
let page = pages[i];
|
let page = pages[i];
|
||||||
let hash = page.getAttribute('hash');
|
let hash = page.getAttribute('hash');
|
||||||
page.setAttribute('class', 'page');
|
page.setAttribute('class', 'page');
|
||||||
if (hash === currentHash.path) {
|
if (hash === currentHash.path) {
|
||||||
currentHash = hash;
|
currHash = hash;
|
||||||
currentPage = page;
|
currentPage = page;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -167,12 +200,15 @@ class Router {
|
|||||||
removeClass(currentPage, 'current');
|
removeClass(currentPage, 'current');
|
||||||
}, 300);
|
}, 300);
|
||||||
currentPage.scrollTop = 0;
|
currentPage.scrollTop = 0;
|
||||||
this.routes[currentHash].callback ? this.routes[currentHash].callback() : null;
|
this.routes[currHash].callback ? this.routes[currHash].callback() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.afterFun ? this.afterFun(currentHash) : null;
|
this.afterFun ? this.afterFun(currentHash) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* url改变
|
||||||
|
*/
|
||||||
urlChange() {
|
urlChange() {
|
||||||
const currentHash = getParamsUrl();
|
const currentHash = getParamsUrl();
|
||||||
if (this.routes[currentHash.path]) {
|
if (this.routes[currentHash.path]) {
|
||||||
@@ -194,6 +230,9 @@ class Router {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 映射路由
|
||||||
|
*/
|
||||||
map() {
|
map() {
|
||||||
for (let i = 0; i < this.routerMap.length; i++) {
|
for (let i = 0; i < this.routerMap.length; i++) {
|
||||||
let route = this.routerMap[i];
|
let route = this.routerMap[i];
|
||||||
@@ -204,26 +243,42 @@ class Router {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let newPath = route.path;
|
let newPath = route.path;
|
||||||
let path = newPath.repalce(/\s+/g, '');
|
let path = newPath.replace(/\s+/g, '');
|
||||||
this.routes[path] = {
|
this.routes[path] = {
|
||||||
callback: route.callback,
|
callback: route.callback,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 切换页面前的hook
|
||||||
|
* @param {*} callback hook执行函数
|
||||||
|
*/
|
||||||
|
|
||||||
beforeEach(callback) {
|
beforeEach(callback) {
|
||||||
if (Object.prototype.toString.call(callback) === '[object Function]') {
|
if (Object.prototype.toString.call(callback) === '[object Function]') {
|
||||||
|
// 判断callback是否为函数
|
||||||
this.beforeFun = callback;
|
this.beforeFun = callback;
|
||||||
} else {
|
} else {
|
||||||
|
// 抛出错误
|
||||||
console.trace('beforeEach callback must be a function');
|
console.trace('beforeEach callback must be a function');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 切换页面后的hook
|
||||||
|
* @param {*} callback hook执行函数
|
||||||
|
*/
|
||||||
|
|
||||||
afterEach(callback) {
|
afterEach(callback) {
|
||||||
if (Object.prototype.toString.call(callback) === '[object Function]') {
|
if (Object.prototype.toString.call(callback) === '[object Function]') {
|
||||||
|
// 判断callback是否为函数
|
||||||
this.afterFun = callback;
|
this.afterFun = callback;
|
||||||
} else {
|
} else {
|
||||||
|
// 抛出错误
|
||||||
console.trace('afterEach callback must be a function');
|
console.trace('afterEach callback must be a function');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export { Router };
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<div id="page-timestamp" class="page active">
|
<div id="page-timestamp" class="page">
|
||||||
<h2>时间戳工具</h2>
|
<h2>时间戳工具</h2>
|
||||||
<div id="current-timestamp">
|
<div id="current-timestamp">
|
||||||
<h2>当前时间戳</h2>
|
<h2>当前时间戳</h2>
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
<div id="page-timestamp" class="page">
|
||||||
|
<h2>任务清单</h2>
|
||||||
|
</div>
|
||||||
@@ -53,9 +53,10 @@
|
|||||||
p a {
|
p a {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
color: #2b2b2b;
|
color: #2b2b2b;
|
||||||
font-family: ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New,
|
||||||
|
monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
padding: 0.5rem 1rem;
|
padding: 0.5rem 1rem;
|
||||||
background-color: #28a745;
|
background-color: #28a745;
|
||||||
@@ -150,27 +151,6 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 页面切换动画 */
|
|
||||||
.page {
|
|
||||||
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 {
|
|
||||||
display: block;
|
|
||||||
position: relative;
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateX(0);
|
|
||||||
transition: opacity 0.3s ease, transform 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 按钮点击效果 */
|
/* 按钮点击效果 */
|
||||||
.button:active,
|
.button:active,
|
||||||
.convert-button:active,
|
.convert-button:active,
|
||||||
|
|||||||
@@ -11,11 +11,11 @@ export function switchPage(pageName) {
|
|||||||
const currentPage = document.querySelector('.page.active');
|
const currentPage = document.querySelector('.page.active');
|
||||||
if (currentPage) {
|
if (currentPage) {
|
||||||
currentPage.classList.remove('active');
|
currentPage.classList.remove('active');
|
||||||
|
|
||||||
// 添加离开动画
|
// 添加离开动画
|
||||||
currentPage.style.opacity = '0';
|
currentPage.style.opacity = '0';
|
||||||
currentPage.style.transform = 'translateX(20px)';
|
currentPage.style.transform = 'translateX(20px)';
|
||||||
|
|
||||||
// 等待动画完成后真正隐藏
|
// 等待动画完成后真正隐藏
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (!currentPage.classList.contains('active')) {
|
if (!currentPage.classList.contains('active')) {
|
||||||
@@ -33,14 +33,14 @@ export function switchPage(pageName) {
|
|||||||
const targetPage = document.getElementById(`page-${pageName}`);
|
const targetPage = document.getElementById(`page-${pageName}`);
|
||||||
if (targetPage) {
|
if (targetPage) {
|
||||||
targetPage.style.display = 'block';
|
targetPage.style.display = 'block';
|
||||||
|
|
||||||
// 触发重排以确保display变化生效
|
// 触发重排以确保display变化生效
|
||||||
targetPage.offsetHeight;
|
targetPage.offsetHeight;
|
||||||
|
|
||||||
// 添加进入动画
|
// 添加进入动画
|
||||||
targetPage.style.opacity = '0';
|
targetPage.style.opacity = '0';
|
||||||
targetPage.style.transform = 'translateX(-20px)';
|
targetPage.style.transform = 'translateX(-20px)';
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
targetPage.classList.add('active');
|
targetPage.classList.add('active');
|
||||||
targetPage.style.opacity = '1';
|
targetPage.style.opacity = '1';
|
||||||
@@ -49,7 +49,8 @@ export function switchPage(pageName) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 激活对应的导航按钮
|
// 激活对应的导航按钮
|
||||||
const navButton = document.getElementById(`nav-${pageName}-btn`) || document.getElementById(`nav-${pageName}`);
|
const navButton =
|
||||||
|
document.getElementById(`nav-${pageName}-btn`) || document.getElementById(`nav-${pageName}`);
|
||||||
if (navButton) {
|
if (navButton) {
|
||||||
navButton.classList.add('active');
|
navButton.classList.add('active');
|
||||||
}
|
}
|
||||||
@@ -75,4 +76,46 @@ export function addEventListenerById(id, event, handler) {
|
|||||||
if (element) {
|
if (element) {
|
||||||
element.addEventListener(event, handler);
|
element.addEventListener(event, handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断元素是否包含指定类名
|
||||||
|
* @param {*} elem
|
||||||
|
* @param {*} cls
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function hasClass(elem, cls) {
|
||||||
|
cls = cls || '';
|
||||||
|
// 检测类名是否为''
|
||||||
|
if (cls.replace(/\s/g, '').length === 0) return false;
|
||||||
|
// 检测elem类名是否包含cls指定类名
|
||||||
|
return new RegExp(' ' + cls + ' ').test(' ' + elem.className + ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 为元素添加类名
|
||||||
|
* @param {*} elem
|
||||||
|
* @param {*} cls
|
||||||
|
*/
|
||||||
|
export function addClass(elem, cls) {
|
||||||
|
if (!hasClass(elem, cls)) {
|
||||||
|
elem.className = elem.className === '' ? cls : elem.className + ' ' + cls;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 为元素删除类名
|
||||||
|
* @param {*} elem
|
||||||
|
* @param {*} cls
|
||||||
|
*/
|
||||||
|
export function removeClass(elem, cls) {
|
||||||
|
if (hasClass(elem, cls)) {
|
||||||
|
let newClass = ' ' + elem.className.replace(/[\t\r\n]/g, '') + ' ';
|
||||||
|
// 删除指定类名
|
||||||
|
while (newClass.indexOf(' ' + cls + ' ') >= 0) {
|
||||||
|
newClass = newClass.replace(' ' + cls + ' ', ' ');
|
||||||
|
}
|
||||||
|
// 重新赋值
|
||||||
|
elem.className = newClass.replace(/^\s+|\s+$/);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
/**
|
/**
|
||||||
* 获取路由的路径和详情参数
|
* 获取路由的路径和详细参数
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function getParamsUrl() {
|
export function getParamsUrl() {
|
||||||
let hasDetail = location.hash.split('?');
|
// 获取路由
|
||||||
let hasName = hasDetail[0].split('#')[1];
|
const hasDetail = location.hash.split('?');
|
||||||
let params = hasDetail[1] ? hasDetail[1].split('&') : [];
|
// 获取路由名称
|
||||||
|
const hasName = hasDetail[0].split('#')[1];
|
||||||
|
// 获取请求参数
|
||||||
|
const params = hasDetail[1] ? hasDetail[1].split('&') : [];
|
||||||
|
// 解析请求参数
|
||||||
let query = {};
|
let query = {};
|
||||||
|
|
||||||
for (let i = 0; i < params.length; i++) {
|
for (let i = 0; i < params.length; i++) {
|
||||||
let param = params[i].split('=');
|
let param = params[i].split('=');
|
||||||
query[param[0]] = param[1];
|
query[param[0]] = param[1];
|
||||||
@@ -20,40 +23,26 @@ export function getParamsUrl() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 闭包返回函数
|
||||||
|
* @param {*} name
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
export function closure(name) {
|
export function closure(name) {
|
||||||
function fun(currentHash) {
|
return (currentHash) => {
|
||||||
window.name&&window[name](currentHash)
|
window.name && window[name](currentHash);
|
||||||
}
|
};
|
||||||
return fun;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成随机key
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
export function genKey() {
|
export function genKey() {
|
||||||
let temp = 'xxxxxxxx';
|
const KEY_TEMPLATE = 'xxxxxxxx';
|
||||||
return temp.replace(/[xy]/g, function (c) {
|
return KEY_TEMPLATE.replace(/[xy]/g, (c) => {
|
||||||
let r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
|
const r = (Math.random() * 16) | 0;
|
||||||
return v.toString(16);
|
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
||||||
});
|
return v.toString(16);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hasClass(elem, cls) {
|
|
||||||
cls = cls || '';
|
|
||||||
if (cls.replace(/\s/g, '').length === 0)
|
|
||||||
return false;
|
|
||||||
return new RegExp(' ' + cls + ' ').test(' ' + elem.className + ' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
export function addClass(elem, cls) {
|
|
||||||
if (!hasClass(elem, cls)) {
|
|
||||||
elem.className = elem.className === '' ? cls : elem.className + ' ' + cls;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function removeClass(elem, cls) {
|
|
||||||
if (hasClass(elem, cls)) {
|
|
||||||
let newClass = ' ' + elem.className.replace(/[\t\r\n]/g, '') + ' ';
|
|
||||||
while (newClass.indexOf(' ' + cls + ' ') >= 0) {
|
|
||||||
newClass = newClass.replace(' ' + cls + ' ', ' ');
|
|
||||||
}
|
|
||||||
elem.className = newClass.replace(/^\s+|\s+$/)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user