refactor(widget): 简化前端配置并重构核心逻辑
移除前端配置中的 postSlug 和 avatarPrefix 参数,改为从后端接口获取 重构 CWDComments 核心类,自动推导 postSlug 等参数并异步加载服务端配置 更新文档和示例页面以反映配置变更
This commit is contained in:
@@ -17,21 +17,24 @@ export class CWDComments {
|
||||
* @param {Object} config - 配置对象
|
||||
* @param {string|HTMLElement} config.el - 挂载元素选择器或 DOM 元素
|
||||
* @param {string} config.apiBaseUrl - API 基础地址
|
||||
* @param {string} config.postSlug - 文章标识符
|
||||
* @param {string} config.postTitle - 文章标题(可选)
|
||||
* @param {string} config.postUrl - 文章 URL(可选)
|
||||
* @param {'light'|'dark'} config.theme - 主题
|
||||
* @param {number} config.pageSize - 每页评论数
|
||||
* @param {string} config.avatarPrefix - 头像服务前缀(可选,默认 https://gravatar.com/avatar/)
|
||||
* @param {string} config.adminEmail - 博主邮箱(可选,用于显示博主标识)
|
||||
* @param {string} config.adminBadge - 博主标识文字(可选,默认"博主")
|
||||
* @param {'light'|'dark'} [config.theme] - 主题(可选)
|
||||
* @param {number} [config.pageSize] - 每页评论数(可选,默认 20)
|
||||
*
|
||||
* 以下字段由组件自动推导或从后端读取,无需通过 config 传入:
|
||||
* - postSlug:window.location.origin + window.location.pathname
|
||||
* - postTitle:document.title 或 postSlug
|
||||
* - postUrl:window.location.href
|
||||
* - avatarPrefix/adminEmail/adminBadge:通过 /api/config/comments 接口获取
|
||||
*/
|
||||
constructor(config) {
|
||||
this.config = { ...config };
|
||||
if (!this.config.postTitle && typeof document !== 'undefined') {
|
||||
if (typeof window !== 'undefined') {
|
||||
this.config.postSlug = window.location.origin + window.location.pathname;
|
||||
}
|
||||
if (typeof document !== 'undefined') {
|
||||
this.config.postTitle = document.title || this.config.postSlug;
|
||||
}
|
||||
if (!this.config.postUrl && typeof window !== 'undefined') {
|
||||
if (typeof window !== 'undefined') {
|
||||
this.config.postUrl = window.location.href;
|
||||
}
|
||||
this.hostElement = this._resolveElement(config.el);
|
||||
@@ -64,6 +67,30 @@ export class CWDComments {
|
||||
return el;
|
||||
}
|
||||
|
||||
async _loadServerConfig() {
|
||||
try {
|
||||
const base = this.config.apiBaseUrl;
|
||||
if (!base) {
|
||||
return {};
|
||||
}
|
||||
const apiBaseUrl = base.replace(/\/$/, '');
|
||||
const res = await fetch(`${apiBaseUrl}/api/config/comments`);
|
||||
if (!res.ok) {
|
||||
return {};
|
||||
}
|
||||
const data = await res.json();
|
||||
return {
|
||||
adminEmail: data.adminEmail || '',
|
||||
adminBadge: data.adminBadge || '',
|
||||
adminEnabled: !!data.adminEnabled,
|
||||
avatarPrefix: data.avatarPrefix || ''
|
||||
};
|
||||
} catch (e) {
|
||||
console.warn('[CWDComments] 加载服务端评论配置失败:', e);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 挂载组件
|
||||
*/
|
||||
@@ -94,24 +121,35 @@ export class CWDComments {
|
||||
this.mountPoint.setAttribute('data-theme', this.config.theme);
|
||||
}
|
||||
|
||||
// 创建 API 客户端和 Store
|
||||
const api = createApiClient(this.config);
|
||||
this.store = createCommentStore(
|
||||
this.config,
|
||||
api.fetchComments.bind(api),
|
||||
api.submitComment.bind(api)
|
||||
);
|
||||
(async () => {
|
||||
const serverConfig = await this._loadServerConfig();
|
||||
if (!this._mounted) {
|
||||
return;
|
||||
}
|
||||
if (serverConfig.avatarPrefix) {
|
||||
this.config.avatarPrefix = serverConfig.avatarPrefix;
|
||||
}
|
||||
if (serverConfig.adminEnabled && serverConfig.adminEmail) {
|
||||
this.config.adminEmail = serverConfig.adminEmail;
|
||||
}
|
||||
if (serverConfig.adminEnabled && serverConfig.adminBadge) {
|
||||
this.config.adminBadge = serverConfig.adminBadge;
|
||||
}
|
||||
|
||||
// 订阅状态变化
|
||||
this.unsubscribe = this.store.store.subscribe((state) => {
|
||||
this._onStateChange(state);
|
||||
});
|
||||
const api = createApiClient(this.config);
|
||||
this.store = createCommentStore(
|
||||
this.config,
|
||||
api.fetchComments.bind(api),
|
||||
api.submitComment.bind(api)
|
||||
);
|
||||
|
||||
// 渲染组件
|
||||
this._render();
|
||||
this.unsubscribe = this.store.store.subscribe((state) => {
|
||||
this._onStateChange(state);
|
||||
});
|
||||
|
||||
// 加载评论
|
||||
this.store.loadComments();
|
||||
this._render();
|
||||
this.store.loadComments();
|
||||
})();
|
||||
|
||||
this._mounted = true;
|
||||
}
|
||||
@@ -339,35 +377,43 @@ export class CWDComments {
|
||||
const prevConfig = { ...this.config };
|
||||
|
||||
Object.assign(this.config, newConfig);
|
||||
if (typeof window !== 'undefined') {
|
||||
this.config.postSlug = window.location.origin + window.location.pathname;
|
||||
}
|
||||
if (typeof document !== 'undefined') {
|
||||
this.config.postTitle = document.title || this.config.postSlug;
|
||||
}
|
||||
if (typeof window !== 'undefined') {
|
||||
this.config.postUrl = window.location.href;
|
||||
}
|
||||
|
||||
// 更新主题
|
||||
if (newConfig.theme && this.mountPoint) {
|
||||
this.mountPoint.setAttribute('data-theme', newConfig.theme);
|
||||
}
|
||||
|
||||
// 如果 postSlug 变化,重新加载评论
|
||||
if (newConfig.postSlug && newConfig.postSlug !== prevConfig.postSlug) {
|
||||
// 重新创建 API 客户端和 Store
|
||||
const shouldReload =
|
||||
this.config.apiBaseUrl !== prevConfig.apiBaseUrl ||
|
||||
this.config.pageSize !== prevConfig.pageSize ||
|
||||
this.config.postSlug !== prevConfig.postSlug;
|
||||
|
||||
if (shouldReload) {
|
||||
const api = createApiClient(this.config);
|
||||
|
||||
// 取消旧订阅
|
||||
if (this.unsubscribe) {
|
||||
this.unsubscribe();
|
||||
}
|
||||
|
||||
// 创建新 store
|
||||
this.store = createCommentStore(
|
||||
this.config,
|
||||
api.fetchComments.bind(api),
|
||||
api.submitComment.bind(api)
|
||||
);
|
||||
|
||||
// 重新订阅
|
||||
this.unsubscribe = this.store.store.subscribe((state) => {
|
||||
this._onStateChange(state);
|
||||
});
|
||||
|
||||
// 加载评论
|
||||
this.store.loadComments();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ const STORAGE_KEY = 'cwd-dev-config';
|
||||
const DEFAULT_CONFIG = {
|
||||
el: '#comments',
|
||||
apiBaseUrl: 'http://localhost:8788',
|
||||
postSlug: window.location.origin + window.location.pathname,
|
||||
theme: 'light', // 默认 light / dark
|
||||
};
|
||||
|
||||
@@ -48,12 +47,10 @@ function saveConfigToStorage(config) {
|
||||
*/
|
||||
function populateInputs(config) {
|
||||
const apiBaseUrlInput = document.getElementById('apiBaseUrl');
|
||||
const postSlugInput = document.getElementById('postSlug');
|
||||
const themeSelect = document.getElementById('theme');
|
||||
const avatarPrefixInput = document.getElementById('avatarPrefix');
|
||||
|
||||
if (apiBaseUrlInput) apiBaseUrlInput.value = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl;
|
||||
if (postSlugInput) postSlugInput.value = config.postSlug || DEFAULT_CONFIG.postSlug;
|
||||
if (themeSelect) themeSelect.value = config.theme || DEFAULT_CONFIG.theme;
|
||||
if (avatarPrefixInput) avatarPrefixInput.value = config.avatarPrefix || DEFAULT_CONFIG.avatarPrefix;
|
||||
}
|
||||
@@ -63,29 +60,8 @@ function populateInputs(config) {
|
||||
*/
|
||||
function getConfigFromInputs() {
|
||||
const apiBaseUrl = document.getElementById('apiBaseUrl')?.value || DEFAULT_CONFIG.apiBaseUrl;
|
||||
const postSlug = document.getElementById('postSlug')?.value || DEFAULT_CONFIG.postSlug;
|
||||
const theme = document.getElementById('theme')?.value || DEFAULT_CONFIG.theme;
|
||||
const avatarPrefix = document.getElementById('avatarPrefix')?.value || DEFAULT_CONFIG.avatarPrefix;
|
||||
return { apiBaseUrl, postSlug, theme, avatarPrefix };
|
||||
}
|
||||
|
||||
async function loadServerCommentConfig(apiBaseUrl) {
|
||||
try {
|
||||
const res = await fetch(`${apiBaseUrl}/api/config/comments`);
|
||||
if (!res.ok) {
|
||||
return {};
|
||||
}
|
||||
const data = await res.json();
|
||||
return {
|
||||
adminEmail: data.adminEmail || '',
|
||||
adminBadge: data.adminBadge || '',
|
||||
adminEnabled: !!data.adminEnabled,
|
||||
avatarPrefix: data.avatarPrefix || '',
|
||||
};
|
||||
} catch (e) {
|
||||
console.warn('[CWDComments] 加载服务端评论配置失败:', e);
|
||||
return {};
|
||||
}
|
||||
return { apiBaseUrl, theme };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,21 +87,11 @@ async function initWidget() {
|
||||
|
||||
// 创建新实例
|
||||
try {
|
||||
const serverConfig = await loadServerCommentConfig(config.apiBaseUrl);
|
||||
|
||||
widgetInstance = new CWDComments({
|
||||
el: '#comments',
|
||||
apiBaseUrl: config.apiBaseUrl,
|
||||
postSlug: config.postSlug,
|
||||
theme: config.theme,
|
||||
avatarPrefix: serverConfig.avatarPrefix || config.avatarPrefix,
|
||||
pageSize: 20,
|
||||
...(serverConfig.adminEnabled && serverConfig.adminEmail
|
||||
? { adminEmail: serverConfig.adminEmail }
|
||||
: {}),
|
||||
...(serverConfig.adminEnabled && serverConfig.adminBadge
|
||||
? { adminBadge: serverConfig.adminBadge }
|
||||
: {}),
|
||||
});
|
||||
widgetInstance.mount();
|
||||
console.log('[CWDComments] Widget 初始化成功', config);
|
||||
@@ -193,7 +159,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
// 监听输入框变化,实时保存
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const inputs = ['apiBaseUrl', 'postSlug', 'theme', 'avatarPrefix'];
|
||||
const inputs = ['apiBaseUrl', 'theme'];
|
||||
inputs.forEach((id) => {
|
||||
const element = document.getElementById(id);
|
||||
if (element) {
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
* <script>
|
||||
* new CWDComments({
|
||||
* el: '#comments',
|
||||
* apiBaseUrl: 'https://api.example.com',
|
||||
* postSlug: 'my-post'
|
||||
* apiBaseUrl: 'https://api.example.com'
|
||||
* }).mount();
|
||||
* </script>
|
||||
* ```
|
||||
|
||||
Reference in New Issue
Block a user