代码之家  ›  专栏  ›  技术社区  ›  Vivin Paliath

Javascript表单验证框架:审查请求

  •  14
  • Vivin Paliath  · 技术社区  · 14 年前

    我不确定我是否能问这样的问题,但在看到 this 在Meta Stackoverflow上,这类问题看起来没问题。好吧,关于我的问题:

    几个月前,我用Javascript编写了一个验证框架。我知道已经有了这样的验证框架 jQuery Validation ,但我想用不同的方法来验证。当前的方法是编写Javascript代码来对表单元素执行验证。通过查看表单源代码,无法立即看出每个元素上发生了什么验证。在某种程度上,这可以通过使用指定不同类型验证的CSS类来解决。但我觉得即使这样也很有限,因为您不能轻松地自定义validaton的行为(错误消息等)。我想在Java中使用 JSR-303 Bean Validation Hibernate Validator .

    因为HTML5允许您向元素添加自定义属性,所以我想我可以利用它来“注释”表单元素以进行验证。所以,基本上,我想到了这个:

    <input id = "myInput"
           name = "myInput"
           type = "text"
           class = "regula-validation"
           data-constraints = '@NotEmpty @IsNumeric @Between(min=1, max=5)' />
    

    基于这一基本思想,我创建了一个Javascript框架:

    • 检查DOM中定义了约束的元素,并将这些约束绑定到元素
    • 允许创建自定义约束
    • 允许对约束进行编程绑定
    • 验证绑定约束

    此外,该框架还具有以下特点:

    • 验证组,类似于JSR-303中指定的验证组
    • 错误消息插值

    一旦我创建了我的框架,我就试图获得反馈和评论,但我不知道该去哪里获得反馈和评论。我写了一些关于它的博客文章,并将其发布到Digg和Reddit(编程部分),但运气不太好。有几个人似乎很感兴趣,但我没有得到更多。

    最近,在我的工作场所,我们正在对遗留的代码库(JSP和servlet)进行现代化,并将其迁移到springmvc中。当谈到验证时,我向我的高级架构师介绍了我的框架。我做了一点集成和概念验证,他们似乎很感兴趣,并同意我将其添加到项目中。到目前为止,我只有我自己的拙见,这将是一个有用的方式做验证,所以这给了我一些信心,我的想法和框架可能有一些优点。然而,我仍然需要更多的参与和框架。在我发现Stackoverflow确实允许此类问题后,我决定将其发布在这里,以获得一些建设性的批评、评论和反馈。

    因此,我想毫不拖延地介绍一下 Regula . 我提供的链接指向GitHub上的wiki,其中包含框架的所有文档。您可以从下载最新版本(v1.1.0) here .

    期待您的评论。

    一些不直接相关的额外信息

    我曾经尝试过将我的框架与Spring集成的想法,即将bean上的验证注释转换为客户端验证。最近,我能够让这项工作,甚至与验证组(虽然目前没有在客户端支持组之间的继承关系)。这样,您只需使用验证约束注释字段属性,客户端验证代码就会自动生成。然而,我是一个Spring新手,所以我的方法可能不是那么干净。我想得到一些反馈,所以如果有人有兴趣请让我知道。理想的情况下(我希望我不是太自命不凡),我想联系Spring的人,看看他们是否对此感兴趣。

    2 回复  |  直到 8 年前
        1
  •  7
  •   Matthew Abbott    14 年前

    我已经很喜欢它了,它保持了我的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.NETMVC,看看它是如何将服务器端验证逻辑转换为客户端约束的。我可能在下个月左右再看。

        2
  •  0
  •   stopsopa    6 年前

    使用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