即時表單驗證極大提升用戶體驗。本文展示 Yii 1.x 利用 CActiveForm 實現 AJAX 異步驗證的完整配置:視圖啟用、控制器處理、模型規則、錯誤顯示與性能優化。
<?php
$form = $this->beginWidget('CActiveForm', array(
'id' => 'zdzone-form', // 表單 ID (必須,AJAX 識別用)
'enableAjaxValidation' => true, // 核心:開啟 AJAX 驗證
'enableClientValidation' => true, // 同時開啟客戶端 JS 驗證 (雙重保障)
'action' => '/manage/adzone/createadzone', // 提交地址
'htmlOptions' => array('class' => 'form-horizontal'),
));
?>
<div class="form-group">
<?php echo $form->labelEx($model, 'name', array('class' => 'col-sm-2 control-label')); ?>
<div class="col-sm-10">
<?php echo $form->textField($model, 'name', array('class' => 'form-control')); ?>
<?php echo $form->error($model, 'name', array('class' => 'text-danger')); ?>
</div>
</div>
<div class="form-group">
<?php echo $form->labelEx($model, 'url', array('class' => 'col-sm-2 control-label')); ?>
<div class="col-sm-10">
<?php echo $form->textField($model, 'url', array('class' => 'form-control')); ?>
<?php echo $form->error($model, 'url', array('class' => 'text-danger')); ?>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<?php echo CHtml::submitButton('提交', array('class' => 'btn btn-primary')); ?>
</div>
</div>
<?php $this->endWidget(); ?>
<?php
class AdzoneController extends Controller {
public function actionCreateadzone() {
$model = new AdZone();
// 【關鍵】AJAX 驗證攔截:必須在模型賦值/保存之前
if (isset($_POST['ajax']) && $_POST['ajax'] === 'zdzone-form') {
echo CActiveForm::validate($model);
Yii::app()->end(); // 直接輸出 JSON 錯誤信息,不渲染視圖
}
// 正常表單提交處理
if (isset($_POST['AdZone'])) {
$model->attributes = $_POST['AdZone'];
if ($model->validate()) { // 服務端二次驗證 (防繞過 AJAX)
if ($model->save()) {
$this->redirect(array('view', 'id' => $model->id));
}
}
}
$this->render('create', array('model' => $model));
}
}
<?php
class AdZone extends CActiveRecord {
public function rules() {
return array(
array('name, url', 'required', 'message' => '{attribute} 不能為空'),
array('name', 'length', 'max' => 100, 'tooLong' => '名稱最長 100 字符'),
array('url', 'url', 'pattern' => '/^(https?:\/\/).+/i', 'message' => 'URL 格式不正確'),
array('url', 'unique', 'message' => '該廣告位鏈接已存在'),
array('status', 'in', 'range' => array(0, 1), 'message' => '狀態值非法'),
// 安全屬性:允許批量賦值
array('name, url, status', 'safe', 'on' => 'search'),
);
}
public function attributeLabels() {
return array(
'name' => '廣告位名稱',
'url' => '落地頁鏈接',
'status' => '狀態',
);
}
}
用戶輸入字段 → 失去焦點 (blur)
↓
jQuery.yii.activeForm.validate() 發送 POST
↓
POST /createadzone?ajax=zdzone-form
↓
控制器識別 $_POST['ajax'] === 'zdzone-form'
↓
CActiveForm::validate($model) 執行模型驗證
↓
返回 JSON: {"fieldId":["錯誤信息1","錯誤信息2"],...}
↓
前端更新對應字段 error 容器顯示紅字
↓
用戶修正後再次觸發驗證 → 綠勾/清空錯誤
| 參數 | 默認值 | 說明 |
|---|---|---|
| enableAjaxValidation | false | 總開關 |
| enableClientValidation | false | 基於模型 rules 生成 JS 驗證代碼 (required、length、email、url、number、compare、custom) |
| validateOnSubmit | true | 提交時觸發 AJAX 驗證,失敗阻止提交 |
| validateOnChange | true | 值改變時觸發 |
| validateOnType | false | 輸入時實時驗證 (高頻請求,慎開) |
| validationDelay | 200 | 防抖延遲毫秒數 |
| clientOptions.validateOnBlur | true | 失焦驗證 |
| clientOptions.afterValidate | null | JS 回調:function(form, data, hasError) {} |
| clientOptions.afterValidateAttribute | null | 單字段驗證後回調 |
$form = $this->beginWidget('CActiveForm', array(
'id' => 'custom-form',
'enableAjaxValidation' => true,
'clientOptions' => array(
'afterValidateAttribute' => 'js:function(form, attribute, data, hasError) {
if (!hasError) {
$(attribute.container).addClass("has-success").removeClass("has-error");
$(attribute.input).tooltip("destroy");
} else {
$(attribute.container).addClass("has-error").removeClass("has-success");
$(attribute.input).tooltip({title: data[0], placement: "right"}).tooltip("show");
}
}',
),
));
| 問題 | 原因 | 解決 |
|---|---|---|
| AJAX 請求過多 | validateOnType=true + 快速輸入 | 關閉 validateOnType,依賴 validateOnBlur + validationDelay=500 |
| 驗證邏輯重複執行 | 客戶端+服務端雙重 | 客戶端僅做格式/必填,複雜業務規則 (唯一性、關聯檢查) 僅服務端 |
| CSRF Token 失效 | AJAX 未攜帶 token | Yii 自動處理,確保表單有 request->csrfTokenName, Yii::app()->request->csrfToken); ?> |
| 文件上傳字段驗證失效 | AJAX 無法上傳文件 | 文件字段僅服務端驗證,或使用 FormData + 獨立上傳接口 |
| 多表單頁面衝突 | form id 重複 | 每個 CActiveForm 必須設置唯一 id |
Yii CActiveForm AJAX 驗證核心三步:視圖 enableAjaxValidation=true → 控制器攔截 $_POST['ajax'] → CActiveForm::validate() 返回 JSON。配合 enableClientValidation 實現客戶端即時反饋、服務端權威校驗的雙重保障。關鍵細節:表單 ID 唯一、驗證攔截優先於賦值、Yii::app()->end() 終止執行、CSRF 自動處理。掌握此模式,可構建媲美 SPA 體驗的傳統表單交互。