开发与对接文档
面向 PHP / ThinkPHP / 传统 CMS 的接入说明。翊象 UI 不依赖构建工具,也不需要 jQuery; 引入核心 CSS / JS 资源即可获得完整的设计系统、三态主题、弹窗、组件与全站免刷新能力。
快速接入
把 css/、js/、assets/ 拷贝到项目静态目录,在页面 <head> 中按顺序引入:
<link rel="stylesheet" href="css/yixiang.core.css">
<link rel="stylesheet" href="css/yixiang.layout.css">
<link rel="stylesheet" href="css/yixiang.components.css">
<link rel="stylesheet" href="css/yixiang.modal.css"> <!-- 需要弹窗时 -->
<link rel="stylesheet" href="css/yixiang.mobile.css">
<link rel="stylesheet" href="css/yixiang.ajax.css"> <!-- 需要加载动画时 -->
<script src="js/yixiang.modal.js"></script> <!-- 需要弹窗时 -->
<script src="js/yixiang.components.js"></script>
<script src="js/yixiang.ajax.js"></script> <!-- 需要 AJAX / PJAX 时 -->
js/yixiang.pjax.js 仅作兼容保留,不要与新引擎同时加载。
资源与目录
| 文件 | 作用 | 是否必需 |
|---|---|---|
yixiang.core.css | 设计令牌(CSS 变量)、重置、排版、深浅色变量 | 是 |
yixiang.layout.css | 前台/后台布局、页头、侧栏、栅格工具类、主题切换器 | 是 |
yixiang.components.css | 按钮、卡片、表单、标签、表格、下拉、Tabs、图表、待办 | 是 |
yixiang.mobile.css | ≤1024 / 768 / 480 响应式规则 | 是 |
yixiang.modal.css | YixiangModal 弹窗样式 | 按需 |
yixiang.ajax.css | 顶部进度条与可选全屏 Loading | 按需 |
yixiang.components.js | 主题、侧栏抽屉、下拉、Tabs、声明式 Modal | 是 |
yixiang.modal.js | YixiangModal 独立弹窗引擎 | 按需 |
yixiang.ajax.js | 全局 AJAX、PJAX、加载动画(可开关) | 按需 |
页面骨架
前台页面
页头必须放在 #pjax-container 内部,这样从首页透明头部切换到内容页实心头部时,头部会随页面一起替换。
<div class="yx-app">
<div id="pjax-container" style="flex: 1; display: flex; flex-direction: column;">
<header class="yx-header yx-header-transparent">…</header>
<main>…</main>
<footer>…</footer>
</div>
</div>
后台 / 控制台页面
<div class="yx-app yx-layout-sidebar">
<aside class="yx-sidebar">…</aside>
<main class="yx-main">
<header class="yx-main-header">…</header>
<div id="pjax-container" class="yx-content">…</div>
</main>
</div>
侧栏菜单链接加 data-pjax 即可启用免刷新;跨布局(前台 ↔ 后台 ↔ 控制台)会自动整页跳转。
全局 AJAX / PJAX / 加载动画
新引擎独立成文件,三个能力可以分别开关:全局 AJAX(fetch/XHR 计数 + 加载动画)、PJAX(免刷新导航)、Loading(顶部进度条 / 全屏遮罩)。
引入与配置
<script src="js/yixiang.ajax.js"
data-ajax="true"
data-pjax="true"
data-loading="true"
data-overlay="false"
data-container="#pjax-container"
data-timeout="10000"></script>
| 配置项 | 默认值 | 说明 |
|---|---|---|
ajax | true | 拦截全局 fetch / XHR,自动显示加载动画 |
pjax | true | 拦截 a[data-pjax] 实现免刷新导航 |
loading | true | 显示顶部进度条 |
overlay | false | 额外显示全屏 Loading 遮罩 |
container | #pjax-container | 被替换的容器选择器 |
fragment | #pjax-container | 从响应 HTML 中提取的片段选择器 |
timeout | 10000 | PJAX 超时(毫秒),超时回退整页跳转 |
cache | false | 是否缓存 PJAX 片段(内存 Map) |
sameLayoutOnly | true | 仅同布局页面之间启用 PJAX |
scrollToTop | true | PJAX 完成后回到顶部 |
minDuration | 260 | 进度条最短展示时间,避免闪烁 |
errorFallback | true | 请求失败时回退整页跳转 |
运行时开关
// 只关闭 PJAX,保留全局 AJAX 与加载动画
YixiangAjax.disable('pjax');
YixiangAjax.enable('pjax');
// 关闭全屏 Loading / 顶部进度条
YixiangAjax.configure({ loading: false, overlay: false });
// 一键关闭全部能力
YixiangAjax.disable();
// 查看当前配置
YixiangAjax.getConfig();
也可以让运营同学直接在后台切换:站点设置 → 性能与导航。开关保存到服务端全局配置,对所有访客生效;保存成功/失败都会弹窗提示。
全局站点设置接口
所有页面初始化时会读取同一份配置,管理员在后台保存后,其他访客下次打开或切换页面即生效。
GET /api/site-settings
{
"ajax": true,
"pjax": true,
"loading": true,
"overlay": false
}
POST /api/site-settings
Content-Type: application/json
{ "pjax": false } // 支持只提交需要修改的字段,返回保存后的完整配置
- 前端通过
YixiangAjax.saveSiteSettings({ pjax: false })保存。 - 请求地址可用脚本属性覆盖:
data-settings-url="/admin/site-settings"。 - 生产环境务必在 POST 接口上增加管理员鉴权与 CSRF 校验。
- 本地
serve.py已实现该接口并写入site-config.json,可直接体验“管理员改一次,所有浏览器生效”。
发起请求
// 自动带进度条(内部使用原生 fetch,不会重复计数)
const response = await YixiangAjax.request('/api/articles', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title: 'Hello' })
});
const json = await response.json();
// 单次请求不显示加载动画
fetch('/api/ping', { yxLoading: false });
// 编程式导航
YixiangAjax.navigate('/admin_article.html');
事件
| 事件 | 触发时机 |
|---|---|
yx:ajax:ready | 引擎初始化完成 |
yx:loading:start / yx:loading:end | 加载动画开始 / 结束 |
yx:pjax:start | 开始 PJAX 请求 |
yx:pjax:success | 内容替换完成 |
yx:pjax:error | 请求失败(默认回退整页) |
yx:pjax:end | 请求结束(无论成功失败) |
yx:pjax:loaded | 组件已重新初始化、导航与面包屑已同步 |
服务端要求
- 响应必须是完整 HTML,并包含
#pjax-container(引擎会从中提取内容)。 - 可选读取
X-PJAX: true与X-PJAX-Container请求头做差异化输出。 - PJAX 只替换容器内容,不会重新加载页面级 CSS/JS;公共资源请在所有页面统一引入。
- 容器内的行内
<script>会自动执行;外链脚本需加data-reload才会重新执行。
主题系统
支持 浅色(默认)、深色、跟随系统 三种模式,偏好保存在 localStorage.yx-theme。
// 切换并持久化
YixiangComponents.applyThemeMode('light'); // 浅色
YixiangComponents.applyThemeMode('dark'); // 深色
YixiangComponents.applyThemeMode('system'); // 跟随系统
YixiangComponents.getThemeMode(); // 读取当前模式
// 监听主题变化
document.addEventListener('yixiang:themechange', function (event) {
console.log(event.detail.theme, event.detail.mode);
});
头部主题切换器使用 data-theme-value 菜单项,图标由 html[data-theme-mode] 自动切换,无需额外 JS。
组件速查
| 组件 | 关键类名 / 属性 |
|---|---|
| 按钮 | yx-btn + yx-btn-primary/default/ghost/text/success/danger,尺寸 yx-btn-sm/lg/icon |
| 卡片 | yx-card、yx-card-header/body/footer、yx-card-hover |
| 表单 | yx-form-group、yx-form-label、yx-input/textarea/select |
| 标签 | yx-badge + yx-badge-primary/success/warning/danger/neutral |
| 表格 | yx-table-wrapper > yx-table |
| 下拉 | yx-dropdown > [data-toggle="dropdown"] + yx-dropdown-menu |
| Tabs | [data-toggle="tabs"]、yx-tabs-nav、yx-tab-item[data-target]、yx-tab-pane |
| 主题切换 | yx-theme-switch + data-theme-value |
完整示例可直接查看 组件文档页。
富文本编辑器
基于 Quill 1.3.7(BSD-3-Clause)与本地 Coolapk 表情面板实现,支持标题、加粗、斜体、下划线、删除线、列表、引用、代码块、链接、图片、对齐、撤销重做与 Emoji 表情选择。
<link rel="stylesheet" href="lib/quill/quill.snow.css">
<link rel="stylesheet" href="css/yixiang.editor.css">
<script src="lib/quill/quill.min.js"></script>
<script src="js/yixiang.emoji.js"></script>
<script src="js/yixiang.editor.js"></script>
// 打开新建文章编辑器 / Open the article editor
YixiangEditor.open();
// 打开编辑模式 / Open edit mode
YixiangEditor.open({ mode: 'edit', title: '文章标题', html: '<p>正文</p>' });
// 发布后监听 / Listen to publish event
document.addEventListener('yx:article:published', function (event) {
console.log(event.detail);
});
编辑器支持 Ctrl/⌘ + S 保存草稿、Esc 关闭,发布/草稿均为模拟异步请求。
弹窗引擎
YixiangModal 为原生实现,支持遮罩、拖拽、ESC、焦点循环、滚动锁定与自动关闭。
YixiangModal.alert('保存成功', { icon: 'success' });
YixiangModal.confirm('确定删除?', function (id) {
// 返回 false 可阻止自动关闭
});
YixiangModal.prompt('请输入标题', { title: '重命名' }, function (value, id) {
YixiangModal.msg('你输入了:' + value);
});
YixiangModal.msg('网络超时,请重试'); // 3 秒自动关闭
YixiangModal.load({ text: '正在加载...', time: 2000 });
YixiangModal.iframe('https://example.com', { area: ['80%', '80vh'] });
YixiangModal.open({
type: 'page',
title: '编辑内容',
content: '<div style="padding:20px">任意 HTML</div>',
btn: ['保存', '取消'],
yes: function (id) { /* … */ }
});
声明式写法(旧版兼容):
<button class="yx-btn yx-btn-primary"
data-toggle="modal" data-target="#demoModal">打开</button>
<div class="yx-modal" id="demoModal">…</div>
扩展弹层:Tabs / Drawer / Photos / Tips
翊象 UI 内置的高频扩展能力,API 原生、可独立调用:
// 标签页弹层 / Tabbed dialog
YixiangModal.tabs({
title: '内容详情',
tabs: [
{ title: '概览', content: '<p>概览内容</p>' },
{ title: '高级', content: '<p>高级设置</p>' }
]
});
// 右侧抽屉 / Right drawer
YixiangModal.drawer({
title: '筛选条件',
content: '<p>抽屉内容</p>',
btn: ['应用筛选', '重置']
});
// 图片预览 / Photo viewer
YixiangModal.photos({
photos: ['assets/images/demo-1.svg', 'assets/images/demo-2.svg'],
index: 0
});
// 气泡提示 / Tooltip
YixiangModal.tips('这是一个气泡提示 ✨', targetElement, { placement: 'bottom', time: 2600 });
Loading 支持卡片式、无卡片与全屏遮罩:YixiangModal.load({ text, card, shade, time })。
CMS 对接示例
ThinkPHP 控制器
public function article()
{
$list = Db::name('article')->order('id desc')->paginate(10);
$this->assign('list', $list);
return $this->fetch(); // 返回完整页面(含 #pjax-container)
}
模板片段
<div id="pjax-container" class="yx-content">
<div class="yx-page-header">
<h1 class="yx-page-title">文章管理</h1>
</div>
<div class="yx-card">
<div class="yx-table-wrapper">
<table class="yx-table">…</table>
</div>
</div>
</div>
表单 AJAX 提交
document.querySelector('#article-form').addEventListener('submit', async function (event) {
event.preventDefault();
const response = await YixiangAjax.request(this.action, {
method: 'POST',
body: new FormData(this)
});
const result = await response.json();
if (result.code === 0) {
YixiangModal.msg('保存成功', { icon: 'success' });
YixiangAjax.navigate('/admin_article.html');
} else {
YixiangModal.alert(result.message, { icon: 'error' });
}
});
Content-Type: application/json。
常见问题
1. 直接双击 HTML,PJAX 不生效?
浏览器会限制 file:// 下的 XHR/fetch。请用 python serve.py 或任意 HTTP 服务器访问。
2. PJAX 后组件失效?
组件使用事件委托,正常情况下无需手动绑定。若自行扩展了 DOM 级插件,请在 yx:pjax:loaded 事件中重新初始化:
document.addEventListener('yx:pjax:loaded', function () {
// 重新初始化第三方插件
});
3. 点击后台链接为什么整页刷新?
前台、后台 admin_*、控制台 console_* 属于三种布局。引擎默认只在同布局内 PJAX,跨布局整页跳转以避免侧栏/头部错乱。
4. 如何彻底关闭免刷新?
移除 data-pjax 属性,或执行 YixiangAjax.disable('pjax');也可以给链接加 data-no-pjax。
5. 进度条不显示?
检查是否引入 css/yixiang.ajax.css、YixiangAjax.isEnabled('loading') 是否为 true,以及脚本标签是否设置了 data-loading="false"。
6. 能和旧版 jQuery PJAX 共存吗?
不能同时加载。新版已完全替代 js/yixiang.pjax.js 与 NProgress,请从页面移除旧脚本和 nprogress.css。
7. 版本
当前框架、组件与脚本统一为 v1.0。