使用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);
生活实例
https://codesandbox.io/s/ymwky9603j