Backbone.js模型验证 #
一、验证概述 #
1.1 什么是验证 #
验证是确保数据符合特定规则的过程,在数据保存前检查数据的有效性。
text
验证流程
├── 调用set/save方法
├── 触发validate方法
├── 验证通过 → 继续操作
└── 验证失败 → 触发invalid事件
1.2 验证时机 #
| 方法 | 默认验证 | 说明 |
|---|---|---|
| set | 是 | 设置属性时验证 |
| save | 是 | 保存模型时验证 |
| unset | 否 | 删除属性时不验证 |
| clear | 否 | 清空属性时不验证 |
二、validate方法 #
2.1 基本验证 #
javascript
var User = Backbone.Model.extend({
validate: function(attrs) {
if (!attrs.name || attrs.name.trim() === '') {
return '姓名不能为空';
}
}
});
var user = new User();
user.on('invalid', function(model, error) {
console.log('验证失败:', error);
});
user.set({ name: '' }, { validate: true });
2.2 返回错误信息 #
javascript
var User = Backbone.Model.extend({
validate: function(attrs) {
if (!attrs.name) {
return '姓名不能为空';
}
if (!attrs.email) {
return '邮箱不能为空';
}
if (attrs.age < 0) {
return '年龄不能为负数';
}
}
});
2.3 返回错误对象 #
javascript
var User = Backbone.Model.extend({
validate: function(attrs) {
var errors = [];
if (!attrs.name || attrs.name.trim() === '') {
errors.push({ field: 'name', message: '姓名不能为空' });
}
if (!attrs.email || !attrs.email.match(/^[\w-]+@[\w-]+\.[a-z]+$/i)) {
errors.push({ field: 'email', message: '邮箱格式不正确' });
}
if (attrs.age !== undefined && attrs.age < 0) {
errors.push({ field: 'age', message: '年龄不能为负数' });
}
if (errors.length > 0) {
return errors;
}
}
});
var user = new User();
user.on('invalid', function(model, errors) {
errors.forEach(function(error) {
console.log(error.field + ': ' + error.message);
});
});
user.set({ name: '', email: 'invalid', age: -1 }, { validate: true });
三、验证规则 #
3.1 必填验证 #
javascript
var User = Backbone.Model.extend({
validate: function(attrs) {
var required = ['name', 'email'];
required.forEach(function(field) {
if (!attrs[field] || attrs[field].trim() === '') {
return field + '是必填字段';
}
});
}
});
3.2 格式验证 #
javascript
var User = Backbone.Model.extend({
validate: function(attrs) {
var patterns = {
email: /^[\w-]+@[\w-]+\.[a-z]+$/i,
phone: /^1[3-9]\d{9}$/,
url: /^https?:\/\/.+/
};
if (attrs.email && !patterns.email.test(attrs.email)) {
return '邮箱格式不正确';
}
if (attrs.phone && !patterns.phone.test(attrs.phone)) {
return '手机号格式不正确';
}
if (attrs.website && !patterns.url.test(attrs.website)) {
return '网址格式不正确';
}
}
});
3.3 范围验证 #
javascript
var Product = Backbone.Model.extend({
validate: function(attrs) {
if (attrs.price !== undefined) {
if (attrs.price < 0) {
return '价格不能为负数';
}
if (attrs.price > 1000000) {
return '价格不能超过100万';
}
}
if (attrs.quantity !== undefined) {
if (attrs.quantity < 0) {
return '数量不能为负数';
}
if (attrs.quantity > 10000) {
return '数量不能超过10000';
}
}
if (attrs.discount !== undefined) {
if (attrs.discount < 0 || attrs.discount > 100) {
return '折扣必须在0-100之间';
}
}
}
});
3.4 长度验证 #
javascript
var Article = Backbone.Model.extend({
validate: function(attrs) {
if (attrs.title) {
if (attrs.title.length < 5) {
return '标题至少5个字符';
}
if (attrs.title.length > 100) {
return '标题不能超过100个字符';
}
}
if (attrs.content) {
if (attrs.content.length < 100) {
return '内容至少100个字符';
}
}
if (attrs.tags && attrs.tags.length > 10) {
return '标签数量不能超过10个';
}
}
});
3.5 自定义验证 #
javascript
var User = Backbone.Model.extend({
validate: function(attrs) {
if (attrs.password && attrs.confirmPassword) {
if (attrs.password !== attrs.confirmPassword) {
return '两次密码输入不一致';
}
if (attrs.password.length < 6) {
return '密码至少6个字符';
}
}
if (attrs.birthDate) {
var birthDate = new Date(attrs.birthDate);
var now = new Date();
var age = now.getFullYear() - birthDate.getFullYear();
if (age < 18) {
return '年龄必须满18岁';
}
if (age > 120) {
return '请输入正确的出生日期';
}
}
}
});
四、验证触发 #
4.1 set时验证 #
javascript
var User = Backbone.Model.extend({
validate: function(attrs) {
if (!attrs.name) {
return '姓名不能为空';
}
}
});
var user = new User({ name: '张三' });
var result = user.set({ name: '' }, { validate: true });
console.log(result);
console.log(user.get('name'));
4.2 save时验证 #
javascript
var User = Backbone.Model.extend({
urlRoot: '/api/users',
validate: function(attrs) {
if (!attrs.name) {
return '姓名不能为空';
}
}
});
var user = new User();
user.save({ name: '' }, {
success: function() {
console.log('保存成功');
},
error: function(model, response) {
console.log('保存失败');
}
});
4.3 跳过验证 #
javascript
var user = new User({ name: '张三' });
user.set({ name: '' }, { validate: false });
console.log(user.get('name'));
user.set({ name: '' }, { silent: true });
4.4 手动验证 #
javascript
var User = Backbone.Model.extend({
validate: function(attrs) {
if (!attrs.name) {
return '姓名不能为空';
}
},
isValid: function() {
return this.validate(this.attributes) === undefined;
}
});
var user = new User({ name: '' });
console.log(user.isValid());
五、错误处理 #
5.1 invalid事件 #
javascript
var User = Backbone.Model.extend({
validate: function(attrs) {
if (!attrs.name) {
return '姓名不能为空';
}
}
});
var user = new User();
user.on('invalid', function(model, error, options) {
console.log('验证错误:', error);
console.log('验证属性:', options);
});
user.set({ name: '' }, { validate: true });
5.2 validationError属性 #
javascript
var User = Backbone.Model.extend({
validate: function(attrs) {
if (!attrs.name) {
return '姓名不能为空';
}
}
});
var user = new User();
var result = user.set({ name: '' }, { validate: true });
if (!result) {
console.log('验证错误:', user.validationError);
}
5.3 在视图中处理错误 #
javascript
var UserView = Backbone.View.extend({
events: {
'click .save': 'saveUser'
},
initialize: function() {
this.listenTo(this.model, 'invalid', this.showError);
},
saveUser: function() {
var data = {
name: this.$('#name').val(),
email: this.$('#email').val()
};
this.model.save(data);
},
showError: function(model, error) {
this.$('.error').text(error).show();
}
});
5.4 显示多个错误 #
javascript
var User = Backbone.Model.extend({
validate: function(attrs) {
var errors = {};
if (!attrs.name) {
errors.name = '姓名不能为空';
}
if (!attrs.email) {
errors.email = '邮箱不能为空';
}
if (attrs.age < 0) {
errors.age = '年龄不能为负数';
}
if (Object.keys(errors).length > 0) {
return errors;
}
}
});
var UserView = Backbone.View.extend({
initialize: function() {
this.listenTo(this.model, 'invalid', this.showErrors);
},
showErrors: function(model, errors) {
this.clearErrors();
for (var field in errors) {
this.$('#' + field).addClass('error');
this.$('#' + field + '-error').text(errors[field]);
}
},
clearErrors: function() {
this.$('.error').removeClass('error');
this.$('.error-message').text('');
}
});
六、高级验证 #
6.1 条件验证 #
javascript
var User = Backbone.Model.extend({
validate: function(attrs) {
if (attrs.type === 'company') {
if (!attrs.companyName) {
return '公司名称不能为空';
}
if (!attrs.businessLicense) {
return '营业执照号不能为空';
}
} else if (attrs.type === 'personal') {
if (!attrs.idCard) {
return '身份证号不能为空';
}
}
}
});
6.2 异步验证 #
javascript
var User = Backbone.Model.extend({
validate: function(attrs) {
if (attrs.username) {
var self = this;
$.ajax({
url: '/api/check-username',
data: { username: attrs.username },
async: false,
success: function(response) {
if (response.exists) {
self.validationError = '用户名已存在';
}
}
});
if (this.validationError) {
return this.validationError;
}
}
}
});
6.3 验证器模式 #
javascript
var Validators = {
required: function(value, message) {
if (!value || value.trim() === '') {
return message || '此字段必填';
}
},
email: function(value, message) {
if (value && !value.match(/^[\w-]+@[\w-]+\.[a-z]+$/i)) {
return message || '邮箱格式不正确';
}
},
minLength: function(value, length, message) {
if (value && value.length < length) {
return message || '长度至少' + length + '个字符';
}
},
maxLength: function(value, length, message) {
if (value && value.length > length) {
return message || '长度不能超过' + length + '个字符';
}
},
range: function(value, min, max, message) {
if (value !== undefined && (value < min || value > max)) {
return message || '值必须在' + min + '到' + max + '之间';
}
}
};
var User = Backbone.Model.extend({
validators: {
name: [
{ validator: 'required', message: '姓名不能为空' },
{ validator: 'minLength', args: [2], message: '姓名至少2个字符' }
],
email: [
{ validator: 'required', message: '邮箱不能为空' },
{ validator: 'email', message: '邮箱格式不正确' }
],
age: [
{ validator: 'range', args: [0, 150], message: '年龄必须在0-150之间' }
]
},
validate: function(attrs) {
var errors = {};
for (var field in this.validators) {
var rules = this.validators[field];
var value = attrs[field];
for (var i = 0; i < rules.length; i++) {
var rule = rules[i];
var validator = Validators[rule.validator];
var args = [value].concat(rule.args || []);
args.push(rule.message);
var error = validator.apply(null, args);
if (error) {
errors[field] = error;
break;
}
}
}
if (Object.keys(errors).length > 0) {
return errors;
}
}
});
七、实用示例 #
7.1 注册表单验证 #
javascript
var Registration = Backbone.Model.extend({
validate: function(attrs) {
var errors = {};
if (!attrs.username || attrs.username.length < 3) {
errors.username = '用户名至少3个字符';
}
if (!attrs.email || !attrs.email.match(/^[\w-]+@[\w-]+\.[a-z]+$/i)) {
errors.email = '请输入有效的邮箱地址';
}
if (!attrs.password || attrs.password.length < 6) {
errors.password = '密码至少6个字符';
}
if (attrs.password !== attrs.confirmPassword) {
errors.confirmPassword = '两次密码输入不一致';
}
if (!attrs.agree) {
errors.agree = '请同意用户协议';
}
if (Object.keys(errors).length > 0) {
return errors;
}
}
});
7.2 产品验证 #
javascript
var Product = Backbone.Model.extend({
validate: function(attrs) {
var errors = {};
if (!attrs.name || attrs.name.trim() === '') {
errors.name = '产品名称不能为空';
}
if (attrs.price === undefined || attrs.price < 0) {
errors.price = '价格必须大于等于0';
}
if (attrs.stock !== undefined && attrs.stock < 0) {
errors.stock = '库存不能为负数';
}
if (attrs.category && !this.isValidCategory(attrs.category)) {
errors.category = '无效的产品分类';
}
if (Object.keys(errors).length > 0) {
return errors;
}
},
isValidCategory: function(category) {
var validCategories = ['electronics', 'clothing', 'food', 'books'];
return validCategories.indexOf(category) !== -1;
}
});
八、总结 #
8.1 验证要点 #
| 要点 | 说明 |
|---|---|
| validate方法 | 返回错误信息表示验证失败 |
| 验证时机 | set和save时自动验证 |
| invalid事件 | 验证失败时触发 |
| validationError | 存储最后一次验证错误 |
8.2 最佳实践 #
- 返回结构化的错误信息
- 在视图中统一处理验证错误
- 提供清晰的错误提示
- 验证规则可配置
- 支持多种验证类型
最后更新:2026-03-28