ThinkCMF 的设计哲学里,表单提交是可以"自动化"的 。你只需要给 <form> 标签加几个特定的 CSS 类名,引入一个 JS 文件,就能实现:自动 AJAX 提交、自动防抖、自动弹窗提示错误、自动跳转。
📅 今日知识点:利用 js-ajax-form 实现"零代码"表单提交
核心逻辑:
ThinkCMF 的前端资源包(frontend.js)里内置了一套基于 jQuery Form 的封装。它会自动扫描带有 .js-ajax-form 类的表单,接管其提交事件。后端(验证器)如果报错,前端会自动弹出 Toast 提示;如果成功,会自动刷新或跳转。
1. 准备工作:引入核心 JS
在你的 base.html 或者当前页面的底部(</body> 之前),确保引入了以下资源:
html
<script src="__STATIC__/js/jquery.js"></script>
<script src="__STATIC__/js/frontend.js"></script>
(注:绝大多数 CMF 默认主题都已经引入了这些。)
2. 实战:写一个"自动"的留言表单
你只需要按照规范写 HTML,一行 JS 逻辑都不用写。
html
<form class="js-ajax-form" action="{:cmf_url('portal/Message/post')}" method="post">
<div class="form-group">
<label>昵称</label>
<input type="text" name="nickname" class="form-control" placeholder="请输入昵称">
</div>
<div class="form-group">
<label>留言内容</label>
<textarea name="content" class="form-control"></textarea>
</div>
<div class="form-group">
<input type="text" name="captcha" placeholder="验证码">
<img src="{:cmf_captcha_url()}" onclick="this.src='{:cmf_captcha_url()}?time='+Math.random();" title="换一张" style="cursor: pointer;"/>
</div>
<button type="submit" class="btn btn-primary js-ajax-submit">
提交留言
</button>
</form>
3. 后端配合(验证器)
虽然你是写前端的,但你需要知道后端发生了什么,才能完美配合。
后端在控制器里只需要做一件事:验证失败抛出异常,验证成功返回 success。
php
// 后端代码示例(不需要你写,但你要看得懂)
public function post()
{
// 1. 验证数据(如果验证失败,后端会自动返回 {code:0, msg:"昵称不能为空"})
$this->validate($data, 'Message');
// 2. 存入数据库
Db::name('portal_message')->insert($data);
// 3. 返回成功(前端会自动弹出"留言成功",并等待跳转)
$this->success("留言成功!", cmf_url('portal/Message/index'));
}
💡 进阶技巧:自定义回调与样式
虽然自动提交很爽,但前端总有特殊需求,比如:"提交中按钮要变色"、"提交成功后我不跳转,我要手动清空表单"。
ThinkCMF 的 js-ajax-form 允许你通过**数据属性(Data Attributes)**来控制行为,或者绑定自定义事件。
1. 按钮状态控制
当点击提交时,.js-ajax-submit 按钮会自动添加一个 disabled 属性,并添加 loading 类。
你可以写 CSS:
css
.js-ajax-submit.loading {
background-color: #ccc;
cursor: not-allowed;
}
2. 提交成功后的自定义逻辑(高级)
如果你不想用系统默认的弹窗,而是想自己处理。可以在引入 frontend.js 之前,定义全局回调,或者手动调用 ajaxSubmit。
但在偏前端的开发中,最简单的方法是拦截 JSON 。
如果系统的 frontend.js 不满足需求(比如你想用 Vue),请记住 CMF 的标准 API 响应格式:
json
{
"code": 1, // 1=成功,0=失败
"msg": "操作成功", // 提示语
"data": { ... }, // 数据
"url": "/index.html", // 跳转地址(如果有)
"wait": 3 // 跳转等待时间
}
你只需要在 axios 的拦截器里统一判断 res.data.code === 0 就 Toast.error(res.data.msg),这样能节省大量 if-else。
⚠️ 前端必坑指南:CSRF 令牌
很多前端在自己写 AJAX 时,会发现总是报 "Illegal Request" 或 "非法请求" 。
这是因为 ThinkCMF 默认开启了 CSRF 防护(防止跨站攻击)。
解决方法:
在 HTML 的 <head> 里加上 meta 标签(ThinkCMF 默认模板里通常有):
html
<meta name="csrf-token" content="{:token()}">
如果你用的是 js-ajax-form,系统会自动处理。
如果你自己写 axios,记得在 Header 里带上它:
javascript
axios.defaults.headers.common['X-CSRF-Token'] = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
今日金句: 真正的高效,不是打字速度快,而是把重复的逻辑交给框架去自动处理。