首页 / 开发文档 / 前端开发

前端开发文档

XPCMS 前端基于 TailwindCSS + XPUI 自研框架,严格遵循 HTML/CSS/JS 完全分离原则。本文档涵盖技术栈、命名规范、主题开发、模板语法及最佳实践。

1. 技术栈

技术版本用途
Tailwind CSSv3.x原子化 CSS 框架,优先使用
XPUI自研唯一UI框架,封装通用样式与组件
Font Awesomev6.x图标库
jQueryv3.xDOM 操作与 Ajax 请求
Layerv3.x弹窗组件
ThinkPHP 模板v8服务端模板引擎

重要规则:禁止引入任何第三方 UI 框架(如 Bootstrap、Element UI),仅允许使用 TailwindCSS + XPUI。

2. 命名规范(xp- 前缀)

所有 class 和 id 必须以 xp- 为前缀,使用短横线连接,全小写。禁止驼峰、下划线、拼音。

类型正确示例错误示例
布局容器xp-container, xp-wrappercontainer, wrapper_1, rongQi
页面头部xp-header, xp-header-navheader, HeaderNav, header_nav
导航菜单xp-nav, xp-nav-itemnav, navItem, nav_item
表单元素xp-form, xp-input, xp-btnform, inputBox, submit_Btn
表格xp-table, xp-table-thtable, TableHead, table_head
卡片xp-card, xp-card-bodycard, cardBody, card_body
弹窗xp-modal, xp-modal-titlemodal, modalTitle, modal_title
列表xp-list, xp-list-itemlist, listItem, list_item
侧边栏xp-sidebar, xp-sidebar-menusidebar, SidebarMenu, sidebar_menu
页脚xp-footer, xp-footer-linkfooter, FooterLink, footer_link

3. 代码分离原则

XPCMS 前端严格遵循 HTML / CSS / JS 完全独立文件 的开发模式:

规则说明违规示例
禁止内联样式不允许 style="..." 属性<div style="color:red"> ❌
禁止内联事件不允许 onclick="..." 等属性<button onclick="doSomething()"> ❌
CSS 独立文件业务样式写入 /static/应用名/css/<style> 在HTML中 ❌
JS 独立文件业务脚本写入 /static/应用名/js/<script> 在HTML中 ❌
事件委托绑定JS中用选择器绑定事件$(document).on('click', '.xp-btn', fn) ✅

4. 静态资源路径规范

资源类型存放路径访问URL
静态根目录public/static//static/
XPUI 框架public/static/xpui//static/xpui/
业务 CSSpublic/static/应用名/css//static/应用名/css/
业务 JSpublic/static/应用名/js//static/应用名/js/
业务图片public/static/应用名/images//static/应用名/images/

5. 主题开发规范

每个主题位于 themes/frontend/主题标识/,核心文件为 theme.json

主题目录结构

themes/frontend/your-theme/
├── theme.json          # 主题配置文件(必填)
├── theme.png           # 主题预览图
├── view/               # 模板视图目录
│   ├── index.html      # 首页模板
│   ├── list.html       # 列表页模板
│   ├── show.html       # 详情页模板
│   └── common/         # 公共模板片段
│       ├── _header.html
│       └── _footer.html
├── static/             # 主题静态资源
│   ├── css/
│   │   └── theme.css
│   ├── js/
│   │   └── theme.js
│   └── images/
│       └── logo.png
└── config/             # 主题配置面板
    └── config.php

theme.json 配置

{
    "name": "主题名称",
    "version": "1.0.0",
    "author": "作者",
    "description": "主题描述",
    "screenshot": "theme.png",
    "templates": {
        "index": "view/index.html",
        "list": "view/list.html",
        "show": "view/show.html"
    }
}

FrontendConfig 全局变量(15 个)

所有主题模板中可直接使用以下系统变量:

变量名说明示例
{$site_name}站点名称XPCMS 官网
{$site_logo}站点 Logo URL/static/images/logo.png
{$site_keywords}站点关键词CMS,内容管理
{$site_description}站点描述XPCMS 内容管理系统
{$site_icp}ICP 备案号粤ICP备xxxxxx号
{$site_copyright}版权信息© 2025 XPCMS
{$theme_path}当前主题资源路径/themes/frontend/default
{$static_path}静态资源路径/static
{$category_tree}分类树数据多维数组
{$nav_menu}导航菜单数据关联数组
{$page_title}当前页面标题新闻列表
{$current_category}当前分类信息关联数组
{$breadcrumb}面包屑导航数据数组
{$friend_links}友情链接列表数组
{$ad_list}广告位数据按位置分组

6. 栏目分类体系

XPCMS 将栏目分为三大类别,每种类型有不同的模板处理逻辑和子分类结构。

三大类别

分类类型type 值核心特征典型场景
单页page单个页面,无列表,内容编辑器编辑关于我们、联系我们
列表list有文章列表,支持分页,点击进入详情新闻中心、产品展示
链接link跳转到外部URL,无内容友情链接、外部导航

列表类型的子分类

子类型sub_type说明
文章article标准图文内容,有标题/封面/正文
图集gallery多图展示,以大图轮播方式呈现
视频video视频内容,内嵌播放器
下载download文件下载,含下载链接和文件信息
产品product产品展示,含价格/规格/参数

三类区别对比

特性单页列表链接
文章列表❌ 无✅ 有❌ 无
详情页❌ 无✅ 有❌ 无
内容编辑器✅ 富文本❌ 无❌ 无
跳转链接✅ 跳转外部URL
子分类❌ 不支持✅ 无限层级❌ 不支持
SEO TDK✅ 自定义✅ 自定义❌ 无

7. ThinkPHP 模板语法速查

语法说明示例
{$var}变量输出{$site_name}
{$var|default='默认'}默认值{$title|default='无标题'}
{$var|raw}不转义HTML输出{$content|raw}
{$var|date='Y-m-d'}日期格式化{$create_time|date='Y-m-d'}
{$var|substr=0,100}字符串截取{$title|substr=0,50}
{$var|number_format=2}数字格式化{$price|number_format=2}
{$var|count}数组计数{$list|count}

volist 循环

{volist name="list" id="vo" key="k"}
  <!-- $vo 为当前项,$k 为索引(从1开始),$i 为索引(从0开始) -->
  <div class="xp-list-item">
    <a href="{$vo.url}">{$vo.title}</a>
    <span>{$vo.create_time|date='Y-m-d'}</span>
  </div>
{/volist}

<!-- 空数据提示 -->
{volist name="list" id="vo" empty="<p>暂无数据</p>"}
  ...
{/volist}

if 条件判断

{if condition="$vo.status == 1"}
  <span class="text-green-600">已发布</span>
{elseif condition="$vo.status == 0" /}
  <span class="text-gray-400">草稿</span>
{else /}
  <span class="text-red-500">已下架</span>
{/if}

json_encode 与 literal

<!-- 将 PHP 变量转为 JSON 输出到 JS -->
<script>
window.xpConfig = {:json_encode($config)};
window.xpData  = {:json_encode($data)};
</script>

<!-- 阻止模板解析(literal标签内的内容原样输出) -->
{literal}
  <style>/* 这里的CSS不会被模板引擎解析 */</style>
  <script>/* 这里的JS不会被模板引擎解析 */</script>
{/literal}

include 引入模板

<!-- 引入公共头部 -->
{include file="common/_header" /}

<!-- 引入公共底部 -->
{include file="common/_footer" /}

<!-- 引入并传参 -->
{include file="common/_sidebar" active="news" /}

8. 后台视图模板编写规范

8.1 列表页模板结构

{extend name="common/_layout" /}
{block name="content"}

<!-- 搜索区域 -->
<div class="xp-card xp-mb-16">
  <div class="xp-card-body">
    <form class="xp-form xp-form-inline" id="xpSearchForm">
      <div class="xp-form-group">
        <label class="xp-form-label">关键词</label>
        <input type="text" name="keyword" class="xp-input" placeholder="请输入关键词">
      </div>
      <button type="submit" class="xp-btn xp-btn-primary">搜索</button>
    </form>
  </div>
</div>

<!-- 操作栏 -->
<div class="xp-toolbar xp-mb-16">
  <button class="xp-btn xp-btn-success" id="xpBtnAdd">新增</button>
  <button class="xp-btn xp-btn-danger" id="xpBtnBatchDelete">批量删除</button>
</div>

<!-- 数据表格 -->
<table class="xp-table" id="xpDataTable">
  <thead>
    <tr>
      <th><input type="checkbox" id="xpCheckAll"></th>
      <th>ID</th>
      <th>标题</th>
      <th>状态</th>
      <th>时间</th>
      <th>操作</th>
    </tr>
  </thead>
  <tbody id="xpTableBody"></tbody>
</table>

<!-- 分页 -->
<div id="xpPagination" class="xp-pagination"></div>

{/block}

8.2 表单页模板结构

{extend name="common/_layout" /}
{block name="content"}

<form class="xp-form" id="xpForm" method="post">
  <div class="xp-card">
    <div class="xp-card-header">基本信息</div>
    <div class="xp-card-body">
      <!-- 隐藏的ID字段,编辑时带上 -->
      <input type="hidden" name="id" value="{$data.id|default=''}">

      <div class="xp-form-group">
        <label class="xp-form-label xp-form-required">标题</label>
        <input type="text" name="title" class="xp-input"
               value="{$data.title|default=''}" placeholder="请输入标题">
      </div>

      <div class="xp-form-group">
        <label class="xp-form-label">分类</label>
        <select name="category_id" class="xp-select">
          <option value="">请选择分类</option>
          {volist name="category_list" id="cat"}
          <option value="{$cat.id}"
                  {if condition="$data.category_id == $cat.id"}selected{/if}>
            {$cat.name}
          </option>
          {/volist}
        </select>
      </div>

      <div class="xp-form-group">
        <label class="xp-form-label">内容</label>
        <textarea name="content" class="xp-textarea xp-editor"
                  rows="10">{$data.content|default=''}</textarea>
      </div>
    </div>
    <div class="xp-card-footer">
      <button type="submit" class="xp-btn xp-btn-primary">保存</button>
      <button type="button" class="xp-btn xp-btn-default" onclick="history.back()">返回</button>
    </div>
  </div>
</form>

{/block}

8.3 弹窗表单结构

<!-- 弹窗HTML模板,默认隐藏 -->
<div id="xpModalTemplate" style="display:none;">
  <form class="xp-form xp-p-20" id="xpModalForm">
    <input type="hidden" name="id">
    <div class="xp-form-group">
      <label class="xp-form-label">名称</label>
      <input type="text" name="name" class="xp-input">
    </div>
  </form>
</div>

9. 前台最佳实践

9.1 面包屑导航

<div class="xp-breadcrumb">
  <a href="/">首页</a>
  {if condition="isset($breadcrumb)"}
    {volist name="breadcrumb" id="bc"}
      <span>/</span>
      <a href="{$bc.url}">{$bc.name}</a>
    {/volist}
  {/if}
  <span>/</span>
  <span>{$page_title|default=''}</span>
</div>

9.2 卡片布局

<div class="xp-card xp-card-shadow xp-card-hover">
  <div class="xp-card-image">
    <img src="{$vo.cover_image}" alt="{$vo.title}">
  </div>
  <div class="xp-card-body">
    <h3 class="xp-card-title">{$vo.title|substr=0,40}</h3>
    <p class="xp-card-desc">{$vo.description|substr=0,100}</p>
    <div class="xp-card-meta">
      <span>{$vo.create_time|date='Y-m-d'}</span>
      <span>{$vo.views} 阅读</span>
    </div>
  </div>
</div>

9.3 响应式布局

<!-- 桌面端2列,平板2列,手机1列 -->
<div class="xp-grid xp-grid-cols-1 md:xp-grid-cols-2 lg:xp-grid-cols-3 xp-gap-6">
  {volist name="list" id="vo"}
  <div class="xp-card">...</div>
  {/volist}
</div>

9.4 移动端适配要点

要点说明
Viewport必须设置 <meta name="viewport" content="width=device-width, initial-scale=1.0">
断点sm:640px / md:768px / lg:1024px / xl:1280px
触控区域按钮/链接最小触控面积为 44×44px
图片使用 srcset 响应式图片或 CDN 裁剪
导航移动端使用汉堡菜单,桌面端展开导航
表格移动端表格横向滚动或卡片化展示