vue2.x 组件化与验证插件的编写

2017-09-12  本文已影响167人  itvwork

学习了一年多的 vue 感觉vue还真是个强大的组件化框架.作为一个前端开发工作者,在开当中预到不少问题。也看到不少开发者写的vue代码,每个人写的代码都有些不同。很多人对组件化理解得不是很深,写的代码很多重复的代码却没抽出来,做成一个独立的组件。我先说说我遇到的情况:

很多人做表单的时候,一个页面一个组件,下面写很多原生input。比如:

image.png

像这样一个页面很多人都会直接一个路原生表单走到黑,

<form>
<label class="row-label">
    <span>标题</span>
    <span class="text-outdoor">
       <input type="text"    class="input-text  />
       <i class="clear-word" ></i>
        <em>错误信息</em>
 </span>
</label>
<label class="row-label">
    <span>标题</span>
    <span class="text-outdoor">
       <input type="text"    class="input-text  />
       <i class="clear-word" ></i>
        <em>错误信息</em>
 </span>
</label><label class="row-label">
    <span>标题</span>
    <span class="text-outdoor">
       <input type="text"    class="input-text  />
       <i class="clear-word" ></i>
        <em>错误信息</em>
 </span>
</label>
<form>
</template>

然后表单就一直加在这个页面,这样一个页面不觉得有很多重用的地方法嘛,为什么不把一个表单儿独立成一个组件呢,这样可大地减少代码理,下面是我自己把一个input 封装成一个组件的代码,我觉得一个input一个组件会给我们带来很大的方便。比如验证写验证的候可以独立验证。像表单验证这种自定义很强的插件本来是要自己写是最好的。组件化表单我方便我们写这样的插件。当然这仅能代表我的写法,没什么特别的意思大家觉得好就点赞,觉得不好当我没说。也可以给一些意见我,当作交流。

好了下面直接复制出我自己独立成组件的代码:

<label class="row-label">
  <span class="row-title" v-if="toggleTitle==1" :style="{width:tw}">{{title}}</span>
  <span class="text-outdoor">
      <input :type="inputType" :id="id"  :value="value"   :disabled='isDisabled' class="input-text" :placeholder="tips"   ref="input"   @input="updateValue($event.target.value)"  />
      <i class="clear-word"  @click="clear()" v-if="value&&(type!='password')&&(!isDisabled)" ></i>
      <i :class="{'icon-view-pwd':(inputType=='password'),'icon-hide-pwd':(inputType!='password')}"  v-if="value&&(type=='password')&&(!isDisabled)"   @click="inputType!='password'?inputType='password':inputType='text' "></i>
      <em class="err-msg" v-if="err!==true">{{err}}</em>
  </span>
</label>
</template>
<script>
export default {
  props: {
    value: {
      type: String, //需要绑定的值 
      default: ''
    },
    title: {
      type: String
      default: '标题'  //表单的标题名称
    },
    tips: {
      type: String,//表单的placeholder
      default: '请输入内容'
    },
  type: {
      type: String,   //表单的类型,比如text number
      default: 'text'
    },
    tw: {
      type: String,//标题所占的宽度
      default: '.1rem'
    },
    toggleTitle: { //就否要显示标题
      type: String,
      default: '0'
    },
    isDisabled:{ //是否禁用
      default:false
    },
    schema:{ //验证字段的对象
      default:false
    },
    rule:{ //验证的规则
      default:false
    },
  },
  computed: {
  },
  data() {
    return {
      inputType: this.$props.type,
      newvalue:this.$props.value,
      err:'',
      id:'input-'+parseInt(Math.random()*1000)+'-'+parseInt(Math.random()*1000)  //来个随机id好调用focus
    }
  },
  methods: {
    updateValue: function(value) {
       if(this.schema){
          this.err=this.schema.single(this.rule,value); //验证表单信息
        }
       this.$emit('update:value', value);
    },
    valtVal:function(){ //提交时验证
        this.err=this.schema.single(this.rule,this.value);
        return this.err;
    },
    focus:function(){
            document.getElementById(this.id).focus();
    },
    showErr:function(err){ //显示错误的信息,这个是做异步验证的,下面会说
        this.err=err;
    },
    clear: function() { //清理表单
      this.$refs.input.value = "";
      this.$emit('update:value', "");  <br/>}
  }
};
</script>

验证码器代码:




export default function Validator(data,self,ref) {  
    this.data = data;//保存新建的规则,
    this.result=""
    this.self=self; 将页面的this传过来并保存
    this.ref=ref; //将表单的ref索引传过来
 
}
Validator.prototype = {
    constructor: Validator,
    single: function(valname, val) { //验证单个字段  查看表单组件的valtVal()方法
        let str = true;
        if (this.data[valname]['tirm']) {
            val = this.trim(val);
        }
        for (let i = 0; i < this.data[valname]['rule'].length; i++) {
            let msg = this.data[valname]['msg'][i];
            let rule = this.data[valname]['rule'][i];
            if (typeof rule == 'string') {
                if (this[rule](val)) {
                    str = true;
                } else {
                    str = msg;
                    break;
                }
            } else {
                if (this[rule[0]](rule, val)) {
                    str = true;
                } else {
                    str = msg;
                    break;
                }
            }
        }

        return str;
    },
    all: function(data) {
        return this.data[valname];
    },
    require: function(str) { //必须字段
        if (str) {
            return true;
        } else {
            return false;
        }
    },
    tel: function(str) { //国内固话验证
        var result = str.match(/^(\(\d{3,4}\)|\d{3,4}-)?\d{7,8}$/);
        if (result == null) return false;
        return true;
    },
    tel400: function(str) {
        if (str.match(/^400\-[\d|\-]{7}[\d]{1}$/)) { //第一次匹配 400-(七个数字和-)(数字结尾)
            if (str.match(/[\-]/g) == "-,-") { //第二次匹配两个 -
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    },
    trim: function(str) { //去除前后空格
        return str.replace(/(^\s*)|(\s*$)/g, '');
    },
    between: function(arr, val) { //区间大小
        if (val.length >= arr[1] && val.length <= arr[2]) {
            return true;
        } else {
            return false;
        }
    },
    max:function(arr,val){
      if (val.length > arr[1]) {
          return false;
      } else {
          return true;
      }
    },
    max:function(arr,val){
      if (val.length <arr[1]) {
          return false;
      } else {
          return true;
      }
    },
    phone: function(str) {
      var result = str.match(/^1[34578]\d{9}$/);
      if (result == null) return false;
      return true;
    },
    email: function(str) { //email
        var result = str.match(/^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/);
        if (result == null) return false;
        return true;
    },
    getResult: function() {
        return this.result;
    },
    strlen: function(str) { //
        return str.replace(/[^\x00-\xff]/g, "**").length;
    },
    alltel:function (str) {
        return this.tel(str)||this.tel400(str)||this.phone(str);
    },
    getdata:function () {
        return this.self.shop
    },
   allvalt:function(){
        let child = this.self.$refs[this.ref?this.ref:'form'].$children;
        let oneerr=true;//获取第一个错误的组件 然后获取焦点
        for(let i =0 ; i<child.length;i++){
            if(child[i].rule){
                if(child[i].valtVal()!==true&&oneerr===true){  判断第一个没有通过验证的是哪个组件
                    child[i].focus();//调用组件的focus,查看input的focus方法
                    oneerr=false;
                }
            }
        }
        if(oneerr===true){
            return true; 
        }else{
            return false;
        }
    }

};

页面调用代码:

导入你的验证器代码在你的入口文件:import Schema from './validator/index.js';
Window.Schema=Schema||{};注册全局

<template>
<indoor>
    <form-edit ref='form'>
      <input-text toggleTitle=1 title="店铺名称:"  tips="请输入店铺名称"  :value.sync="shop.store_name"  :schema="schema" rule="store_name"  tw="1rem"></input-text>
     //调用的时我们必须把数据绑定到上面
        <input-text toggleTitle=1 title="联系人(可不填):"  tips="请输入联系人姓名"  :value.sync="shop.store_contact" tw="1rem"></input-text>
      <input-text toggleTitle=1 title="电话号码:"  tips="请输入联系电话"  :value.sync="shop.store_phone" :schema="schema" rule="store_phone" tw="1rem"></input-text>
      <input-text toggleTitle=1 title="店面地址:" ref='addr'  tips="请输入地址至少要到区"  :value.sync="shop.store_address" :schema="schema" rule="store_address"  tw="1rem"></input-text>
        <div class="sub-bar" style="padding-left: 1.3rem">
            <button  class="btns btn-sub" @click="send()">{{subword}}</button>
        </div>
    </form-edit>
</indoor>
</template>
<script>
//下面就是我写的验证器用法
let schema ={
   store_name:{
     tirm:false,
     rule:['require',['between',3,20]],//这是用到的规则
     msg:['店名是必须','店名必须在10-15个字符'] // 对应上面输入出的错误信息
  },
  store_phone:{
    rule:['require','alltel'],
    msg:['电话是必填的',"请输入正确的电话号码,固话,手机,400电话"]
  },
  store_address:{
    rule:['require'],
    msg:['地址不能为空']
  }
};

export default {
    components: { addbtn },
    data() {
        return {
            btn: [{
                    type: 'link',
                    url: '/admin/shop/add',
                    name: '添加店铺',
                    class: 'btn-add-model'
                }
            ],
            shop:{
              store_name:"",
              store_phone:'',
              store_ewm:'',
              store_contact:'',
              store_address:'',
              latlng:''
            },
            forbid:true,
            subword:"提交",
            schema:new Schema(schema,this), //将验证码
            tips:''
        }
    },   
    watch: {
        '$route': function(to, from) {
            if (this.$route.query.page) {
                this.$refs.page.change({});
            }
        }
    },
    methods: {
      async send(){
        if(!this.schema.allvalt()){
                return false;
        }
      }
     
};
</script>

不懂的可以看我的源代码 https://github.com/itvwork/itvwork
按提示安装依赖 然后运行项目
访问9090端口点击登录,然后点店铺管理,点击右上角的店铺添加 就可以看到源码了

验证器放在 app/validator 目录下
子组件事input放在 app/commpents/input/input-text.vue中
调用子组件和验证器的案例在:app/view/store/add.vue中

本文写到这里,有什么建议和疑问可以发我邮箱xieke76v@qq.com
这只是我自己总结出来的方法,当然大家有更好的方法也可以说,大家多交流,谢谢

上一篇下一篇

猜你喜欢

热点阅读