feat(sidepanel): 实现基于组件的架构并优化路由管理
- 引入 BaseComponent 基类统一管理事件、定时器和脚本加载 - 重构 timestamp 模块为继承自 BaseComponent 的类组件 - 新增 ScriptManager 工具类用于动态加载和卸载脚本 - 修改路由配置支持按需加载页面对应的 JS 模块 - 路由切换时自动销毁旧组件实例以防止内存泄漏 - 更新文件引用路径适配新的目录结构 - 修复 rollup 配置中的语法问题及端口配置 - 移除无用的日志输出和冗余代码提升性能
This commit is contained in:
+3
-3
@@ -1,4 +1,4 @@
|
|||||||
import { defineConfig } from 'rollup';
|
import {defineConfig} from 'rollup';
|
||||||
import resolve from '@rollup/plugin-node-resolve';
|
import resolve from '@rollup/plugin-node-resolve';
|
||||||
import commonjs from '@rollup/plugin-commonjs';
|
import commonjs from '@rollup/plugin-commonjs';
|
||||||
import json from '@rollup/plugin-json';
|
import json from '@rollup/plugin-json';
|
||||||
@@ -14,7 +14,7 @@ const devPlugins = [
|
|||||||
}),
|
}),
|
||||||
serve({
|
serve({
|
||||||
open: true,
|
open: true,
|
||||||
port: 8082,
|
port: 3000,
|
||||||
contentBase: ['.', 'sidepanel'],
|
contentBase: ['.', 'sidepanel'],
|
||||||
headers: {
|
headers: {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
@@ -42,4 +42,4 @@ export default defineConfig([
|
|||||||
},
|
},
|
||||||
plugins: [...basePlugins, ...devPlugins],
|
plugins: [...basePlugins, ...devPlugins],
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
export class BaseComponent {
|
||||||
|
constructor() {
|
||||||
|
this._timerManager = window.timerManager;
|
||||||
|
this._scriptManager = window.scriptManager;
|
||||||
|
this._eventManager = window.eventManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安全绑定事件,并自动记录以记录销毁
|
||||||
|
* @param {string | HTMLElement} target 目标元素
|
||||||
|
* @param {string} type 事件类型
|
||||||
|
* @param {Function} handler 回调函数
|
||||||
|
*/
|
||||||
|
bindEvent(target, type, handler) {
|
||||||
|
|
||||||
|
console.log('Bind 1111;')
|
||||||
|
// 获取目标元素
|
||||||
|
const ele = typeof target === 'string' ? document.getElementById(target) : target;
|
||||||
|
|
||||||
|
if (!ele) {
|
||||||
|
console.error(`Element with ID ${target} not found.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ele.addEventListener(type, handler);
|
||||||
|
|
||||||
|
this._eventManager.add(ele, type, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建定时器
|
||||||
|
* @param {Function} fn 定时器回调函数
|
||||||
|
* @param {number} ms 定时器间隔时间(毫秒)
|
||||||
|
*/
|
||||||
|
setInterval(fn, ms) {
|
||||||
|
this._timerManager.setInterval(fn, ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建定时器
|
||||||
|
* @param {Function} fn 定时器回调函数
|
||||||
|
* @param {number} ms 定时器间隔时间(毫秒)
|
||||||
|
*/
|
||||||
|
setTimeout(fn, ms) {
|
||||||
|
this._timerManager.setTimeout(fn, ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载脚本
|
||||||
|
* @param {string} path 脚本路径
|
||||||
|
* @param {string} name 脚本名称
|
||||||
|
* @param {boolean} isModule 是否为模块
|
||||||
|
* @param {string[]} deps 依赖的脚本
|
||||||
|
*/
|
||||||
|
loadScript(path, name, isModule = false, deps = []) {
|
||||||
|
this._scriptManager.loadScript({path, name, isModule, deps});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 销毁组件
|
||||||
|
*/
|
||||||
|
destroy() {
|
||||||
|
this._eventManager.removeAll();
|
||||||
|
this._timerManager.cleanAll();
|
||||||
|
this._scriptManager.unloadScript().then(r => console.log(r));
|
||||||
|
console.log('destroy success');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.BaseComponent = BaseComponent;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ScriptManager } from '../utils/scriptManager.js';
|
import {ScriptManager} from './utils/scriptManager.js';
|
||||||
import { TimerManager } from '../utils/timerManager.js';
|
import {TimerManager} from './utils/timerManager.js';
|
||||||
import { EventManager } from '../utils/eventManager.js';
|
import {EventManager} from './utils/eventManager.js';
|
||||||
import { Router } from '../modules/Router.js';
|
import {Router} from '../modules/Router.js';
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
routerViewId: 'app',
|
routerViewId: 'app',
|
||||||
@@ -9,8 +9,9 @@ const config = {
|
|||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
name: 'redirect',
|
name: 'timestamp',
|
||||||
html: 'pages/timestamp.html',
|
html: 'pages/timestamp.html',
|
||||||
|
script: '../dist/timestamp.js',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/home',
|
path: '/home',
|
||||||
|
|||||||
+77
-91
@@ -1,108 +1,94 @@
|
|||||||
import {
|
import {
|
||||||
handleToggleUnit,
|
|
||||||
handleStopTimer,
|
|
||||||
handleStartTimer,
|
|
||||||
handleConvertTimestamp,
|
|
||||||
handleConvertDateToTimestamp,
|
|
||||||
handleCopyTimestamp,
|
|
||||||
handleClosePanel,
|
handleClosePanel,
|
||||||
handleTimezoneResult,
|
handleConvertDateToTimestamp,
|
||||||
|
handleConvertTimestamp,
|
||||||
|
handleCopyTimestamp,
|
||||||
|
handleStartTimer,
|
||||||
|
handleStopTimer,
|
||||||
handleTimezoneInput,
|
handleTimezoneInput,
|
||||||
|
handleTimezoneResult,
|
||||||
|
handleToggleUnit,
|
||||||
} from '../modules/eventHandlers.js';
|
} from '../modules/eventHandlers.js';
|
||||||
import { updateTimestamp } from '../utils/timestampUtils.js';
|
import {updateTimestamp} from './utils/timestampUtils.js';
|
||||||
import { addEventListenerById } from '../utils/domUtils.js';
|
import {timeZoneList} from './const/timezone.js';
|
||||||
import { timeZoneList } from './const/timezone.js';
|
|
||||||
|
const BaseComponent = window.BaseComponent;
|
||||||
|
|
||||||
// 定义一个全局变量来保存是否显示毫秒
|
|
||||||
let showMilliseconds = true;
|
|
||||||
// 定义一个全局变量来保存计时器
|
|
||||||
let timestampInterval;
|
|
||||||
// 获取本地时区
|
// 获取本地时区
|
||||||
const localTimeZone = new Intl.DateTimeFormat().resolvedOptions().timeZone;
|
const localTimeZone = new Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||||
|
|
||||||
/**
|
class Timestamp extends BaseComponent {
|
||||||
* 初始化时间戳显示
|
constructor() {
|
||||||
*/
|
super();
|
||||||
function initTimestampDisplay() {
|
this.init();
|
||||||
const currentTimestampValue = document.getElementById('current-timestamp-value');
|
// 定义一个全局变量来保存是否显示毫秒
|
||||||
|
this.showMilliseconds = true;
|
||||||
// 初始化时更新一次时间戳
|
// 定义一个全局变量来保存计时器
|
||||||
updateTimestamp(currentTimestampValue, showMilliseconds);
|
this.timestampInterval = null;
|
||||||
|
|
||||||
// 添加时间戳定时器
|
|
||||||
if (timestampInterval) {
|
|
||||||
console.log('clearInterval');
|
|
||||||
clearInterval(timestampInterval);
|
|
||||||
window.timerManager.clearInterval(timestampInterval);
|
|
||||||
}
|
}
|
||||||
timestampInterval = setInterval(
|
|
||||||
() => updateTimestamp(currentTimestampValue, showMilliseconds),
|
|
||||||
100
|
|
||||||
);
|
|
||||||
window.timerManager.setInterval(timestampInterval);
|
|
||||||
|
|
||||||
initTimeZoneList();
|
async init() {
|
||||||
initTimestampAndDate();
|
const currentTimestampValue = document.getElementById('current-timestamp-value');
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// 初始化时更新一次时间戳
|
||||||
* 初始化时区列表
|
updateTimestamp(currentTimestampValue, this.showMilliseconds);
|
||||||
*/
|
|
||||||
function initTimeZoneList() {
|
|
||||||
const timezoneResultSelect = document.getElementById('timezone-result');
|
|
||||||
const timezoneInputSelect = document.getElementById('timezone-input');
|
|
||||||
|
|
||||||
// 获取本地时区在列表中的索引
|
this.setInterval(() => updateTimestamp(currentTimestampValue, this.showMilliseconds), 100);
|
||||||
const localTimeZoneIndex = timeZoneList.indexOf(localTimeZone);
|
|
||||||
|
|
||||||
for (let i = 0; i < timeZoneList.length; i++) {
|
const timezoneResultSelect = document.getElementById('timezone-result');
|
||||||
if (i === localTimeZoneIndex) {
|
const timezoneInputSelect = document.getElementById('timezone-input');
|
||||||
// 默认选中本地时区
|
|
||||||
timezoneResultSelect.add(new Option(timeZoneList[i], i, true, true));
|
// 获取本地时区在列表中的索引
|
||||||
timezoneInputSelect.add(new Option(timeZoneList[i], i, true, true));
|
const localTimeZoneIndex = timeZoneList.indexOf(localTimeZone);
|
||||||
} else {
|
|
||||||
timezoneResultSelect.add(new Option(timeZoneList[i], i));
|
for (let i = 0; i < timeZoneList.length; i++) {
|
||||||
timezoneInputSelect.add(new Option(timeZoneList[i], i));
|
if (i === localTimeZoneIndex) {
|
||||||
|
// 默认选中本地时区
|
||||||
|
timezoneResultSelect.add(new Option(timeZoneList[i], i, true, true));
|
||||||
|
timezoneInputSelect.add(new Option(timeZoneList[i], i, true, true));
|
||||||
|
} else {
|
||||||
|
timezoneResultSelect.add(new Option(timeZoneList[i], i));
|
||||||
|
timezoneInputSelect.add(new Option(timeZoneList[i], i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const timestampInput = document.getElementById('timestamp-input');
|
||||||
|
const dateInput = document.getElementById('datetime-input');
|
||||||
|
|
||||||
|
timestampInput.value = Date.now();
|
||||||
|
dateInput.value = new Date().toLocaleString('sv-SE');
|
||||||
|
|
||||||
|
this.bindBtnEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
bindBtnEvent() {
|
||||||
|
// 绑定时间戳相关按钮事件
|
||||||
|
this.bindEvent(
|
||||||
|
'toggle-unit-btn',
|
||||||
|
'click',
|
||||||
|
() => (this.showMilliseconds = handleToggleUnit(this.showMilliseconds))
|
||||||
|
);
|
||||||
|
|
||||||
|
// 绑定计时器相关按钮事件
|
||||||
|
this.bindEvent('stop-timer-btn', 'click', () => handleStopTimer(this.timestampInterval));
|
||||||
|
this.bindEvent(
|
||||||
|
'start-timer-btn',
|
||||||
|
'click',
|
||||||
|
() => (this.timestampInterval = handleStartTimer(this.timestampInterval, this.showMilliseconds))
|
||||||
|
);
|
||||||
|
// 绑定时间戳转换按钮事件
|
||||||
|
this.bindEvent('convert-timestamp-to-date-btn', 'click', handleConvertTimestamp);
|
||||||
|
// 绑定日期转换按钮事件
|
||||||
|
this.bindEvent('convert-date-to-timestamp-btn', 'click', handleConvertDateToTimestamp);
|
||||||
|
// 绑定复制时间戳按钮事件
|
||||||
|
this.bindEvent('copy-timestamp-btn', 'click', handleCopyTimestamp);
|
||||||
|
// 绑定关闭面板按钮事件
|
||||||
|
this.bindEvent('close-panel-btn', 'click', handleClosePanel);
|
||||||
|
// 绑定切换时区事件
|
||||||
|
this.bindEvent('timezone-result', 'change', handleTimezoneResult);
|
||||||
|
// 绑定输入时区事件
|
||||||
|
this.bindEvent('timezone-input', 'change', handleTimezoneInput);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
window.timestamp = Timestamp;
|
||||||
* 初始化时间戳和日期输入框
|
|
||||||
*/
|
|
||||||
function initTimestampAndDate() {
|
|
||||||
const timestampInput = document.getElementById('timestamp-input');
|
|
||||||
const dateInput = document.getElementById('datetime-input');
|
|
||||||
|
|
||||||
timestampInput.value = Date.now();
|
|
||||||
dateInput.value = new Date().toLocaleString('sv-SE');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 初始化时间戳显示
|
|
||||||
initTimestampDisplay();
|
|
||||||
|
|
||||||
// 绑定时间戳相关按钮事件
|
|
||||||
addEventListenerById(
|
|
||||||
'toggle-unit-btn',
|
|
||||||
'click',
|
|
||||||
() => (showMilliseconds = handleToggleUnit(showMilliseconds))
|
|
||||||
);
|
|
||||||
// 绑定计时器相关按钮事件
|
|
||||||
addEventListenerById('stop-timer-btn', 'click', () => handleStopTimer(timestampInterval));
|
|
||||||
addEventListenerById(
|
|
||||||
'start-timer-btn',
|
|
||||||
'click',
|
|
||||||
() => (timestampInterval = handleStartTimer(timestampInterval, showMilliseconds))
|
|
||||||
);
|
|
||||||
// 绑定时间戳转换按钮事件
|
|
||||||
addEventListenerById('convert-timestamp-to-date-btn', 'click', handleConvertTimestamp);
|
|
||||||
// 绑定日期转换按钮事件
|
|
||||||
addEventListenerById('convert-date-to-timestamp-btn', 'click', handleConvertDateToTimestamp);
|
|
||||||
// 绑定复制时间戳按钮事件
|
|
||||||
addEventListenerById('copy-timestamp-btn', 'click', handleCopyTimestamp);
|
|
||||||
// 绑定关闭面板按钮事件
|
|
||||||
addEventListenerById('close-panel-btn', 'click', handleClosePanel);
|
|
||||||
// 绑定切换时区事件
|
|
||||||
addEventListenerById('timezone-result', 'change', handleTimezoneResult);
|
|
||||||
// 绑定输入时区事件
|
|
||||||
addEventListenerById('timezone-input', 'change', handleTimezoneInput);
|
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
export class ScriptManager {
|
||||||
|
constructor() {
|
||||||
|
this._loadedClasses = new Map();
|
||||||
|
this.currentScriptEl = null;
|
||||||
|
this.currentModule = null;
|
||||||
|
this.currentName = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadScript({path, name, isModule = false, deps = []}) {
|
||||||
|
console.log('loadScript', name);
|
||||||
|
if (this._loadedClasses.has(name)) {
|
||||||
|
console.log(`Component ${name} loaded from cache`);
|
||||||
|
return this._loadedClasses.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const dep of deps) {
|
||||||
|
await this._appendScript({path: dep, isModule: false});
|
||||||
|
}
|
||||||
|
|
||||||
|
let componentReference = null;
|
||||||
|
|
||||||
|
console.log(isModule);
|
||||||
|
if (isModule) {
|
||||||
|
const module = await import(path);
|
||||||
|
this.currentModule = module;
|
||||||
|
componentReference = module;
|
||||||
|
} else {
|
||||||
|
await this._appendScript({path, isModule: false});
|
||||||
|
componentReference = window[name] || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (componentReference) {
|
||||||
|
this._loadedClasses.set(name, componentReference);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currentName = name;
|
||||||
|
return componentReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
async _appendScript({path, isModule}) {
|
||||||
|
const s = document.createElement('script');
|
||||||
|
s.src = path;
|
||||||
|
s.type = isModule ? 'module' : 'text/javascript';
|
||||||
|
s.async = false;
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
s.onload = () => {
|
||||||
|
this.currentScriptEl = s;
|
||||||
|
console.log(s);
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
s.onerror = () => {
|
||||||
|
reject(new Error(`Failed to load script: ${path}`));
|
||||||
|
}
|
||||||
|
document.body.appendChild(s);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async unloadScript() {
|
||||||
|
console.log('unloadScript');
|
||||||
|
if (this.currentScriptEl) {
|
||||||
|
try {
|
||||||
|
this.currentScriptEl.remove();
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currentModule = null;
|
||||||
|
this.currentName = null;
|
||||||
|
this.currentScriptEl = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getComponentInstance(name) {
|
||||||
|
const ComponentClassReference = this._loadedClasses.get(name);
|
||||||
|
const BaseClassForCheck = window.BaseComponent;
|
||||||
|
|
||||||
|
if (!ComponentClassReference) {
|
||||||
|
console.error('ComponentClassReference not found');
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const ComponentClass = ComponentClassReference.default
|
||||||
|
|| ComponentClassReference;
|
||||||
|
|
||||||
|
if (typeof ComponentClass === 'function') {
|
||||||
|
if (!(ComponentClass.prototype instanceof BaseClassForCheck)) {
|
||||||
|
console.error(`Component ${name} does not inherit BaseComponent.`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ComponentClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
console.error(`Component ${name} does not exist`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,7 +25,6 @@ export class TimerManager {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
setInterval(fn, delay, ...args) {
|
setInterval(fn, delay, ...args) {
|
||||||
console.log('setInterval in TimerManager');
|
|
||||||
const id = window.setInterval(fn, delay, ...args);
|
const id = window.setInterval(fn, delay, ...args);
|
||||||
this.timers.push(id);
|
this.timers.push(id);
|
||||||
return id;
|
return id;
|
||||||
@@ -52,4 +51,4 @@ export class TimerManager {
|
|||||||
});
|
});
|
||||||
this.timers = [];
|
this.timers = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+24
-23
@@ -1,7 +1,3 @@
|
|||||||
import { TimerManager } from '../utils/timerManager.js';
|
|
||||||
import { EventManager } from '../utils/eventManager.js';
|
|
||||||
import { ScriptManager } from '../utils/scriptManager.js';
|
|
||||||
|
|
||||||
class Router {
|
class Router {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.routes = {};
|
this.routes = {};
|
||||||
@@ -11,11 +7,11 @@ class Router {
|
|||||||
this.redirectRoute = null;
|
this.redirectRoute = null;
|
||||||
this.stackPages = true;
|
this.stackPages = true;
|
||||||
this.routerMap = [];
|
this.routerMap = [];
|
||||||
this.historyFlag = '';
|
|
||||||
this.history = [];
|
|
||||||
this.scriptManager = window.scriptManager;
|
this.scriptManager = window.scriptManager;
|
||||||
this.eventManager = window.eventManager;
|
|
||||||
this.timerManager = window.timerManager;
|
// 页面实例
|
||||||
|
this.currentinstance = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,7 +27,7 @@ class Router {
|
|||||||
// 监听路由变化
|
// 监听路由变化
|
||||||
window.addEventListener('hashchange', () => this.urlChange());
|
window.addEventListener('hashchange', () => this.urlChange());
|
||||||
window.addEventListener('load', () => this.urlChange());
|
window.addEventListener('load', () => this.urlChange());
|
||||||
window.lintTo = (path) => this.naviage(path);
|
window.lintTo = (path) => this.navigate(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
map() {
|
map() {
|
||||||
@@ -41,7 +37,7 @@ class Router {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const r of this.routerMap) {
|
for (const r of this.routerMap) {
|
||||||
if (r.name == 'redirect') this.redirectRoute = r.path;
|
if (r.name === 'redirect') this.redirectRoute = r.path;
|
||||||
this.routes[r.path] = r;
|
this.routes[r.path] = r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,7 +45,7 @@ class Router {
|
|||||||
/**
|
/**
|
||||||
* 导航
|
* 导航
|
||||||
*/
|
*/
|
||||||
naviage(path) {
|
navigate(path) {
|
||||||
window.location.hash = path;
|
window.location.hash = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,27 +63,26 @@ class Router {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const doChange = async () => {
|
const doChange = async () => {
|
||||||
this.timerManager.cleanAll();
|
if (this.currentinstance && typeof this.currentinstance.destroy === 'function') {
|
||||||
this.eventManager.removeAll();
|
console.log(`销毁旧组件${this.currentRoute.name}`);
|
||||||
|
this.currentinstance.destroy();
|
||||||
|
this.currentinstance = null;
|
||||||
|
}
|
||||||
|
|
||||||
const mount = document.getElementById(this.routerViewId);
|
const mount = document.getElementById(this.routerViewId);
|
||||||
if (!mount) {
|
if (!mount) {
|
||||||
console.error('挂载点不存在:', this.routerViewId);
|
console.error('挂载点不存在:', this.routerViewId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.stackPages) mount.innerHTML = '';
|
if (!this.stackPages) mount.innerHTML = '';
|
||||||
|
|
||||||
if (route.html) {
|
if (route.html) {
|
||||||
try {
|
try {
|
||||||
const html = await fetch(route.html).then((r) => r.text());
|
mount.innerHTML = await fetch(route.html).then((r) => r.text());
|
||||||
mount.innerHTML = html;
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
mount.innerHTML = `<h2>页面加载失败:${e.message}</h2>`;
|
mount.innerHTML = `<h2>页面加载失败:${e.message}</h2>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('当前组件:', route.script);
|
|
||||||
if (route.script) {
|
if (route.script) {
|
||||||
await this.scriptManager.loadScript({
|
await this.scriptManager.loadScript({
|
||||||
path: route.script,
|
path: route.script,
|
||||||
@@ -97,17 +92,23 @@ class Router {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('当前组件:', route.name);
|
const newInstance = await this.scriptManager.getComponentInstance(route.name);
|
||||||
await this.scriptManager.runInit(route.name);
|
console.log(`newInstance${newInstance}`);
|
||||||
|
if (newInstance) {
|
||||||
|
this.currentinstance = newInstance;
|
||||||
|
if (typeof newInstance.init === 'function') {
|
||||||
|
newInstance.init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.currentRoute = route;
|
this.currentRoute = route;
|
||||||
if (this.afterFun) this.afterFun(route);
|
if (this.afterFun) this.afterFun(route);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.beforeFun) {
|
if (this.beforeFun) {
|
||||||
this.beforeFun({ to: route, next: doChange });
|
this.beforeFun({to: route, next: doChange});
|
||||||
} else {
|
} else {
|
||||||
doChange();
|
doChange().then(r => console.log(r));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,4 +135,4 @@ class Router {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Router };
|
export {Router};
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
import {
|
import {convertDateToTimestamp, convertTimestampToDate, updateTimestamp,} from '../js/utils/timestampUtils.js';
|
||||||
updateTimestamp,
|
|
||||||
convertTimestampToDate,
|
|
||||||
convertDateToTimestamp,
|
|
||||||
} from '../utils/timestampUtils.js';
|
|
||||||
|
|
||||||
import { timeZoneList } from '../js/const/timezone.js';
|
import {timeZoneList} from '../js/const/timezone.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 切换单位按钮事件处理器
|
* 切换单位按钮事件处理器
|
||||||
|
|||||||
@@ -1,115 +0,0 @@
|
|||||||
export class ScriptManager {
|
|
||||||
constructor() {
|
|
||||||
this.currentScriptEl = null;
|
|
||||||
this.currentModule = null;
|
|
||||||
this.currentName = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
async loadScript({ path, name, isModule = false, deps = [] }) {
|
|
||||||
console.log('loadScript');
|
|
||||||
console.log({ path, name, isModule, deps })
|
|
||||||
await this.unloadScript();
|
|
||||||
|
|
||||||
for (const dep of deps) {
|
|
||||||
await this._appendScript({ path: dep, isModule: false });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isModule) {
|
|
||||||
const absPath = (path = '?t' + Date.now());
|
|
||||||
this.currentModule = await import(absPath);
|
|
||||||
this.currentScriptEl = null;
|
|
||||||
this.currentName = name;
|
|
||||||
return this.currentModule;
|
|
||||||
} else {
|
|
||||||
await this._appendScript({ path, isModule: false });
|
|
||||||
this.currentName = name;
|
|
||||||
return window[name] || null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async _appendScript({ path, isModule }) {
|
|
||||||
const s = document.createElement('script');
|
|
||||||
try {
|
|
||||||
s.src = path + '?t=' + Date.now();
|
|
||||||
s.type = isModule ? 'module' : 'text/javascript';
|
|
||||||
s.async = false;
|
|
||||||
s.onload = () => {
|
|
||||||
this.currentScriptEl = s;
|
|
||||||
};
|
|
||||||
} catch (e) {
|
|
||||||
throw new Error(`Failed to load script: ${path}`);
|
|
||||||
} finally {
|
|
||||||
document.body.appendChild(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async unloadScript() {
|
|
||||||
console.log('unloadScript');
|
|
||||||
try {
|
|
||||||
if (this.currentName && window[this.currentName]) {
|
|
||||||
const mod = window[this.currentName];
|
|
||||||
const unName = this._findUnmountName(mod);
|
|
||||||
if (unName && typeof mod[unName] === 'function') {
|
|
||||||
await mod[unName]();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.currentModule) {
|
|
||||||
const mod = this.currentModule;
|
|
||||||
const unName = this._findUnmountName(mod);
|
|
||||||
if (unName && typeof mod[unName] === 'function') {
|
|
||||||
await mod[unName]();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.currentScriptEl) {
|
|
||||||
try {
|
|
||||||
this.currentScriptEl.remove();
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.currentModule = null;
|
|
||||||
this.currentName = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
_findInitName(obj) {
|
|
||||||
if (!obj) return null;
|
|
||||||
const candidates = ['init', 'start', 'main'];
|
|
||||||
for (const c of candidates) {
|
|
||||||
if (typeof obj[c] === 'function') {
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
_findUnmountName(obj) {
|
|
||||||
if (!obj) return null;
|
|
||||||
const candidates = ['unmount', 'stop', 'destroy'];
|
|
||||||
for (const c of candidates) {
|
|
||||||
if (typeof obj[c] === 'function') {
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
async runInit(name) {
|
|
||||||
if (this.currentModule) {
|
|
||||||
const mod = this.currentModule;
|
|
||||||
const init = this._findInitName(mod);
|
|
||||||
if (init) return mod[init]();
|
|
||||||
return null;
|
|
||||||
} else if (name && window[name]) {
|
|
||||||
const mod = window[name];
|
|
||||||
const init = this._findInitName(mod);
|
|
||||||
if (init) return mod[init]();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user