美文网首页
vue 如何写插件、自己写一个表单验证插件

vue 如何写插件、自己写一个表单验证插件

作者: milletmi | 来源:发表于2018-10-16 14:58 被阅读0次

    一般我们用vue的时候,有很多好用的插件,我们npm安装一下就可以用了,但是像表单验证这种的很难找到自己心仪的插件,和自己的网站交互也不一样,还需要修改一下,而且文件很大,不如自己手写一个了,只要自己需要的功能,可能写的不好,提出意见

    在我们开始写插件之前要好好看看vue官方文档,了解下面几个API
    1、 Vue.directive( id, [definition] )
    参数:

    {string} id
    {Function | Object} [definition]
    用法:

    注册或获取全局指令。


    image.png
    image.png
    image.png
    image.png

    2、好好看看文档的这里 ---->插件
    下面我们开始写一个验证的插件

    validator.js 定义插件


    /**
     * 默认规则:
     * 1、不为空
     * 2、电话号码校验
     * 3、邮箱校验
     */
    // 默认规则正则表
    let regList = {
      required: true,
      Mobile: /^1[3|4|5|7|8]\d{9}$/,
      Mail: /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/
    }
    // 默认规则错误信息
    let msgList = {
      required: '必填',
      Mobile: '请输入正确的手机号',
      Mail: '请输入正确的邮箱'
    }
    // 规则构造器
    function Rule (ruleName, ruleValue, ruleMsg) {
      this.ruleName = ruleName
      this.ruleValue = ruleValue
      this.msg = ruleMsg
    }
    // 挂在vue实例上面$va
    function createVa (vm, domSelector) {
      let va = {
        ruleListRank: [],
        forms: {},
        checkRule: checkRule,
        checkAll: checkAll
      }
      if (vm.$va) {
        return vm.$va
      } else {
        vm.$va = va
        return vm.$va
      }
    }
    // va构造器挂在vue实例上面$va的forms上面
    function VaForm (el, finalRule) {
      this.dom = el
      this.rules = finalRule
    }
    // 断言函数
    function assert (condition, message) {
      if (!condition) {
        console.error('[validator-warn]:' + message)
      }
    }
    // 挂载va上的方法================================================>
    // 校验表单的全部字段
    function checkAll () {
      let ruleListRank = this.ruleListRank
      let forms = this.forms
      let checkRule = this.checkRule
      let checkFlag = true
      for (let name of ruleListRank) {
        let dom = forms[name].dom
        let rules = forms[name].rules
        let flag = checkRule(dom, rules)
        if (flag === false) {
          checkFlag = flag
        }
      }
      return checkFlag
    }
    // 校验表单的一个字段的第一个报错信息
    function checkRule (dom, rules) {
      let ruleCheckers = {
        required: checkEmpty,
        reg: checkReg
      }
      for (let rule of rules) {
        let {ruleName, ruleValue, msg} = rule
        let checkResult
        if (typeof ruleValue === 'function') {
          checkResult = ruleValue()
        } else {
          checkResult = ruleCheckers[ruleName]
            ? ruleCheckers[ruleName](ruleValue, dom)
            : ruleCheckers.reg(ruleValue, dom)
        }
    
        if (!checkResult) {
          setError(dom, msg, 'add')
          return false
        }
      }
      setError(dom, '', 'remove')
      return true
    }
    // 表单验证的方法================================================>
    // 检测非空
    function checkEmpty (ruleValue, vaForm, va) {
      return vaForm.value.trim() !== ''
    }
    // 检测正则
    function checkReg (ruleValue, vaForm, va) {
      return ruleValue.test(vaForm.value)
    }
    /**
     * 设置错误的方法
     * @param {*} dom 当前dom元素
     * @param {*} msg 报错信息
     * @param {*} type 是添加报错信息还是移除
     */
    function setError (dom, msg, type) {
      if (dom.parentNode.classList) {
        if (type === 'add') {
          dom.parentNode.classList.add('error_item')
        } else {
          dom.parentNode.classList.remove('error_item')
        }
      }
      dom.nextElementSibling.innerHTML = msg
    }
    let installed = false
    function plugin (Vue, options) {
      if (installed) {
        assert(installed, 'already installed')
        return
      }
      Vue.directive('validator', {
        bind: function (el, binding, vnode) {
          let vm = vnode.context // 基本的校验规则
          let finalRule = [] // 最终的校验规则
          let domSelector = binding.arg === undefined ? el.getAttribute('id') : binding.arg
          let options = binding.value ? binding.value : []// 特殊配置(允许非空,编辑新增共用等)
          assert(domSelector, 'not set id or binding.arg')
          let va = createVa(vm, domSelector)// 单例模式创建va,绑定在vm上
          va.ruleListRank.push(domSelector)// 表单检验的顺序
          for (let option of options) {
            if (typeof option === 'object') {
              // 用户自定义的校验规则
              let ruleName = Object.keys(option)[0]
              let ruleValue = option[ruleName] ? option[ruleName] : regList[ruleName]
              assert(ruleValue, domSelector + " selector's " + ruleName + ' not set verification mode')
              finalRule.push(new Rule(ruleName, ruleValue, option.msg))
            } else {
              // 配置项定义的校验规则
              if (regList[option]) {
                finalRule.push(new Rule(option, regList[option], msgList[option]))
              }
            }
          }
          let vaForm = new VaForm(el, finalRule)
          va.forms[domSelector] = vaForm
        }
      })
      installed = true
    }
    // 自动注册vue
    if (typeof window !== 'undefined' && window.Vue) {
      window.Vue.use(plugin)
    }
    export default {
      install: plugin
    }
    
    

    API文档


    vue template结构外层嵌套input_item里面有一个class为error的p标签

        <div class="input_item">
           <label for="password">{{$t('login.password.name')}}</label>
           <input class="error-content" type="password" id="password" v-model="password" :placeholder="$t('login.password.name')" autocomplete="off" tag="密码" v-validator:password= "validatePassword" >
           <p class="error"></p>
       </div>
    
    /**
     * @param {*} type   reg(正则), required(必填),Mobile(电话),Mail(邮件),type 
        填写其他的话默认按照正则
     * @param {*} typeVal 根据不同type设置不同的值,正则表达式,type类型为 
        Mobile、required、Mail 的可以写true,false ,还有function
     * @param {*} errMsg 自定义的报错信息
     * 设置了三种规则:
     * 1.选项规则: 通过Vue指令的修饰符添加的规则。v-validator:email= "[ 
        'required', 'Mail','Mobile']" 就可以校验默认有的规则弹出默认的错误提示信息。 
        例如你不想要默认的错误提示信息。用自己写的
        v-validator:email= "[{required: '', msg: '不可以为空呦'}]"
     * 2.自定义规则: Vue指令属性值上添加的规则。有两种
           (1)正则
          v-validator:email= "[ 
          'required', 'Mail','Mobile']"
          (2)function
          [{limit: () =>{
            return true/false
           }, msg: this.$i18n.t('login.password.errorMsg.limit')}]
           如果你是放在data中设置规则的话
    export default {
      name: 'login',
      data () {
        return {
          validatePassword: [
            {limit: this.limit, msg: this.$i18n.t('login.password.errorMsg.limit')}//$i18n是 
             为了语言切换
          ]
        }
      },
      methods: {
        limit: function () {
          let password = this.$data.password
          return (password.length >= 6 && password.length <= 12)
        }
      }
       3.还没加这个功能 同一个type的规则只存在一个,也就是说,如果type为reg(正则),那么会互相 
          盖。 覆盖的优先级: 自定义规则 > 选项规则 > 默认规则
     */
    

    实战使用
    main.js

    import Validator from './plugins/validator'
    Vue.use(Validator)
    

    main.vue

    <template>
      <div class="login-main">
          <div class="login-form">
            <div class="login-content">
                <div class="input_item">
                    <label for="email">{{$t('login.email.name')}}{{$t('login.email.errorMsg.required')}}</label>
                    <input class="error-content" type="text" id="email"  v-model="email" :placeholder="$t('login.email.placeholder')" autocomplete="off" v-validator:email= "validateEmail" tag="邮箱">
                    <span class="error"></span>
                </div>
                <div class="input_item">
                    <label for="password">{{$t('login.password.name')}}</label>
                    <input class="error-content" type="password" id="password" v-model="password" :placeholder="$t('login.password.name')" autocomplete="off" tag="密码" v-validator:password= "validatePassword" >
                    <p class="error"></p>
                </div>
                <div class="login-options">
                  <input type="submit" class="cannot-login-btn" :value="$t('login.forget.name')" >
                </div>
                <input type="submit" class="login-btn" :value="$t('login.loginBtn.name')"  @click="checkLogin();">
            </div>
              <div class="change-btn">
                  {{$t('login.changedes')}}
                  <a href="/signup"> {{$t('login.signInBtn.name')}}</a>
              </div>
          </div>
      </div>
    </template>
    <script>
    export default {
      name: 'login',
      data () {
        return {
          email: '',
          validateEmail: [
            {required: '', msg: this.$i18n.t('login.email.errorMsg.required')},
            {Mail: '', msg: this.$i18n.t('login.email.errorMsg.mail')}
          ],
          password: '',
          validatePassword: [
            {required: '', msg: this.$i18n.t('login.password.errorMsg.required')},
            {limit: this.limit, msg: this.$i18n.t('login.password.errorMsg.limit')}
          ]
        }
      },
      methods: {
        checkLogin: function () {
          let _this = this
          let checkResult = _this.$va.checkAll()
          if (checkResult) {
            console.log('请求接口去登陆')
          }
        },
        limit: function () {
          let password = this.$data.password
          return (password.length >= 6 && password.length <= 12)
        }
      }
    }
    </script>
    <style lang="less" scoped>
    .login-main{
      min-height: 100vh;
      background: #000000;
      // background: url('../../../static/img/login/login1.png')no-repeat;
      background-size: cover;
      overflow: hidden;
      .login-form{
        width: 432px;
        margin: 150px auto;
        background-color: #fff;
        border-radius: 2px;
        box-shadow: 0 1px 3px rgba(26,26,26,.1);
        .login-content{
          padding: 62px 42px 68px;
        }
        .input_item{
          margin: 0 0 20px;
          label{
            font-size: 16px;
            display: block;
            color: #2d2d2d;
            margin-bottom: 5px
          }
          input{
            font-size: 16px;
            border: none;
            line-height: 32px;
            width: 100%;
            border-bottom: 1px solid #ebebeb;
          }
          input::-webkit-input-placeholder{
            color: #DFE2EC;
          }
          input::-moz-placeholder{  //不知道为何火狐的placeholder的颜色是粉红色,怎么改都不行,希望有大牛路过帮忙指点
            color: #DFE2EC;
          }
          input::-ms-input-placeholder{  //由于我的IE刚好是IE9,支持不了placeholder,所以也测试不了(⊙﹏⊙),有IE10以上的娃可以帮我试试
            color: #DFE2EC;
          }
    //没报错的样式
          .error{
            display: none
          }
    //没报错的样式
        }
    //报错的样式
        .input_item.error_item{
        .error{
            display: block;
            color: red;
            font-size: 16px;
            line-height: 32px;
        }
        .error-content{
              border-bottom: 1px solid red;
        }
        }
    //样式
        .login-btn{
              margin-top: 30px;
              border: none;
              background: rgba(0,166,248,0.9);
              width: 100%;
              color: #fff;
              padding: 10px 0;
              border-radius: 3px;
              font-size: 16px;
        }
        .change-btn{
            display: flex;
            -webkit-box-align: center;
            align-items: center;
            -webkit-box-pack: center;
            justify-content: center;
            width: 100%;
            background-color: #f6f6f6;
            height: 58px;
            border-top: 1px solid #ebebeb;
            font-size: 16px;
            border-radius: 0 0 2px 2px;
            a{
              color:rgba(0, 166, 248, 1)
            }
        }
        .login-options{
          .cannot-login-btn{
              float: right;
              border: none;
              font-size: 14px;
              color: #BEBCBA;
              text-align: center;
              cursor: pointer;
              background: none;
          }
        }
      }
    }
    </style>
    

    最终的效果


    image.png

    相关文章

      网友评论

          本文标题:vue 如何写插件、自己写一个表单验证插件

          本文链接:https://www.haomeiwen.com/subject/kvpozxtx.html