LX UI - 灵曦平台 AI 组件库通用工具函数库
bash
npm install @will1123/lx-ui-utils
或
yarn add @will1123/lx-ui-utils
或
pnpm add @will1123/lx-ui-utils
`
使用方法
$3
`typescript
import { sse, extractThinking, createMarkdownRender, bindMarkdownCodeBoxEvents } from '@will1123/lx-ui-utils'
`
$3
`typescript
import { sse } from '@will1123/lx-ui-utils'
import { extractThinking } from '@will1123/lx-ui-utils'
import {
createMarkdownRender,
getMarkdownCodeTheme,
setMarkdownCodeTheme,
toggleMarkdownCodeTheme,
updateMarkdownCodeBlocksTheme,
bindMarkdownCodeBoxEvents
} from '@will1123/lx-ui-utils'
import { copyToClipboard, isDom } from '@will1123/lx-ui-utils'
`
API 文档
$3
基于 @microsoft/fetch-event-source 封装的 SSE 请求,支持流式响应、自动重连和页面可见性控制。
#### 类型定义
`typescript
interface SSEConfig {
url: string // 请求 URL
method?: 'GET' | 'POST' // 请求方法,默认 POST
headers?: Record // 请求头
body?: object // 请求体(对象类型)
signal?: AbortSignal // 用于取消请求
token?: string // 认证 Token
openWhenHidden?: boolean // 页面隐藏时是否保持连接,默认 true
}
interface SSEHandlers {
onOpen?: (response: Response) => void | Promise // 连接打开时触发
onMessage?: (message: EventSourceMessage) => void // 接收到消息时触发
onClose?: () => void // 连接关闭时触发
onError?: (error: Error) => void // 发生错误时触发
}
`
#### 使用示例
`typescript
import { sse } from '@will1123/lx-ui-utils'
// 基础用法(默认 POST)
await sse({
url: 'https://api.example.com/stream',
body: { prompt: '你好' }
}, {
onMessage(msg) {
console.log('收到消息:', msg)
}
})
// 使用 Token 认证
await sse({
url: 'https://api.example.com/stream',
token: 'Bearer your-token-here',
body: { prompt: '你好' }
}, {
onOpen(response) {
console.log('连接已打开,状态:', response.status)
},
onMessage(msg) {
// msg 是原始对象,包含 data、event、id 等字段
console.log('收到消息:', msg.data)
},
onClose() {
console.log('连接已关闭')
},
onError(err) {
console.error('连接错误:', err)
}
})
// GET 请求
await sse({
url: 'https://api.example.com/stream',
method: 'GET'
}, {
onMessage(msg) {
console.log(msg.data)
}
})
// 取消请求
const ctrl = new AbortController()
await sse({
url: 'https://api.example.com/stream',
signal: ctrl.signal
}, {
onMessage(msg) {
console.log(msg.data)
}
})
// 取消请求
ctrl.abort()
`
$3
从 AI 响应中提取深度思考内容。
#### 类型定义
`typescript
interface ThinkingExtractConfig {
tagName?: string // 思考标签名称,默认 'think'
mode?: 'full' | 'end-tag-only' // 解析模式
}
interface ThinkingResult {
thinking: string // 提取的思考内容
content: string // 实际回答内容
}
`
#### 使用示例
`typescript
import { extractThinking } from '@will1123/lx-ui-utils'
// 模式 1:完整标签(默认)
const text1 = 这是思考内容
const result1 = extractThinking(text1)
console.log(result1.thinking) // "这是思考内容"
console.log(result1.content) // "这是回答内容"
// 模式 2:仅结束标签
const text2 = '这是思考内容这是回答内容'
const result2 = extractThinking(text2, { mode: 'end-tag-only' })
console.log(result2.thinking) // "这是思考内容"
console.log(result2.content) // "这是回答内容"
// 模式 3:没有标签
const text3 = '全部是正文内容'
const result3 = extractThinking(text3)
console.log(result3.thinking) // ""
console.log(result3.content) // "全部是正文内容"
`
$3
基于 Marked.js 的增强 Markdown 渲染器,支持代码高亮、主题切换、自定义样式和 KaTeX 数学公式。
#### 特性
- ✅ 链接增强 - 自动添加 target="_blank"
- ✅ 表格优化 - 自动包装在可滚动容器中
- ✅ 代码增强 - 显示语言标签、复制按钮、主题切换
- ✅ 主题系统 - 支持 dark/light 主题切换,基于 localStorage
- ✅ 代码高亮 - 集成 highlight.js,支持 190+ 语言
- ✅ GFM 支持 - 表格、任务列表、删除线等
- ✅ 类名前缀 - 所有生成的类名带 lx-ui 前缀,避免冲突
- ✅ KaTeX 公式 - 支持数学公式渲染(可选)
#### 类型定义
`typescript
type CodeTheme = 'dark' | 'light'
interface CreateMarkdownRenderConfig {
codeBoxToolEnable?: boolean // 代码块工具栏是否启用,默认 true
katexEnable?: boolean // 是否启用 KaTeX 公式支持,默认 true
katexOptions?: KatexOptions // KaTeX 配置选项
}
`
#### 使用步骤
##### 1. 引入代码高亮样式(必需)
选择一个 highlight.js 主题并引入:
`javascript
// 暗色主题(推荐)
import 'highlight.js/styles/base16/outrun-dark.min.css'
import 'highlight.js/styles/atom-one-dark.min.css'
import 'highlight.js/styles/github-dark.min.css'
// 亮色主题
import 'highlight.js/styles/github.min.css'
import 'highlight.js/styles/base16/solarflare-light.min.css'
// 查看所有主题:https://highlightjs.org/examples
// 主题文件位置:node_modules/highlight.js/styles/
`
##### 2. 引入 KaTeX 样式(必需,默认启用公式支持)
`javascript
// KaTeX 样式(必需,默认启用公式支持)
import 'katex/dist/katex.min.css'
`
##### 3. 创建渲染器
`typescript
import { createMarkdownRender } from '@will1123/lx-ui-utils'
// 创建渲染器(默认启用工具栏和 KaTeX 公式支持)
const renderer = createMarkdownRender({
codeBoxToolEnable: true,
katexEnable: true,
katexOptions: {
throwOnError: false,
strict: false
}
})
// 创建渲染器(禁用工具栏)
const simpleRenderer = createMarkdownRender({
codeBoxToolEnable: false
})
// 创建渲染器(禁用公式支持)
const noKatexRenderer = createMarkdownRender({
codeBoxToolEnable: true,
katexEnable: false
})
`
##### 4. 渲染 Markdown
`typescript
const markdown = # 标题
\\javascript
function greet(name) {
console.log(\Hello, \${name}!\)
return true
}
\\\
// 渲染(异步)
const html = await renderer.parse(markdown)
console.log(html)
`
#### KaTeX 公式语法
支持两种公式语法:
行内公式 - 使用单个 $ 包裹:
`markdown
爱因斯坦方程:$E = mc^2$
`
块级公式 - 使用双个 $$ 包裹:
`markdown
$$
\\int_{-\\infty}^{\\infty} e^{-x^2} dx = \\sqrt{\\pi}
$$
`
注意事项:
- 行内公式不能包含换行符
- 块级公式可以跨多行
- 如果公式渲染失败,会保留原始公式文本
- KaTeX 公式支持默认启用,无需配置即可使用
- 如需禁用公式支持,设置 katexEnable: false
#### 生成的 HTML 结构 - KaTeX 公式
行内公式:
`html
`
块级公式:
`html
`
#### 主题管理
`typescript
import { getMarkdownCodeTheme, setMarkdownCodeTheme, toggleMarkdownCodeTheme, updateMarkdownCodeBlocksTheme } from '@will1123/lx-ui-utils'
// 获取当前主题
const theme = getMarkdownCodeTheme() // 'dark' | 'light'
// 设置主题
setMarkdownCodeTheme('light')
// 切换主题(只更新 localStorage,不更新 DOM)
const newTheme = toggleMarkdownCodeTheme()
// 更新 DOM 中所有代码块的主题(方式 1:只传主题)
updateMarkdownCodeBlocksTheme('dark')
// 更新指定容器内代码块的主题(方式 2:传容器和主题)
const container = document.querySelector('#markdown-container')
updateMarkdownCodeBlocksTheme(container, 'light')
`
注意:
- toggleMarkdownCodeTheme() 只切换 localStorage 中的主题,不会更新 DOM
- updateMarkdownCodeBlocksTheme() 用于更新 DOM 中代码块的 data-theme 属性
- bindMarkdownCodeBoxEvents() 内部会自动调用这两个函数
- updateMarkdownCodeBlocksTheme() 支持两种调用方式:
- 只传主题字符串:updateMarkdownCodeBlocksTheme('dark') - 更新 document.body 中的所有代码块
- 传容器和主题:updateMarkdownCodeBlocksTheme(container, 'light') - 更新指定容器内的代码块
#### 绑定代码块工具栏事件(推荐)
bindMarkdownCodeBoxEvents 用于处理代码块工具栏的交互事件(复制、主题切换、折叠)。
##### 类型定义
`typescript
interface CodeBoxEventsConfig {
onCopySuccess?: (text: string) => void // 复制成功回调
onCopyError?: (error: Error) => void // 复制失败回调
onThemeChange?: (theme: CodeTheme) => void // 主题切换回调
}
// 函数重载
function bindMarkdownCodeBoxEvents(): () => void
function bindMarkdownCodeBoxEvents(config: CodeBoxEventsConfig): () => void
function bindMarkdownCodeBoxEvents(container: HTMLElement | Document): () => void
function bindMarkdownCodeBoxEvents(
container: HTMLElement | Document,
config: CodeBoxEventsConfig
): () => void
`
##### 使用步骤
1. 不传参数(默认 document.body)
`typescript
import { bindMarkdownCodeBoxEvents } from '@will1123/lx-ui-utils'
const unbind = bindMarkdownCodeBoxEvents()
// 组件销毁时解绑
onUnmounted(() => unbind())
`
2. 只传 config(默认 document.body)
`typescript
const unbind = bindMarkdownCodeBoxEvents({
onCopySuccess: (text) => console.log('已复制:', text),
onCopyError: (error) => console.error('复制失败:', error),
onThemeChange: (theme) => console.log('主题切换为:', theme)
})
`
3. 只传 container(使用默认配置)
`typescript
const container = document.querySelector('#markdown-container')
const unbind = bindMarkdownCodeBoxEvents(container)
`
4. 传 container 和 config
`typescript
const container = document.querySelector('#markdown-container')
const unbind = bindMarkdownCodeBoxEvents(container, {
onCopySuccess: (text) => console.log('已复制:', text),
onThemeChange: (theme) => console.log('主题切换为:', theme)
})
`
5. Vue 组件完整示例
`vue
`
##### 功能说明
1. 复制按钮
- 点击复制按钮自动复制代码到剪贴板
- 内部使用 copyToClipboard 工具函数
- 触发 onCopySuccess 或 onCopyError 回调
2. 主题切换按钮
- 点击主题按钮切换 dark/light 主题
- 自动执行两步操作:
1. 调用 toggleMarkdownCodeTheme() 切换 localStorage 中的主题
2. 调用 updateMarkdownCodeBlocksTheme() 更新指定容器内所有代码块的 data-theme 属性
- 无需重新渲染 - 切换即时生效,性能更好
- 触发 onThemeChange 回调
- 容器隔离 - 只更新绑定容器内的代码块,不影响其他区域
3. 折叠按钮
- 点击折叠按钮展开/收起代码块
- 纯前端操作,无需重新渲染
##### 注意事项
- 事件委托:使用事件委托,动态添加的代码块也会生效
- 清理函数:返回的清理函数必须在组件销毁时调用,避免内存泄漏
- 职责分离:
- toggleMarkdownCodeTheme() - 只负责切换 localStorage 中的主题
- updateMarkdownCodeBlocksTheme() - 只负责更新 DOM 中代码块的 data-theme
- bindMarkdownCodeBoxEvents() - 内部自动调用这两个函数完成完整流程
- 函数重载:bindMarkdownCodeBoxEvents() 支持多种调用方式(不传参数、只传 config、只传 container、两个都传)
- 容器隔离:指定 container 后,主题切换只影响该容器内的代码块,适合多实例场景
- 兼容性:复制功能支持所有现代浏览器和 IE11+
#### 生成的 HTML 结构
链接 - 自动添加 target="_blank":
`html
链接文本
`
表格 - 包装在可滚动容器中:
`html
...
`
代码块(启用工具栏):
`html
javascript
...
`
代码块(禁用工具栏):
`html
javascript
...
`
#### CSS 样式指南
你需要自行实现以下 CSS 类的样式(所有类名都带 lx-ui 前缀以避免冲突):
`css
/ 表格容器 /
.lx-ui-table-wrapper {
overflow-x: auto;
}
.lx-ui-table-box {
/ 表格内层容器 /
}
/ 代码块容器 /
.lx-ui-code-box-wrapper {
margin-bottom: 20px;
}
.lx-ui-code-box {
border-radius: 4px;
overflow: hidden;
}
/ 代码主题 /
.lx-ui-code-box[data-theme="dark"] {
background: #1e1e1e;
color: #d4d4d4;
}
.lx-ui-code-box[data-theme="light"] {
background: #f5f5f5;
color: #333;
}
/ 代码块工具栏 /
.lx-ui-code-box-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 12px;
}
.lx-ui-code-box-header-left,
.lx-ui-code-box-header-right {
display: flex;
align-items: center;
gap: 8px;
}
.lx-ui-code-language {
font-size: 12px;
font-weight: 500;
}
.lx-ui-code-box-content {
padding: 12px;
overflow-x: auto;
}
/ 工具栏图标 /
.lx-ui-icon-copy,
.lx-ui-icon-theme,
.lx-ui-icon-fold {
cursor: pointer;
opacity: 0.6;
transition: opacity 0.2s;
}
.lx-ui-icon-copy:hover,
.lx-ui-icon-theme:hover,
.lx-ui-icon-fold:hover {
opacity: 1;
}
/ KaTeX 公式样式(默认启用公式支持) /
.lx-ui-katex-inline {
padding: 0 4px;
font-size: 1.05em;
}
.lx-ui-katex-block {
margin: 20px 0;
padding: 15px;
overflow-x: auto;
text-align: center;
background: #f5f7fa;
border-radius: 4px;
}
`
#### 完整示例
`vue
`
核心优势
$3
- ✅ 简洁 API - 默认 POST 请求,内置 Token 认证支持
- ✅ 页面可见性 - 自动处理页面隐藏/显示(Page Visibility API)
- ✅ 自动解析 - 无需手动解析 SSE 消息格式
- ✅ 生产级 - 基于 Microsoft 维护的 @microsoft/fetch-event-source
- ✅ 代码精简 - 相比手动实现减少 70% 代码量
$3
- ✅ 灵活解析 - 支持完整标签和仅结束标签两种模式
- ✅ 类型安全 - 完整的 TypeScript 类型定义
- ✅ 简洁 API - 一个函数完成所有解析逻辑
$3
- ✅ 增强功能 - 链接自动新窗口、表格可滚动、代码块工具栏
- ✅ 主题系统 - dark/light 主题切换,基于 localStorage 持久化
- ✅ 代码高亮 - 集成 highlight.js,支持 190+ 语言
- ✅ 标准兼容 - 基于 Marked.js,99% CommonMark 兼容
- ✅ GFM 支持 - 表格、任务列表、删除线等
- ✅ 类名安全 - 所有生成的类名带 lx-ui 前缀,避免冲突
- ✅ 按需样式 - 不提供 CSS 文件,用户自行实现样式
- ✅ KaTeX 公式 - 支持 LaTeX 数学公式渲染(可选)
$3
通用工具函数,可在任何场景使用。
#### 复制到剪贴板
copyToClipboard 是一个通用的复制文本到剪贴板的工具函数。
##### 类型定义
`typescript
function copyToClipboard(text: string): Promise
`
##### 使用示例
`typescript
import { copyToClipboard } from '@will1123/lx-ui-utils'
// 基础用法
const success = await copyToClipboard('Hello World')
if (success) {
console.log('复制成功')
} else {
console.log('复制失败')
}
// 复制代码
const code = 'console.log("Hello World")'
await copyToClipboard(code)
// 复制 HTML 内容
const html = 'Hello'
await copyToClipboard(html)
`
##### 特性
- ✅ 现代 API - 优先使用 Clipboard API
- ✅ 自动降级 - 不支持时自动降级到 document.execCommand
- ✅ SSR 安全 - 服务端渲染环境自动返回 false
- ✅ 返回值 - 返回 Promise,成功返回 true,失败返回 false
- ✅ 兼容性好 - 支持所有主流浏览器(包括 IE11+)
- ✅ 通用性 - 可在任何场景使用,不限于 Markdown
#### 判断 DOM 元素
isDom 用于判断值是否为 DOM 元素(HTMLElement 或 Document)。
##### 类型定义
`typescript
function isDom(val: unknown): val is HTMLElement | Document
`
##### 使用示例
`typescript
import { isDom } from '@will1123/lx-ui-utils'
// 判断各种值
isDom(document.body) // true
isDom(document) // true
isDom(document.querySelector('div')) // true (如果找到元素)
isDom({}) // false
isDom('div') // false
isDom(null) // false
isDom(undefined) // false
isDom(123) // false
// 在函数重载中使用
function processInput(input: unknown) {
if (isDom(input)) {
// input 在这里被识别为 HTMLElement | Document
input.addEventListener('click', handler)
} else {
console.log('不是 DOM 元素')
}
}
`
##### 特性
- ✅ 类型守卫 - TypeScript 类型守卫,可缩小类型范围
- ✅ 精确判断 - 使用 instanceof 判断,支持所有 DOM 元素
- ✅ SSR 安全 - 服务端渲染环境也能正常工作
- ✅ 辅助开发 - 常用于函数重载、参数验证等场景
构建
`bash
安装依赖
yarn install
构建 utils 包
yarn workspace @will1123/lx-ui-utils build
``