Bootstrap 验证冲突

Bootstrap validation conflicts

我正在使用 Vue.js 和 Bootstrap 来设计网站。我有一个表单,我正在尝试 运行 我的自定义验证。它工作正常,直到用户单击提交,根据 bootstrap 文档将 was-validated class 添加到表单。

此时,无论是否满足我的自定义验证,任何具有任何输入的必填输入字段都被标记为有效并获得绿色边框和复选标记。我的自定义验证仍在 运行 并正确显示 b-form-invalid-feedback。但是,似乎 was-validated 将具有所需道具的字段标记为有效,同时没有考虑我的自定义验证,这导致验证冲突,因为字段具有绿色复选标记(因为它满足所需的 属性) 但仍然是一条错误消息,因为根据我的自定义验证,它尚未生效。

我已经尝试删除 :valid 样式,这不是我想要的效果,因为我确实希望它在根据我的验证有效时显示这些样式。希望这是有道理的,否则我会提供图片。我还有第二个问题,即使添加了 was-validated,我的日期选择器也根本不显示 b-form-invalid-feedback

我的代码

<b-form @submit.prevent="addReview" name="review-form" novalidate>
  <div class="name">
    <label class="sr-only" for="form-input-name">Name</label>
    <b-input id="form-input-name" class="form-inputs mb-2 mr-sm-2 mb-sm-0" v-model="name" placeholder="Name" required :state="isStateValid(this.name)"></b-input>
    <b-form-invalid-feedback id="form-input-name">
      You must enter a name
    </b-form-invalid-feedback>
  </div>

  <div class="date">
    <label class="sr-only" for="example-datepicker">Choose a date</label>
    <b-form-datepicker id="datepicker" v-model="dateVisited" class="mb-2" required placeholder="Date Visited" :state="isStateValid(this.dateVisited)"></b-form-datepicker>
    <b-form-invalid-feedback id="datepicker">
      You must enter a valid date
    </b-form-invalid-feedback>
  </div>

  <div class="service">
    <label class="sr-only" for="form-input-service">Service Provided</label>
    <b-input id="form-input-service" class="form-inputs mb-2" placeholder="Service Provided" v-model="service" required :state="isStateValid(this.service)"></b-input>
    <b-form-invalid-feedback id="form-input-service">
      You must enter the service provided
    </b-form-invalid-feedback>
  </div>

  <div class="email">
    <label class="sr-only" for="inline-form-input-username">Email</label>
    <b-input id="inline-form-input-username" class="form-control mb-2 mr-sm-2 mb-sm-0" placeholder="Email" v-model="email" required :state="emailStateValidation"></b-input>
    <b-form-invalid-feedback id="inline-form-input-username">
      You must enter the part of your email that comes before the '@' symbol
    </b-form-invalid-feedback>
  </div>

  <div class="domain">
    <label class="sr-only" for="inline-form-input-domain">Domain</label>
    <b-input-group prepend="@" class="mb-2 mr-sm-2 mb-sm-0">
      <b-input id="inline-form-input-domain" placeholder="Domain ex: gmail.com" v-model="domain" required :state="domainStateValidation"></b-input>
      <b-form-invalid-feedback id="inline-form-input-domain">
        You must enter the part of your email that comes after the '@' symbol
      </b-form-invalid-feedback>
    </b-input-group>
  </div>

  <div class="description">
    <label class="sr-only" for="textarea-rows">Describe Your Experience</label>
    <b-form-textarea class="mb-3 mr-sm-2 mb-sm-0" id="textarea-rows" placeholder="Describe Your Experience" rows="4" required v-model="description" :state="isStateValid(this.description)"></b-form-textarea>
    <b-form-invalid-feedback id="textarea-rows">
      You must enter a description of your experience
    </b-form-invalid-feedback>
  </div>

  <b-button type="submit">Save</b-button>
</b-form>
computed: {
        emailStateValidation() {
            if (this.email) {
                return this.emailIsValid() ? true : false;
            }
            return null;
        },
        domainStateValidation() {
            if (this.domain) {
                return this.domainIsValid() ? true : false;
            }
            return null;
        },
    },
    methods: {
        emailIsValid() {
            let regEx = /^(?!.*@)((^[^\.])[a-z0-9\.!#$%&'*+\-\/=?^_`{|}~"]*)*([^\.]$)/;
            return regEx.test(this.email);
        },
        domainIsValid() {
            let regEx = /((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
            return regEx.test(this.domain);
        },
        isStateValid(variable) {
            if (variable) {
                return variable.length > 0 ? true : false;
            }
            return null;
        },
        addReview() {
            let mainForm = document.getElementsByName("review-form")[0];
            mainForm.classList.add("was-validated");
        ...

问题

  1. 解决required和my custom validation之间的冲突 导致输入字段被过早标记为有效
  2. 如果提交,则在表单提交的日期选择器上显示 b-form-invalid-feedback 未选择日期
  1. 根本上was-validated不是bootstrap-vue原生的,是浏览器原生的,对:state也没有理解。如果您想使用 was-validated,则不能使用自定义验证。如果你想使用自定义验证。请参阅建议 2。基本上,使用另一个变量来控制是否应应用验证。

  2. 来自 bootstrap-vue

    上的文档

When set, adds the aria-required="true" attribute on the component. Required validation needs to be handled by your application

您需要明确检查验证是否应该显示,文档中并不清楚 required 实际做了什么,但它不会影响验证。这解释了为什么那部分不起作用。就个人而言,我在提交时设置了一个全局 this.showValidations = true,这样验证实际上 运行 在正确的时间而不是之前(和预期的时间之后)。在您的情况下,您可以检查您明确添加的 was-validated class 。不是很好,但看来必须在这里完成。

简而言之,从 Vue 模板中的 <form> 中删除 novalidate。当您设置 novalidate 时,输入将在其整个生命周期中保持其 :valid 状态,直到您明确调用 setCustomValidityWorking Sandbox

因为,Bootstrap 样式也适用于 :valid:invalid 状态,所以,即使您的自定义验证器确定输入无效,有效和无效样式都将被应用,即:valid.is-invalid 但是,我猜它只是碰巧如此,:valid 样式优先于 Bootstrap 样式表当前编写的方式。

U̶s̶e̶ ̶̶n̶o̶v̶a̶l̶i̶d̶a̶t̶e̶̶ ̶w̶h̶e̶n̶ ̶y̶o̶u̶'̶r̶e̶ ̶i̶m̶p̶l̶e̶m̶e̶n̶t̶i̶n̶g̶ ̶a̶ ̶c̶o̶m̶p̶l̶e̶t̶e̶ ̶v̶a̶l̶i̶d̶a̶t̶i̶o̶n̶ ̶s̶o̶l̶u̶t̶i̶o̶n̶ ̶y̶o̶u̶r̶s̶e̶l̶f̶ ̶i̶n̶c̶l̶u̶d̶i̶n̶g̶ ̶̶r̶e̶q̶u̶i̶r̶e̶d̶̶ ̶v̶a̶l̶i̶d̶a̶t̶o̶r̶.̶

使用 Bootstrap,因为它还将样式应用于 :valid:invalid 输入状态,所以最好不要使用 novalidate .

当然,这将启用浏览器弹出窗口,要求填写某些可能不需要的字段。

建议:在你的表单上使用validated属性并将其绑定到你的表单状态并在addReview()中将其设置为true,它会自动添加 was-validated class 而你不需要直接操作 DOM.

编辑: 由于删除 novalidate 启用浏览器验证,submit 事件不再在表单上触发,因此,was-validated class 永远不会添加到表单中。这在我的原始答案中提出了一个问题,因为没有 was-validated 就不会显示消息和图标。我已经修改了沙箱以建议解决该问题,即绑定 click 事件以提交按钮以进行验证逻辑,并使用 submit 事件来处理成功验证后应该发生的事情。

编辑日期选择器:日期选择器从未失效的原因是isStateValid()方法中的一个问题,特别是部分:

if(variable) { // "" evaluates to false
   // ...
}

由于 "" 的计算结果为 false,因此它将始终 return null。对此的修复与上面关于维护表单的 validated 状态的建议相结合。现在,我们不检查 if(variable),而是检查 if(this.validated),如果它是 true,我们只需检查长度和 return truefalse ].