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

学习了一年多的 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
这只是我自己总结出来的方法,当然大家有更好的方法也可以说,大家多交流,谢谢

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容

  • UI组件 element - 饿了么出品的Vue2的web UI工具套件 Vux - 基于Vue和WeUI的组...
    鲁大师666阅读 43,358评论 5 97
  • UI组件 element - 饿了么出品的Vue2的web UI工具套件 Vux - 基于Vue和WeUI的组件库...
    卞卞村长L阅读 1,685评论 0 8
  • 转载 :OpenDiggawesome-github-vue 是由OpenDigg整理并维护的Vue相关开源项目库...
    果汁密码阅读 23,072评论 8 124
  • 如果有一天,你不在寻找爱情,只是去爱;你不在渴望成功,只是去做;你不在追求成长,只是去修;一些才是真的开始。来自纪...
    深圳润土阅读 166评论 0 0
  • 在人们眼中,小马和小丫过着令人羡慕的生活:各自有稳定的工作,假期多,家有一子,有房有车…收入虽然谈不上丰厚,但也在...
    且将生活一饮而尽阅读 397评论 0 0