Files
cwd/docs/guide/frontend-config.md
anghunk d060cf20da docs: 更新文档中的版本检查响应与前端CDN链接
- 将部署成功时的版本检查响应从纯文本改为JSON格式,包含版本号和部署成功信息
- 更新前端配置指南,推荐使用版本锁定的CDN链接替代最新版本链接
- 统一修改所有示例代码中的CDN引用,添加版本控制说明
- 调整表格格式以保持一致性
2026-01-31 12:24:01 +08:00

182 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 前端配置
**这里仅提供一套开箱即用的方案,如果是个人开发者可以根据 [API 文档](../api/overview) 自行编写前端评论组件。**
组件源码目录:`/docs/widget`
## 组件特性
CWD 评论组件采用 **Shadow DOM** 技术构建,基于独立根节点渲染,具备以下优势:
- **样式隔离**:组件样式完全独立,不会与宿主页面的样式产生冲突
- **DOM 隔离**:组件内部 DOM 结构与外部页面完全隔离,互不干扰
- **即插即用**:无需担心现有网站的样式框架(如 Bootstrap、Tailwind 等)影响组件显示
- **自定义样式**:通过 `customCssUrl` 参数注入自定义样式表,灵活调整外观
## 评论组件初始化
在初始化 `CWDComments` 实例时,可以传入以下配置参数:
建议使用 cdn 锁版本,防止组件版本升级导致的兼容性问题,更新时只需要修改版本号即可。
```html
<div id="comments"></div>
<script src="https://unpkg.com/cwd-widget@0.0.x/dist/cwd.js"></script>
<!-- <script src="https://cdn.jsdelivr.net/npm/cwd-widget@0.0.x/dist/cwd.js"></script> -->
<script>
const comments = new CWDComments({
el: '#comments',
apiBaseUrl: 'https://your-api.example.com', // 换成你的 API 地址
});
comments.mount();
</script>
```
**cdn 链接(推荐使用)**
```
https://unpkg.com/cwd-widget@0.0.x/dist/cwd.js
https://cdn.jsdelivr.net/npm/cwd-widget@0.0.x/dist/cwd.js
```
*最新版本链接(不建议使用)*
```
https://cwd.js.org/cwd.js
```
### 参数说明
| 参数 | 类型 | 必填 | 默认值 | 说明 |
| -------------- | ----------------------- | ---- | --------- | ---------------------------------------- |
| `el` | `string \| HTMLElement` | 是 | - | 挂载元素选择器或 DOM 元素 |
| `apiBaseUrl` | `string` | 是 | - | API 基础地址 |
| `theme` | `'light' \| 'dark'` | 否 | `'light'` | 主题模式 |
| `pageSize` | `number` | 否 | `20` | 每页显示评论数 |
| `customCssUrl` | `string` | 否 | - | 自定义样式表 URL追加到 Shadow DOM 底部 |
头像前缀、博主邮箱和标识等信息由后端接口 `/api/config/comments` 提供,无需在前端进行配置。
`/admin/settings/comments` 中配置了“评论博主邮箱”(`adminEmail`)时:
- 前台组件会将该邮箱视为“管理员邮箱”;
- 使用该邮箱发表评论时,会在邮箱输入框失焦后触发“管理员身份验证”弹窗;
- 验证通过后,会在浏览器本地保存一次管理员密钥(仅用于本机后续请求携带 `adminToken`
- 后端会在 `/api/comments` 中校验此密钥,确保管理员身份的评论需要额外验证;
- 后端邮件通知会将新评论提醒发送到该邮箱,无需再单独配置通知收件人。
## 实例方法
| 方法 | 说明 |
| ---------------------- | ------------------------------ |
| `mount()` | 挂载组件到 DOM |
| `unmount()` | 卸载组件 |
| `updateConfig(config)` | 更新配置(支持动态切换主题等) |
| `getConfig()` | 获取当前配置 |
**使用示例**
```javascript
// 动态切换主题
comments.updateConfig({ theme: 'dark' });
// 配置自定义样式(会以 <link> 形式注入到 Shadow DOM 底部)
comments.updateConfig({
customCssUrl: 'https://your-cdn.example.com/cwd-custom.css',
});
```
## 其他框架示例
如果你有其他博客框架的需求,欢迎在下方评论区留言。
### HTML
此方法适用于绝大多数博客框架,包括 Hexo、Hugo、Jekyll、WordPress 等。
```html
<div id="comments"></div>
<script src="https://unpkg.com/cwd-widget@0.0.x/dist/cwd.js"></script>
<!-- 实例调用 -->
<script>
const comments = new CWDComments({
el: '#comments',
apiBaseUrl: 'https://your-api.example.com', // 换成你的 API 地址
});
comments.mount();
// 或者
// document.addEventListener('DOMContentLoaded', () => {
// const comments = new window.CWDComments({
// el: '#comments',
// apiBaseUrl: 'https://your-api.example.com',
// });
// comments.mount();
// });
</script>
```
### Astro
```astro
<div id="comments"></div>
<script src="https://unpkg.com/cwd-widget@0.0.x/dist/cwd.js" is:inline></script>
<script is:inline>
document.addEventListener('DOMContentLoaded', () => {
const comments = new window.CWDComments({
el: '#comments',
apiBaseUrl: 'https://your-api.example.com', // 换成你的 API 地址
});
comments.mount();
});
</script>
```
### Vue
在 Vue 单文件组件里封装。
`CommentsWidget.vue`:
```html
<template>
<div ref="comments"></div>
</template>
<script setup>
import { onMounted, onBeforeUnmount, ref } from 'vue';
const comments = ref(null);
let instance = null;
onMounted(async () => {
if (!window.CWDComments) {
await loadScript('https://unpkg.com/cwd-widget@0.0.x/dist/cwd.js');
}
instance = new window.CWDComments({
el: comments.value,
apiBaseUrl: 'https://your-api.example.com', // 换成你的 API 地址
});
instance.mount();
});
onBeforeUnmount(() => {
instance = null;
});
function loadScript(src) {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = src;
script.async = true;
script.onload = () => resolve();
script.onerror = (e) => reject(e);
document.head.appendChild(script);
});
}
</script>
```