vue 自写验证 加 jsx

Posted smallteeth

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue 自写验证 加 jsx相关的知识,希望对你有一定的参考价值。

import vTips from ‘./component.js‘

var va = {};

function unique(arr){
    var hashTable = {}, newArr = [];
    for(var i = 0;i < arr.length;i++){
        if(!hashTable[arr[i]]){
            hashTable[arr[i]] = true;
            newArr.push(arr[i]);
        }
    }
    return newArr;
}

function addClass(dom, _class){
    var hasClass = !!dom.className.match(new RegExp(‘(\\s|^)‘ + _class + ‘(\\s|$)‘))
    if(!hasClass){
        dom.className += ‘ ‘ + _class
    }
}

//校验函数
function check(v, conditions){
    var res = 0;                                        //0代表OK, 若为数组代表是某个字段的错误
    //验证函数
    var cfg = {
        //非空
        nonvoid: (v, bool)=>{
            if(bool){
                return v.trim() ? 0 : [‘nonvoid‘];
            }else{
                return 0;
            }
        },
        reg:(v, reg)=> reg.test(v) ? 0 : [‘reg‘],                //正则
        limit:(v, interval)=> {  return (v.length >= interval[0] && v.length <= interval[1]) ? 0 : [‘limit‘, interval]},
        equal: (v, target)=>{                                                        //和什么相等
            var _list = document.getElementsByName(target), _target
            for(var i = 0;i < _list.length;i++){
                if(_list[i].className.indexOf(‘va‘) > -1){
                    _target = _list[i];
                }
            }
            return (_target.value === v) ? 0 : [‘equal‘, _target.getAttribute(‘tag‘)]
        },
        unique:(v)=>{
            var _list = document.getElementsByClassName(‘unique‘),
                    valList = [].map.call(_list, item=>item.value)
            return (unique(valList).length === valList.length) ? 0 : [‘unique‘]
        }
    }
    for(var i = 0;i < conditions.length;i++){
        var condi = conditions[i],
            type = condi.type,
            typeVal = condi.typeVal
        res = cfg[type](v, typeVal)
        // console.log(res, v, type,typeVal)
        //如果有自定义报错信息, 返回自定义的报错信息
        if(res){
            res = condi.errMsg || res
            break
        }
    }

    return res;
}

function showErr(name, checkResult){
    var type = checkResult[0],
            ext = checkResult[1] || []

    var ERR_MSG = {
        nonvoid: `${name}不能为空`,
        reg: `${name}格式错误`,
        limit: `${name}必须在${ext[0]}与${ext[1]}之间`,
        equal: `两次${ext}不相同`,
        unique: `${name}重复`
    }
    //使用layer来报错,如果需要自定义报错方式,要把全文的layer集中起来包一层。
    return ERR_MSG[type];
}


/**
 * [VaConfig va配置的构造函数]
 * @param {[string]} type    [校验类型,如reg, limit等等]
 * @param {[*]} typeVal             [根据校验类型配置的值]
 * @param {[string]} errMsg  [报错信息]
 * @param {[string]} name    [用以ajax的字段名]
 * @param {[string]} tag     [中文名,用以报错]
 */
function VaConfig(type, typeVal, errMsg, name, tag){
    this.type = type, this.typeVal = typeVal, this.errMsg = errMsg, this.name = name, this.tag = tag
}

//用来剔除重复的规则,以及规则的覆盖。默认后面的取代前面
Array.prototype.uConcat = function(arr){
    var comb = this.concat(arr)
            ,unique = {}
            ,result = []

    for(var i = 0;i < comb.length;i++){
        // console.log(i, comb[i])
        var type = comb[i].type
        if(unique[type]){
            var index = unique[type].index
            unique[type] = comb[i]
            unique[type].index = index;
        }else{
            unique[type] = comb[i]
            unique[type].index = i;
        }
    }

    for(var i= 0;i < 100;i++){
        for(var item in unique){
            if(unique[item].index === i){
                delete unique[item].index
                result.push(unique[item])
            }
        }
    }
    return result
}

import regList from ‘./reg.js‘;

va.install = function(Vue, options){
    var tipError = vTips(Vue, {errorClass:‘air-fromate-error‘})
    Vue.directive(‘va‘,{
        bind:function(el, binding, vnode){
            var dom = el.querySelector(‘input‘)
            var vm = vnode.context
                ,name = binding.arg === ‘EXTEND‘ ? dom.getAttribute(‘name‘) : binding.arg
                ,tag = dom.getAttribute(‘tag‘) || binding.value.tag
                ,baseCfg = []                                        //默认的校验规则                         --不用写,默认存在的规则(如非空)
                ,optionalConfig = []                                //用户选择的配置成套         --与name相关
                ,customConfig = []                                    //用户自定义的规则(组件中) --bingding.value
                ,option = binding.modifiers
                ,regMsg = dom.getAttribute(‘regMsg‘) || binding.value.regMsg
            var eazyNew = (type, typeVal) =>{return new VaConfig(type, typeVal, ‘‘, name, tag)}
            var regNew = (typeVal) =>{return new VaConfig(‘reg‘, typeVal, regMsg, name, tag)}    //正则的新建
            var newClassName = ‘va‘ + vm._uid
            addClass(dom,newClassName)
            dom.name = name
            vm.vaConfig || (vm.vaConfig = {})
            var NON_VOID = eazyNew(‘nonvoid‘, true)

            //默认非空,如果加了canNull的修饰符就允许为空
            if(!option.canNull){
                baseCfg.push(NON_VOID)
            }

            //需要立即校验的框
            var oldValue=‘‘;
            Object.defineProperty(dom, ‘_value‘, {
                configurable: true,
                set: function(value) {
                    this.value = value;
                    if(oldValue!=value){
                        oninputCallback();                                               
                    }
                    oldValue = value;     
                },
                get: function() {
                    return this.value;
                }
            });
            function oninputCallback(){
                vm.vaResult || (vm.vaResult = {})
                vm.vaVal || (vm.vaVal = {})
                var value = dom.value,
                        conditions = vm.vaConfig[name],
                        para = dom.getAttribute(‘va-para‘)                //传给回调的参数
                //如果允许为空的此时为空,不校验
                if(value === ‘‘ && option.canNull){
                    vm.vaVal[name] = value
                    return
                }               
                vm.vaResult[name] = check(value, conditions);
                var _result = vm.vaResult[name]
                if(_result){
                    //如果返回的是字符串,则为自定义报错; 如果是数组,则使用showErr 报错
                    typeof _result === ‘string‘ ? _result : _result=showErr(conditions[0].tag, _result);
                    dom.style.borderBottom = ‘1px solid  red‘
                    dom.instance=tipError({el:dom,message:_result,target: dom.instance || null,})            
                    dom.value = vm.vaVal[name] = ‘‘
                    return
                }
                tipError({el:dom,remove:true,target: dom.instance || null})
                dom.style.borderBottom = ‘1px solid  rgba(0,0,0,0.04)‘
                vm.vaVal[name] = value
                // vm.$vanow(para)                                     
                
                
                // dom.addEventListener(‘oninput ‘, function(){
                //     vm.vaResult || (vm.vaResult = {})
                //     vm.vaVal || (vm.vaVal = {})
                //     var value = dom.value,
                //             conditions = vm.vaConfig[name],
                //             para = dom.getAttribute(‘va-para‘)                //传给回调的参数
                //     //如果允许为空的此时为空,不校验
                //     if(value === ‘‘ && option.canNull){
                //         vm.vaVal[name] = value
                //         return
                //     }               
                //     vm.vaResult[name] = check(value, conditions);
                //     var _result = vm.vaResult[name]
                //     if(_result){
                //         //如果返回的是字符串,则为自定义报错; 如果是数组,则使用showErr 报错
                //         typeof _result === ‘string‘ ? _result : _result=showErr(conditions[0].tag, _result);
                //         dom.style.borderBottom = ‘1px solid  red‘
                //         dom.instance=tipError({el:dom,message:_result,target: dom.instance || null,})            
                //         dom.value = vm.vaVal[name] = ‘‘
                //         return
                //     }
                //     tipError({el:dom,remove:true,target: dom.instance || null})
                //     dom.style.borderBottom = ‘1px solid  rgba(0,0,0,0.04)‘
                //     vm.vaVal[name] = value
                //     vm.$vanow(para)                    //写在实例内部method的回调
                // })
            }

            //不能重复的
            if(option.unique){
                optionalConfig.push(eazyNew(‘unique‘, name))
            }

            //如果有在正则表里
            var regOptions = Object.keys(option);
            for(var i = 0;i < regOptions.length;i++){
                var regOption = regOptions[i]
                if(regList[regOptions[i]]){
                    optionalConfig.push(regNew(regList[regOption]))
                }
            }

            //如果regList里有name对应的,直接就加进optionalConfig
            if(regList[name]){
                optionalConfig.push(regNew(regList[name]))
            }

            //用户自定义的规则
            if(binding.value.rol){
                customConfig = binding.value.rol.map(item=>{
                    let type = Object.keys(item)[0];
                    if(type === ‘reg‘){
                        return regNew(item[type])
                    }else{
                        if(type === ‘unique‘){
                            addClass(dom, ‘unique‘)
                        }
                        return eazyNew(type, item[type])
                    }
                })
            }

            //规则由 默认规则 + 修饰符规则 + 写在属性的自定义规则 + 用户直接加到vm.vaConfig里的规则 合并(后面的同type规则会覆盖前面的)
            vm.vaConfig[name] || (vm.vaConfig[name] = [])
            vm.vaConfig[name] = baseCfg.uConcat(optionalConfig).uConcat(customConfig).uConcat(vm.vaConfig[name])
        },
    })

    Vue.directive(‘va-check‘, {
        bind:function(el, binding, vnode){
            var vm = vnode.context
            el.addEventListener(‘click‘, function(){
                var domList = document.getElementsByClassName(‘va‘ + vm._uid);
                vm.vaResult || (vm.vaResult = {})
                vm.vaVal || (vm.vaVal = {})
                var flag = true;
                for(var i = 0;i < domList.length;i++){
                    var dom = domList[i],
                            name = dom.name,
                            value = dom.value,
                            conditions = vm.vaConfig[name]
                    var _result = check(value, conditions)                                 
                    //如果返回不为0,则有报错
                    if(_result){
                        //如果返回的是字符串,则为自定义报错; 如果是数组,则使用showErr 报错
                        typeof _result === ‘string‘ ? _result : _result=showErr(conditions[0].tag, _result);
                        dom.instance=tipError({el:dom,message:_result,target: dom.instance || null,})
                        dom.style.borderBottom = ‘1px solid  red‘
                        flag=false;
                    }else{
                        dom.style.borderBottom = ‘1px solid  rgba(0,0,0,0.04)‘
                        tipError({el:dom,remove:true,target: dom.instance || null})
                    }
                    vm.vaVal[name] = value
                }
                //校验通过的回调
                if(flag){
                    console.log(vm)
                    vm.$vaSubmit(vm.vaVal)                
                }
                // layer.msgWarn(‘全部校验成功‘)
            })

        }
    })

    Vue.directive(‘va-test‘,{
        bind: function(el, binding, vnode){
            var vm = vnode.context
            el.addEventListener(‘click‘, function(){
                vm.vaResult || (vm.vaResult = {})
                vm.vaVal || (vm.vaVal = {})

                var dom = document.getElementsByName(binding.arg)[0],
                        name = dom.name,
                      value = dom.value,
                      conditions = vm.vaConfig[name]

                var _result = check(value, conditions)
                //如果返回不为0,则有报错
                if(_result){
                    //如果返回的是字符串,则为自定义报错; 如果是数组,则使用showErr 报错
                    typeof _result === ‘string‘ ? layer.msgWarn(_result) : showErr(conditions[0].tag, _result)
                    return
                }

                vm.vaVal[name] = value
                var callback = Object.keys(binding.modifiers)[0]
                vm[callback]()
            })
        }
    })


    /**
   **  在实例的monuted周期使用 api设置自定义配置
     */
    Vue.prototype.VaConfig = VaConfig
}
export default va;

上面是验证 下面是jsx

var component = {
    name: ‘vTips‘,
    data () {
      return {
        exist: false
      }
    },
    props: {
      position: {
        type: Object,
        default: () => {
          return {
            top: 48,
            left: 0
          }
        }
      },
      message: {
        type: String,
        default: ‘‘
      },
      errorClass: {
        type: String,
        default: ‘air-form-err‘
      },
      errorIcon: {
        type: String,
        default: ‘‘
      }
    },
    render (h) {
      if (!this.exist) return
      return h(‘div‘, {
        style: {
          fontSize: ‘12px‘,
          color: ‘#F2553D‘,
          position: ‘absolute‘,
          top:‘48px‘,
          left: this.position.left + ‘px‘,
          backgroundColor: ‘#fff‘,
          padding: ‘2px 8px‘,
        //   display:‘none‘,
          margin: 0,
          zIndex: ‘99‘,
        //   boxShadow: ‘0 -4px 4px rgba(0,0,0,.12), 0 0 6px rgba(0,0,0,.04)‘,
          border: "1px solid rgba(0,0,0,0.12)",
          borderRadius: ‘4px‘
        },
        class: [this.errorClass]
      }, [
        h(‘i‘, {
          class: [this.errorIcon]
        }),
        h(‘b‘, {
          style: {
            position: ‘absolute‘,
            top: ‘-5px‘,
            bottom: ‘-5px‘,
            width: ‘8px‘,
            height: ‘8px‘,
            display: ‘block‘,
            borderLeft: ‘1px solid rgba(0,0,0,.1)‘,
            transform: ‘rotateZ(45deg)‘,
            borderTop: ‘1px solid rgba(0,0,0,.1)‘,
            borderSizing: ‘border-box‘,
            backgroundColor: ‘#fff‘
          }
        }),
        h(‘span‘, this.message)
      ])
    }
  }


  
  export default function (Vue, config) {
    const PromptConstructor = Vue.extend(component)
    const tipsList = []
    
    function getAnInstance () {
      if (tipsList.length > 1) {
        const instance = tipsList[0]
        tipsList.splice(0, 1)
        return instance
      }
      return new PromptConstructor({
        el: document.createElement(‘div‘)
      })
    }
  
    const returnAnInstance = instance => {
      if (instance) {
        tipsList.push(instance)
      }
    }
  
    function getElPosition (el) {
      if (window.getComputedStyle && (el.parentNode && !el.parentNode.style.position)) {
        const _position = window.getComputedStyle(el.parentNode).position
        if (!_position || _position === ‘static‘) {
          el.parentNode.style.position = ‘relative‘
        }
      }
      return {
        top: el.offsetTop - 38,
        left: el.offsetLeft
      }
    }
  
    const removeDom = target => {
      const container = getContainer()
      if (target.parentNode) {
        container.removeChild(target)
      }
    }
  
    PromptConstructor.prototype.close = function (el) {
      this.exist = false
      // removeDom(el)
      // this.exist = true
      // returnAnInstance(this)
    }
    
    const vTips = (options = {}) => {
      const instance = options.target || getAnInstance()
      const container = options.el.parentNode
      if (options.remove) {
        
        instance.close(options.target)
        return
      }
  
      instance.message = typeof options === ‘string‘ ? options : options.message
      instance.position = options.el ? getElPosition(options.el, instance) : options.position
      instance.exist = false
      instance.errorClass = options.errorClass || config.errorClass
      instance.errorIcon = options.errorIcon || config.errorIcon
      container.appendChild(instance.$el)
      Vue.nextTick(function () {
        instance.exist = true
      })
      return instance
    }
  
    return vTips
  }

 

以上是关于vue 自写验证 加 jsx的主要内容,如果未能解决你的问题,请参考以下文章

webstorm中怎么让.vue文件render中的JSX高亮

数据结构——自写简易哈希表(Java)

vue路由组件左右切换(×××返回键或自写按钮)

更漂亮的东西弄乱了 jsx 片段

关于vue的jsx语法

如何通过 VITE 在 Data() Vue 3 组件中使用 JSX/HTML 代码