首页 > 解决方案 > 如何使用 Vue.js 进行表单向导进行验证

问题描述

我正在使用 Vue.Js 做一个小项目,我按照视频教程创建向导,但现在我尝试使用我已经创建的两个 css 类来验证表单'is-valid'和'is-invalid ' 但我的验证不起作用,这是我的代码

<div class="modal-content tx-14">
              <div class="p-0 bg-ui-01">
                 <ul class="nav nav-tabs nav-justified" id="myTab3" role="tablist">
                    <li class="nav-item m-0">
                       <a class="nav-link border-0 rounded-0" id="home-tab3" data-toggle="tab" href="#home3" role="tab" aria-controls="home" aria-selected="true" :class="{'active':current_step == 1}" @click.prevent="goToStep(1)">Website</a>
                    </li>
                    <li class="nav-item m-0">
                       <a class="nav-link border-0 rounded-0" id="profile-tab3" data-toggle="tab" href="#profile3" role="tab" aria-controls="profile" aria-selected="false" :class="{'disabled':max_step < 2, 'active': current_step == 2}" @click.prevent="goToStep(2)">Location</a>
                    </li>
                    <li class="nav-item m-0">
                       <a class="nav-link border-0 rounded-0" id="contact-tab3" data-toggle="tab" href="#contact3" role="tab" aria-controls="contact" aria-selected="false" :class="{'disabled':max_step < 3, 'active': current_step == 3}" @click.prevent="goToStep(3)">Keywords</a>
                    </li>
                    <li class="nav-item m-0">
                       <a class="nav-link border-0 rounded-0" id="contact-tab3" data-toggle="tab" href="#contact4" role="tab" aria-controls="contact" aria-selected="false" :class="{'disabled':max_step < 4, 'active': current_step == 4}" @click.prevent="goToStep(4)">Crawler</a>
                    </li>
                    <li class="nav-item m-0">
                       <a class="nav-link border-0 rounded-0" id="contact-tab3" data-toggle="tab" href="#contact4" role="tab" aria-controls="contact" aria-selected="false" :class="{'disabled':max_step < 5, 'active': current_step == 5}" @click.prevent="goToStep(5)">Competition</a>
                    </li>
                 </ul>
              </div>
              <div class="modal-body">
                 <div class="tab-content" id="myTabContent">
                    <div class="fade show active" id="home" role="tabpanel" aria-labelledby="home-tab" v-show="current_step == 1">
                       <h4 class="text-center">Create Your Project</h4>
                       <p class="text-center">Enter your website informations, so you can track and improve your SEO traffic and keep an eye on the competition.</p>
                       <div class="row row-sm">
                          <div class="col-sm-12">
                             <div class="form-group">
                                <input type="url" id="project_url" v-model="rules.project_url.string" class="form-control" placeholder="Project URL">
                             </div>
                          </div>
                          <div class="col-sm-12">
                             <div class="form-group">
                                <input type="text" class="form-control" id="project_name" v-model="rules.project_name.string" placeholder="Project name">
                             </div>
                          </div>
                       </div>
                    </div>
                    <div id="location" role="tabpanel" aria-labelledby="profile-tab" v-show="current_step == 2">
                       <h4 class="text-center">Choose Your Location</h4>
                       <p class="text-center">
                          Enter all of the countries or cities you do business in or want traffic from. We recommend that you add at least 3 locations.
                       </p>
                       <div class="row row-sm">
                          <div class="col-sm-4">
                             <div class="form-group">
                                <select class="custom-select">
                                   <option selected>Select Engine</option>
                                   <option value="1">Google</option>
                                   <option value="2">Google Mobile</option>
                                </select>
                             </div>
                          </div>
                          <div class="col-sm-8">
                             <div class="form-group">
                                <input type="text" class="form-control" placeholder="Target Location">
                             </div>
                          </div>
                       </div>
                       <div class="row row-sm">
                          <div class="col-sm-4">
                             <div class="form-group">
                                <select class="custom-select">
                                   <option selected>Select Engine</option>
                                   <option value="1">Google</option>
                                   <option value="2">Google Mobile</option>
                                </select>
                             </div>
                          </div>
                          <div class="col-sm-8">
                             <div class="form-group">
                                <input type="text" class="form-control" placeholder="Target Location">
                             </div>
                          </div>
                       </div>
                    </div>
                    <div id="keywords" role="tabpanel" aria-labelledby="contact-tab" v-show="current_step == 3">
                       <h4 class="text-center">Add Keywords</h4>
                       <p class="text-center">
                          Choose the keywords you would like to track across the selected search engines. Track on the national level, or add locations to track on the local level. Add labels to group keywords by topic.
                       </p>
                       <textarea class="form-control" cols="30" rows="10" placeholder="Add separated keywords by comma ex: pasta,fish"></textarea>
                    </div>
                    <div id="crawling" role="tabpanel" aria-labelledby="contact-tab" v-show="current_step == 4">
                       <h4 class="text-center">Set Crawl Limit</h4>
                       <p class="text-center">
                          We crawl your site weekly to surface technical site issues that may be impacting your SEO performance. Select the number of pages you’d like to have crawled on this site.
                       </p>
                       <div class="row row-sm">
                          <div class="col-sm-4">
                             <div class="form-group">
                                <select class="custom-select">
                                   <option value="5000">5,000</option>
                                   <option value="10000">10,000</option>
                                   <option value="20000">20,000</option>
                                   <option value="30000">30,000</option>
                                   <option value="40000">40,000</option>
                                   <option value="50000">50,000</option>
                                   <option value="75000">75,000</option>
                                   <option value="100000">100,000</option>
                                   <option value="250000">250,000</option>
                                   <option value="450000">450,000</option>
                                </select>
                             </div>
                          </div>
                          <div class="col-sm-8">
                             <div class="form-group">
                                <select class="custom-select">
                                   <option selected>Whole Website</option>
                                   <option value="1">Exclude sub-domains</option>
                                   <option value="2">Follow sitemap</option>
                                </select>
                             </div>
                          </div>
                       </div>
                    </div>
                    <div id="crawling" role="tabpanel" aria-labelledby="contact-tab" v-show="current_step == 5">
                       <h4 class="text-center">Benchmark vs Competitors</h4>
                       <p class="text-center">
                          We will track competitive link and keyword metrics for these sites.
                       </p>
                       <div class="row row-sm">
                          <div class="col-sm-12">
                             <div class="form-group">
                                <input type="text" class="form-control" placeholder="Target Location">
                             </div>
                          </div>
                          <div class="col-sm-12">
                             <div class="form-group">
                                <input type="text" class="form-control" placeholder="Target Location">
                             </div>
                          </div>
                          <div class="col-sm-12">
                             <div class="form-group">
                                <input type="text" class="form-control" placeholder="Target Location">
                             </div>
                          </div>
                          <div class="col-sm-12">
                             <div class="form-group">
                                <input type="text" class="form-control" placeholder="Target Location">
                             </div>
                          </div>
                       </div>
                    </div>
                 </div>
              </div>
              <div class="modal-footer">
                 <button type="button" class="btn btn-secondary tx-13" data-dismiss="modal">Close</button>
                 <button type="button" class="btn btn-primary tx-13" @click="advanceStep">
                 <span v-if="max_step === 5">Submit</span>
                 <span v-else>Next</span>  
                 </button>
              </div>
           </div>

Javascript

    <script>
   new Vue({
       el: "#page",
       delimiters: ['[[', ']]'],
         data (){
            return {
               rules: {
                  project_url: {
                     pattern: /^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$/,
                     string: ''
                  },
                  project_name: {
                     pattern: /^(?!\s*$).+/,
                     string: ''
                  }
               },
               current_step: 1,
               max_step: 1
            }
        },
        methods:{
            is_valid(rules){
               $.each(rules, function(index, value){
                  if (value.string.match(value.pattern)) {
                     $('#' + index).removeClass('is-invalid')
                     $('#' + index).addClass('is-valid')
                     nextStep =  true
                  } else {
                     $('#' + index).removeClass('is-valid')
                     $('#' + index).addClass('is-invalid')
                     nextStep =  false
                  }
               })
               return nextStep
            },
            validate(){
               if(this.current_step === 1){
                  if(this.is_valid(this.rules))
                     return true
               }
                if(this.current_step === 2)
                    return true
                if(this.current_step === 3)
                    return true
                if(this.current_step === 4)
                    return true
                if(this.current_step === 5)
                    return true
            },
            goToStep(value){
               if(!this.validate())
                  return
               this.current_step = value
            },
            submitForm(){
                alert("submit")
            },
            advanceStep(){
                if(!this.validate())
                    return
    
                if(this.max_step === 5)
                    return this.submitForm()
    
                this.current_step++
    
                if(this.max_step < this.current_step)
                    this.max_step = this.current_step
            }
        }
    })
</script>

谁能清理我的代码并帮助我添加表单验证

标签: javascriptvue.js

解决方案


基本思想是您不验证表单本身,而是验证表单中显示的数据。

您可能会认为“但它们是相同的”或“这是一个细微的区别”,但不是。

使用jQuery,您正在浏览表单 UI - 应用程序的一部分,这是许多其他事情的最终结果。不要那样做。将表单数据存储在Vue的 data 选项中,并且只显示验证结果。

Vue.component('InputField', {
  props: ['error', 'value'],
  computed: {
    inputValue: {
      get() {
        return this.value
      },
      set(val) {
        this.$emit("update:value", val)
      }
    },
  },
  template: `
    <div
      class="input-field-wrapper"
      :class="{ error: error }"
    >
      <label>
        INPUT: 
        <input
          type="text"
          placeholder="Type in something"
          v-model="inputValue"
        />
        <span v-if="error">this field is required!</span>
      </label>
    </div>
  `
})

new Vue({
  el: "#app",
  data() {
    return {
      form: [],
      canSubmit: false,
    }
  },
  methods: {
    handleAddInput(id) {
      this.form.push({
        id,
        error: null,
        value: null,
      })
    },
    handleFormValidate() {
      this.form = this.form.map(({ id, error, value }) => {
        return {
          id,
          error: !value,
          value,
        }
      })
      return this.form.every(({
        error
      }) => !error)
    },
    handleResetValidation() {
      this.form = this.form.map(field => {
        return {
          ...field,
          error: false
        }
      })
    },
    handleSubmitForm() {
      this.canSubmit = this.handleFormValidate()
    },
  },
  template: `
    <div>
      <button
        @click="handleAddInput(form.length + 1)"
      >ADD INPUT FIELD +</button>
      <button
        @click="handleFormValidate"
      >VALIDATE FORM</button>
      <button
        @click="handleResetValidation"
      >RESET VALIDATION</button>
      <hr />
      <form>
        <input-field
          v-for="(inputField, i) in form"
          :key="inputField.id"
          :error="inputField.error"
          :value.sync="inputField.value"
        ></input-field>
        <hr />
        <button type="submit" @click.prevent="handleSubmitForm">SUBMIT FORM</button>
      </form>
      FORM CAN BE SUBMITTED: {{ canSubmit }}
    </div>
  `
})
.input-field-wrapper {
  padding: 8px 16px;
  color: black;
}
.input-field-wrapper.error {
  color: white;
  background: red;
  transition: all 0.1s;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>

这个怎么运作

上面的代码片段非常简单:

  • 它有 data 属性 ( form) 存储我们想要通过表单获取的所有数据和非常重要的错误状态
  • ADD INPUT FIELD +form属性中推送一个新对象
  • 模板为它在data 属性InputField中找到的每个对象呈现一个组件form
  • InputField组件实际上什么都不做,只呈现一个文本输入元素(带有错误类,如果输入字段未验证)并将文本输入的值发送回父级(以便可以将其存储在其form数据中)
  • VALIDATE FORM上,我们循环遍历form数据,检查value每个元素,并设置errorifvalue不验证(这里的规则是一个简单的“它是否有值?”,但可以进行任何验证)。状态在组件 ( )error上向下传递,并且该组件立即对状态更改做出反应InputField:error="inputField.error"
  • SUBMIT FORM上,我们运行验证方法并输出验证结果(它可能是实际提交表单的一个守卫)
  • RESET VALIDATION我们清除每个form项目的错误状态(从而重置InputFields组件中的错误显示)

您可以看到,如果您以“数据驱动”方式设置组件,则无需直接接触 DOM(这是非常罕见的,您确实无法避免通过合理的工作量来干预 DOM) . 如果你将数据和 UI 解耦,你就有更多的自由来制定应用程序的逻辑。

而且你不需要jQuery来完成这项工作。


推荐阅读