Form 表单

基本用法

<c-form @submit.prevent="onSubmit" ref="form">
  <c-form-item label="用户名:" required>
    <c-input v-model="userName" />
  </c-form-item>
  <c-form-item label="密码:" required>
    <c-input v-model="password" type="password" />
  </c-form-item>
  <c-form-item label=" ">
    <c-button primary type="submit">登录</c-button>
    <c-button type="button">忘记密码?</c-button>
  </c-form-item>
</c-form>

<script>
export default {
  data () {
    return {
      userName: '',
      password: ''
    }
  },
  methods: {
    onSubmit () {
      return this.$refs.form.isValid()
    }
  }
}
</script>

行内显示

<c-form inline>
  <c-form-item label="用户名" required>
    <c-input v-model="userName" />
  </c-form-item>
  <c-form-item label="密码" required>
    <c-input v-model="password" type="password" />
  </c-form-item>
</c-form>

<script>
export default {
  data () {
    return {
      userName: '',
      password: ''
    }
  }
}
</script>

设置表单尺寸

Clair 提供了一些属性让你可以定制标签和表单项的大小。

指定 label 宽度

c-form 组件上设置 label-width 属性即可设置 label 宽度,它的值可以是任何有效的 CSS 长度值。默认的 label 宽度为 4em

<c-form label-width="8em">
  <c-form-item label="目标网页URL:">
    <c-input />
  </c-form-item>
  <c-form-item label="转化目标名称:">
    <c-input />
  </c-form-item>
</c-form>

设置宽度和大小

Clair 中的某些表单控件提供了 sizewidth 属性来指定大小和宽度。你可以在 c-form 上统一为表单内的所有控件设置统一规格的尺寸。

normal

响应式布局

<c-form>
  <c-box>
    <c-box-item xs="12" sm="6" md="4">
      <c-form-item label="用户名" required flex>
        <c-input v-model="userName" width="flex" />
      </c-form-item>
    </c-box-item>
    <c-box-item xs="12" sm="6" md="4">
      <c-form-item label="密码" required flex>
        <c-input v-model="password" type="password" width="flex" />
      </c-form-item>
    </c-box-item>
  </c-box>
</c-form>

<script>
export default {
  data () {
    return {
      userName: '',
      password: ''
    }
  }
}
</script>

<style>
.c-form {
  font-size: 14px;
}
</style>

自定义 label

<c-form label-width="10em">
  <c-form-item>
    <c-icon name="globe" slot="label" />
    <c-input placeholder="公司地址" />
  </c-form-item>
  <c-form-item>
    <c-select :options="['手机', '座机']" width="shorter" slot="label" />
    <c-input placeholder="号码" />
  </c-form-item>
</c-form>

监听用户提交

<c-form @submit.prevent="onSubmit" ref="form">
  <c-form-item label="用户名" required>
    <c-input v-model="userName" />
  </c-form-item>
  <c-form-item label="密码" required>
    <c-input v-model="password" />
  </c-form-item>
  <c-form-item label=" ">
    <c-button type="submit" primary>登录</c-button>
  </c-form-item>
</c-form>

<script>
export default {
  data () {
    return {
      userName: '',
      password: ''
    }
  },
  methods: {
    onSubmit (e) {
      const form = this.$refs.form
      if (form.isValid()) {
        alert('登录成功')
        form.resetValidity()
        this.userName = ''
        this.password = ''
      }
    }
  }
}
</script>

输入验证

Clair 内置了输入验证的功能,可以对用户的输入实时进行校验,并给出错误提示。验证规则通过 rules 属性指定,它的值是一个对象。

required 必填验证

<c-input v-model="userName" :rules="rules" />

<script>
  export default {
    data() {
      return {
        userName: '删了我试试~',
        rules: {
          required: true
        }
      }
    }
  }
</script>

使用 minlength 和 maxlength 验证输入长度

<c-input v-model="userName" :rules="rules" placeholder="输入2到8位字符" />

<script>
  export default {
    data() {
      return {
        userName: '',
        rules: {
          required: true,
          minlength: 2,
          maxlength: 8
        }
      }
    }
  }
</script>

常用数据格式验证

一些常用的数据格式,比如邮箱、URL、手机号码等,可以通过指定 type 来验证。

<div class="form-item">
  <c-input v-model="mail" :rules="{type: 'email'}" placeholder="邮箱" />
</div>

<div class="form-item">
  <c-input v-model="mobile" :rules="{type: 'mobile'}" placeholder="手机号" />
</div>

<script>
  export default {
    data() {
      return {
        mail: '',
        mobile: ''
      }
    }
  }
</script>

<style>
.form-item {
  margin-bottom: 1em;
}
</style>

Clair 目前支持验证的 type 有:

  • email:邮箱
  • mobile:手机号码
  • tel:固定电话号码
  • number:数字
  • integer:整数

正则表达式验证

用来验证用户输入是否符合通过 pattern 属性指定的正则表达式。例如:

<c-input v-model="id" :rules="rules" placeholder="请输入六位数字" />

<script>
  export default {
    data() {
      return {
        id: '',
        rules: {
          pattern: /^\d{6}$/
        }
      }
    }
  }
</script>

自定义错误提示

在指定规则时,可以通过给规则对象添加 msg 属性来实现自定义消息。

<c-input v-model="id" :rules="rules" placeholder="2-6个字" />

<script>
  export default {
    data() {
      return {
        id: '',
        rules: {
          required: true,
          minlength: 2,
          maxlength: 6,
          msg: '请输入2-6个字符哦~'
        }
      }
    }
  }
</script>

在上面的例子中,不管发生了哪种类型的格式错误,都会显示固定的错误消息。你也可以针对不同类型的错误,显示不同的消息:

<c-input v-model="id" :rules="rules" placeholder="2-6个字" />

<script>
  export default {
    data() {
      return {
        id: '',
        rules: {
          required: true,
          minlength: 2,
          maxlength: 6,
          msg: {
            required: '不填可不行哦~',
            minlength: '一个字太少了吧~',
            maxlength: '不能超过6个字~'
          }
        }
      }
    }
  }
</script>

手动调用验证

如果你想通过 JavaScript 获取到某个输入框的输入有效性,可以获取到 c-input 组件的引用,然后调用该组件的 validate 方法。

该方法返回结果是一个对象,包括 validmsg 两个字段,分别表示是否合法以及错误提示。

<c-input v-model="id" :rules="rules" placeholder="请输入六位数字" ref="input" />
<c-button @click="onClick" primary>检查输入有效性</c-button>

<script>
  export default {
    data() {
      return {
        id: '',
        rules: {
          required: true,
          pattern: /^\d{6}$/
        }
      }
    },
    methods: {
      onClick: function(e) {
        var validity = this.$refs.input.validate();
        if (validity.valid) {
          alert('输入正确');
        } else {
          alert('输入错误:' + validity.msg)
        }
      }
    }
  }
</script>

自定义验证规则

除了 Clair 内置的验证规则之外,你也可以自定义验证规则。只需要提供一个规则名和一个验证函数即可。验证函数的参数为用户输入的值,如果验证失败,返回 { valid: false, msg: '错误提示内容' };验证通过则返回 { valid: true } 即可。

在自定义验证函数中,可以使用 this 访问触发验证的 Vue 组件实例。

设置密码:
设置密码:<c-input v-model="password" :rules="rules" />

<script>
  export default {
    data () {
      return {
        password: '',
        rules: {
          required: true,
          minlength: 6,
          strength: function (val) {
            console.log(this) // this 是 c-input 实例
            const hasNumber = /\d/.test(val)
            const hasLetter = /[a-z]/i.test(val)
            const hasSpecialChar = /\W/.test(val)
            if (hasNumber && hasLetter && hasSpecialChar) {
              return { valid: true }
            } else {
              return { valid: false, msg: '密码中必须包含数字、字母和特殊符号' }
            }
          }
        }
      }
    }
  }
</script>

异步验证

某些情况下,输入的验证过程是异步的(比如需要调用服务器端接口去验证)。你可以自定义一个异步的验证函数,让这个函数返回一个 Promise 即可。

对于需要访问 HTTP 接口进行异步校验的场景,我们通常需要对验证函数进行节流处理。通过 validate-throttle 属性可以指定进行验证的最小时间间隔。

<c-input v-model="user" :rules="rules" placeholder="请输入用户名" :validate-throttle="500" />

<script>
  const rules = {
    available: function (val) {
      console.log(`validating value ${val}`)
      return new Promise((resolve, reject) => {
        // 这里模拟一个异步验证
        setTimeout(() => {
          const valid = val.length > 3
          const msg = valid ? '' : `用户名 ${val} 被占用`
          resolve({ valid, msg })
        }, 1000 * Math.random())
      })
    }
  }

  export default {
    data () {
      return { user: '', rules }
    }
  }
</script>

验证整个表单

每个表单项在用户操作过程中会实时验证并给出错误提示。如果要验证整个表单是否全部填写正确,可以调用表单组件的 validate() 方法。该方法会返回 truefalse

注意:如果表单项中含有异步验证,那么 validate() 方法会返回一个 Promise。这个 Promiseresolve 之后才能知道验证结果是 true 还是 false

如果要重置表单的验证结果,也就是清除错误提示,可以调用表单的 resetValidity() 方法。另外,表单还有一个 reset() 方法,可以将表单重置为用户修改之前的状态,同时清除错误提示。reset() 是重置表单项为初始值,而不是清空其内容。

请选择...
    <c-form @submit.prevent="onSubmit" ref="form" label-width="6em" width="long">
      <c-form-item label="任务名称:" required>
        <c-input v-model="name" :rules="rules.name" />
      </c-form-item>
      <c-form-item label="统计时段:" required>
        <c-checkbox-group
          v-model="timespan"
          :options="[
            { label: '最近7天', value: 1 },
            { label: '最近14天', value: 2 },
            { label: '最近30天', value: 3 },
            { label: '自然月', value: 4 },
            { label: '自然季', value: 5 }
          ]"
        />
      </c-form-item>
      <c-form-item label="移动端:" required>
        <c-switch v-model="hasMobile" />
      </c-form-item>
      <c-form-item label="移动版本:" required v-if="hasMobile">
        <c-input v-model="version" :rules="rules.version" />
      </c-form-item>
      <c-form-item label="开始日期:" required>
        <c-datepicker v-model="startDate" />
      </c-form-item>
      <c-form-item label="运行范围:" required>
        <c-datepicker type="daterange" v-model="range" />
      </c-form-item>
      <c-form-item label="发送周期:" required>
        <c-radio-group
          button
          :options="[
            { label: '每天', value: 1 },
            { label: '每周', value: 2 },
            { label: '每月', value: 3 },
          ]"
          v-model="frequency"
        />
      </c-form-item>
      <c-form-item label="地域:" required>
        <c-select
          :options="[
            { label: '东北', value: 1 },
            { label: '华北', value: 2 },
            { label: '西北', value: 3 },
            { label: '华中', value: 4 },
            { label: '华南', value: 5 },
            { label: '华东', value: 6 },
            { label: '西南', value: 7 }
          ]"
          v-model="zone"
        />
      </c-form-item>
      <c-form-item label="每页条数:" required>
        <c-slider v-model="num" />
      </c-form-item>
      <c-form-item label=" ">
        <c-button type="submit" primary>生成报告</c-button>
        <c-button type="button" @click.prevent="onReset">重置表单</c-button>
      </c-form-item>
    </c-form>
    
    <script>
    export default {
      data () {
        return {
          name: '',
          timespan: [2],
          hasMobile: false,
          startDate: '',
          range: [],
          frequency: 1,
          zone: '',
          num: 10,
          version: '',
          rules: {
            name: {
              checkavailable (name) {
                return new Promise((resolve, reject) => {
                  setTimeout(() => {
                    resolve({
                      valid: name.length > 3,
                      msg: '任务名称已经存在'
                    })
                  }, Math.random() * 1000)
                })
              }
            },
            version: {
              pattern: /^\d{2,6}$/,
              required: true
            }
          }
        }
      },
      methods: {
        onSubmit (e) {
          const form = this.$refs.form
          form.isValid().then(valid => {
            if (!valid) return
            alert('提交成功')
            form.reset()
          })
        },
        onReset (e) {
          this.$refs.form.reset()
        }
      }
    }
    </script>
    

    扩展表单组件

    在复杂的业务场景下,我们需要自定义表单组件,这些组件可以使用 v-model 进行双向绑定

    Clair 也提供了一些方法,让你开发的自定义组件也可以使用 Clair 的表单验证机制。

    import Clair from clair
    
    /**
     * 自定义表单组件使用Clair的表单验证系统
     */
    Vue.component('fancy-input', {
      mixins: [Clair.mixins.validatable],
      props: ['value'],
      data () {
        return {
          // 这里可以内置一些验证规则
          builtinRules: {
            ruleA (val) {
              // ...
            }
          }
        }
      }
      // ...
    })
    
    /**
     * 使用 `rules` 属性传入验证规则
     */
    new Vue({
      el: '#app',
      template: '<fancy-input v-model="val" :rules="rules">',
      data () {
        return {
          val: '',
          rules: {
            required: true,
            maxLength: 12
          }
        }
      }
    })
    

    属性说明

    c-form 属性

    属性 类型 默认值 说明
    inline Boolean false 是否将表单项在一行内显示
    labelWidth String 4em 标签宽度,可以为任何有效的 CSS 长度
    size String md 表单中的控件尺寸,可以取 xs sm md lg xl
    width String normal 表单中的控件宽度,可以取 shortest shorter short normal long longer longest

    c-form-item 属性

    属性 类型 默认值 说明
    label String 标签
    labelWidth String 4em 标签宽度,可以为任何有效的 CSS 长度
    required Boolean false 是否必填项

    c-form 事件

    事件名 参数 说明
    submit Event 原生的表单提交事件