我不确定我是否可以提出这样的问题,但在Meta Stackoverflow上看到this后,看起来这样的问题还可以。好吧,在我的问题上:
几个月前,我在Javascript中编写了一个验证框架。我知道已存在像jQuery Validation这样的验证框架,但我想采用不同的验证方法。当前的方法涉及编写Javascript代码以对表单元素执行验证。通过查看表单源代码,不会立即明确在每个元素上进行验证。在某种程度上,这可以通过使用指定不同类型的验证的CSS类来解决。但我觉得即使这样也是有限的,因为你无法轻松定制验证的行为(错误消息等)。我希望使用JSR-303 Bean Validation或Hibernate Validator在Java中执行基于注释的验证。
由于HTML5允许您向元素添加自定义属性,我认为我可以利用它来“注释”表单元素以进行验证。所以,基本上,我想出了这个:
<input id = "myInput"
name = "myInput"
type = "text"
class = "regula-validation"
data-constraints = '@NotEmpty @IsNumeric @Between(min=1, max=5)' />
考虑到这个基本想法,我创建了一个Javascript框架:
此外,该框架具有以下功能:
一旦我创建了我的框架,我就会尝试获得反馈并对其进行审核,但我不知道该去哪里获得反馈和审核。我写了一些关于它的博客文章并将其发布到Digg和Reddit(编程部分),没有太多运气。有些人似乎很感兴趣,但我没有得到更多。
最近,在我的工作场所,我们一直在对遗留代码库(JSP和servlet)进行现代化,并将其转移到Spring MVC中。当验证对话出现时,我将我的框架投给了我的高级架构师。我做了一点整合和概念验证,他们似乎很感兴趣,并让我继续将它添加到项目中。直到现在,我只有自己的拙见,这将是一种有用的验证方式,所以这让我有信心我的想法和框架可能有一些优点。但是,我仍然需要更多的参与和框架。在我发现Stackoverflow确实允许这些问题之后,我决定将它发布在这里以获得一些建设性的批评,评论和反馈。
所以我没有任何延迟,我想介绍Regula。我提供的链接转到GitHub上的wiki,其中包含该框架的所有文档。您可以从here下载最新版本(v1.1.0)。
期待您的意见。
一些不直接相关的额外信息
我曾经想过将我的框架与Spring集成,即将bean上的验证注释转换为客户端验证。最近我能够使这个工作,即使有验证组(虽然目前没有支持客户端组之间的继承关系)。这样,您只需使用验证约束来注释字段属性,并自动生成客户端验证代码。但是,我是一个春天的新手,所以我的方法可能不那么干净。我想得到一些反馈,所以如果有人有兴趣请告诉我。理想情况下(我希望我不会太自命)我想联系春天的人,看看他们是否对此感兴趣。
答案 0 :(得分:7)
我已经非常喜欢它了,它使我的html保持干净,并且构建自定义验证器的能力非常好。我添加的一件事是绑定验证和提交函数的简写,并将其包装为jQuery插件:
if (jQuery) {
(function($)
{
$.regula = function(formId, callback)
{
regula.bind();
$("#" + formId).submit(function()
{
var validationResults = regula.validate();
if (validationResults.length > 0)
{
if (callback)
callback(validationResults);
return false;
}
return true;
});
};
})(jQuery);
}
事实上,我只是blogged关于它,因为我对它的干净和轻松印象深刻。我仍然会花时间浏览你的来源,看看你是如何完成它的,但它是一个很好的开始:)
关于集成框架,我主要使用ASP.NET MVC,看看它如何将服务器端验证逻辑转换为客户端约束将会很有趣。我可能会在接下来的一个月左右看一下。
答案 1 :(得分:0)
我正在使用完全不同的方法: 使用像React或Angular这样的现代框架,您始终会在javascript中的某个位置保持表单状态,而不是DOM输入状态(DOM只是数据的视图层)。而且我认为应该是这样的,因为无论您使用哪种华丽的组件来构建表单,都始终在对象下面包含所有状态。从这点到我,自然的方法是只使用原始JSR-303(不带注释)来验证该对象(因为JSR-303为您提供了这种灵活性)并将错误填充回DOM。让我给你看一个例子:
import React, { Component } from "react";
import ReactDOM from "react-dom";
import validator, {
Collection,
All,
Required,
Optional,
NotBlank,
Length,
Email
} from "@stopsopa/validator";
class App extends Component {
constructor(...args) {
super(...args);
this.state = {
data: {
name: "",
email: "",
comments: []
},
errors: {},
validate: false
};
}
onSubmit = async e => {
e.preventDefault();
const errors = await validator(
this.state.data,
new Collection({
name: new Required([new NotBlank(), new Length({ min: 3 })]),
email: new Required([new NotBlank(), new Email()]),
comments: new All([new NotBlank(), new Length({ min: 10 })])
})
);
this.setState({
errors: errors.getTree(),
validate: true
});
if (!errors.count()) {
console.log("send data to server", this.state.data);
}
};
onChange = (name, value) => {
console.log(name, value);
this.setState(state => ({
...state,
data: { ...state.data, ...{ [name]: value } }
}));
};
addComment = () =>
this.setState(state => {
const comments = state.data.comments;
comments.push("");
const newState = { ...state };
newState.data.comments = comments;
return newState;
});
deleteComment = i =>
this.setState(state => {
const newState = { ...state };
state.data.comments.splice(i, 1);
return newState;
});
editComment = (i, value) => {
this.setState(state => {
const newState = { ...state };
state.data.comments[i] = value;
return newState;
});
};
render() {
const s = this.state;
console.log("state", JSON.stringify(s, null, 4));
return (
<form onSubmit={this.onSubmit}>
<label>
name:
<input
value={s.data.name}
onChange={e => this.onChange("name", e.target.value)}
/>
</label>
{s.validate && s.errors.name && (
<div className="error">{s.errors.name}</div>
)}
<br />
<label>
email:
<input
value={s.data.email}
onChange={e => this.onChange("email", e.target.value)}
/>
</label>
{s.validate && s.errors.email && (
<div className="error">{s.errors.email}</div>
)}
<div>
comments:{" "}
<a onClick={this.addComment} href="javascript:void(0)">
add
</a>
{s.data.comments.map((m, i) => (
<div style={{ border: "1px solid red" }} key={i}>
<textarea
rows="2"
value={m}
onChange={e => this.editComment(i, e.target.value)}
/>
<a
onClick={() => this.deleteComment(i)}
href="javascript:void(0)"
>
delete
</a>
{s.validate && s.errors.comments && s.errors.comments[i] && (
<div className="error">{s.errors.comments[i]}</div>
)}
</div>
))}
</div>
<br />
<input type="submit" value="submit" />
</form>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);