Vue-component | 自定义Form组件

日常开发中积累了不少可能对一些开发有帮助的简单易用的组件,好记性不如烂笔头,想对过去的一些零零乱乱的东西做一些总结,反省自己的同时也便于思考一些更优的方法,提升下开发思维😉😉😉。
代码传送门(😃感觉有作用的的同学帮忙点下❤️️)

效果截图

先上效果图,自定义规则,违反规则马上显示提示。


Form

组件结构

参照elementUI的表单组件,组件的结构是Form > ... (FormItem > Form组件)

<j-form>    // Form
    <j-form-item>     //  FormItem
             <j-input></j-input>    // content
    </j-form-item>
    //  ...可以添加多个Item
</j-form>

核心代码

Form组件
最上级是Form组件,是进行全局验证的组件,并且接收prop(传递的数据模型和规则),并将自身注入到子级中。

<template>
  <div id="form">
    <slot></slot>
  </div>
</template>
<script>
export default {
  name: 'j-form',
  //  将自身注入
  provide () {
    return {
      form: this
    }
  },
  props: {
  //  数据模型
    model: {
      type: Object,
      required: true
    },
  //  校验规则
    rules: {
      type: Object
    }
  },
  methods: {
    //  表单全局校验方法,校验所有的item内容
    validate (callBack) {
      const tasks = this.$children.filter(item => item.prop).map(item => item.validate())
      // 所有任务都通过才算校验通过
      Promise.all(tasks).then(() => callBack(true)
      ).catch(() => callBack(false)
      )
    }
  }
}
</script>


FormItem组件
用item组件包裹表达内容组件,目的是为了进行单一校验,并产生错误的提示信息。这里使用的是async-validator第三方的校验库,需要额外装载。


<template>
  <div id="form-item">
    <label v-if="label" class="label">{{label}}</label>
    <slot></slot>
    <p v-if="errorMsg" class="error-msg">{{errorMsg}}</p>
  </div>
</template>
<script>
import Schema from 'async-validator'
export default {
  name: 'j-form-item',
  components: {},
  inject: ['form'],
  data () {
    return {
      errorMsg: ''
    }
  },
  props: {
    //  标题文本
    label: {
      type: String,
      default: '',
      required: true
    },
  //  数据字段名
    prop: {
      type: String
    }
  },
  mounted () {
    // 监听校验
    this.$on('validate', () => { this.validate() })
  },
  methods: {
    validate () {
      console.log('触发校验===')
      // async-validator的校验方法
      const value = this.form.model[this.prop]
      const rules = this.form.rules[this.prop]
      const desc = { [this.prop]: rules }
      const schema = new Schema(desc)
      // return的是校验结果的Promise
      return schema.validate({ [this.prop]: value }, errors => {
        if (errors) {
          console.log('error', errors[0].message)
          this.errorMsg = errors[0].message
        } else {
          console.log('error', errors)
          this.errorMsg = ''
        }
      })
    }
  }
}
</script>

Input组件
内容组件,在这里进行内容的监听,上到FormItem进行校验

<template>
  <div id="input">
    <input :value="value" @input="onInput" v-bind="$attrs" />
  </div>
</template>
<script>
export default {
  name: 'j-input',
  // 禁用继承的属性
  inheritAttrs: false,
  model: {
    prop: 'value',
    event: 'change'
  },
  props: {
    value: {
      type: String,
      default: ''
    }
  },
  methods: {
    onInput (e) {
      console.log(e.target.value)
      // 监听数值变化
      this.$emit('change', e.target.value)
      // 触发校验
      this.$parent.$emit('validate')
    }
  }
}
</script>

使用
使用组件就和elementUI一样进行处理即可

<template>
  <div id="home">
    <j-form ref="ruleForm" :model="model" :rules="rules">
      <j-form-item label="姓名" prop="name">
        <j-input v-model="model.name" placeholder="请输入姓名" />
      </j-form-item>
      <j-form-item label="年龄" prop="age">
        <j-input v-model="model.age" placeholder="请输入年龄" />
      </j-form-item>
    </j-form>
  </div>
</template>
<script>
export default {
  components: {},
  data () {
    return {
      model: {
        name: '',
        age: ''
      },
      rules: {
        name: [
          { required: true, message: '请填写姓名', trigger: 'change' },
          { min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'change' }
        ],
        age: [
          { required: true, message: '请填写年龄', trigger: 'change' },
          { min: 1, max: 2, message: '长度在 1 到 2 个字符', trigger: 'change' }
        ]
      }
    }
  }

关键点


处理自定义组件,一定要对vue中的传值比较清晰了解,这里就不一一列举。在这里主要使用的一些技术包括:

技术 概述 备注
props传值 父级传子级 /
provide-inject 从上往下可以跨级传值 在代码里将自身传递下来
slot 插槽,将子组件插入父组件中 Input>FormIten>Form
inheritAttrs-$attrs 禁用继承的属性直接赋予给根标签,自定义继承 /
v-model 自定义双向传值 /
Promise.all() 同时完成所有的任务 /

后续会持续更新其他一些有用的组件提供参考...

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