前言
很久没有写文章了,学习了一下webpack,基础的一些组件,今天带来form表单验证组件(element.iviewui)的一期教程(作为一个菜鸡毕竟经历众多项目可以给一些新手一点提示 (QQ群技术讨论)838293023备注(github进来的
github 技术文档 技术文档会持续更新
效果图
1.原理解释
考虑
我们看一下我们可以用form去整体触发校验也可以单个input来触发form-item 进行校验 童鞋们现在可能感觉还是没懂,没关系继续往下看。
2.派发和广播
为什么要用广播和派发呢。通常我们和业务没有关系的组件尽量不要使用vuex和bus(事件总线)。 下面我送上广播和派发的代码。我们在需要调用组件绑上 this.$on('event',res=>())
,通过派发和广播进行调用 $emit
。
- 派发是向上查找且只调用1个
- 广播是向下查找调用多个
- 注意"htmlcode">
emitter.js /** * 递归使用 call 方式this指向 * @param componentName // 需要找的组件的名称 * @param eventName // 事件名称 * @param params // 需要传递的参数 */ function broadcast(componentName, eventName, params) { // 循环子节点找到名称一样的子节点 否则 递归 当前子节点 this.$children.map(child=>{ if (componentName===child.$options.name) { child.$emit.apply(child,[eventName].concat(params)) }else { broadcast.apply(child,[componentName,eventName].concat(params)) } }) } export default { methods: { /** * 派发 (向上查找) (一个) * @param componentName // 需要找的组件的名称 * @param eventName // 事件名称 * @param params // 需要传递的参数 */ dispatch(componentName, eventName, params) { let parent = this.$parent || this.$root;//$parent 找到最近的父节点 $root 根节点 let name = parent.$options.name; // 获取当前组件实例的name // 如果当前有节点 && 当前没名称 且 当前名称等于需要传进来的名称的时候就去查找当前的节点 // 循环出当前名称的一样的组件实例 while (parent && (!name||name!==componentName)) { parent = parent.$parent; if (parent) { name = parent.$options.name; } } // 有节点表示当前找到了name一样的实例 if (parent) { parent.$emit.apply(parent,[eventName].concat(params)) } }, /** * 广播 (向下查找) (广播多个) * @param componentName // 需要找的组件的名称 * @param eventName // 事件名称 * @param params // 需要传递的参数 */ broadcast(componentName, eventName, params) { broadcast.call(this,componentName, eventName, params) } } }
3.async-validator
不懂
async-validator
可以去官网看看 githubyarn add async-validator // 因为当前这个插件是需要打包到项目里的所以不能加-D
4.api设计
我们看一下下面
element
官网的图`form
有2个注入的字段:rules
规则,和:model
当前form的值会通过model
的值和rules
进行匹配来进行校验.form-item
有2个注入的字段lable
和prop
(prop
)是来和form
进行匹配来获取当前的form-item
的值的input
其实有当前的@input
的方法。v-model
就不解释了form
我们在
form
先开始注入当前所有的form-item
实例(获取)created
会在生命周期开始的时候绑定和删除当前实例的方法。通常绑定都在页面dom开始前调用需要在dom
加载完provide
配合inject 使用让子组件可以调用当前父组件的方法以及data下面都写了备注可以放心食用(经过测试当前是可以进行校验的)
form.vue <template> <form> <slot></slot> </form> </template> <script> export default { name: "aiForm", provide(){ // [不懂的可以看看](https://cn.vuejs.org/v2/api/#provide-inject) return { form: this } }, props: { // 当前 form 的model model: { type: Object }, // 验证 rules: { type: Object } }, data(){ return{ fields: [] // 储存当前的 form-item的实例 } }, created(){ // 存当前实例 let that =this; this.$on('on-form-item-add',item=>{ if (item) { that.fields.push(item) } }); // 删除当前有的实例 this.$on('on-form-item-remove',item=>{ if (item.prop) {// 如果当前没有prop的话表示当前不要进行删除(因为没有注入) that.fields.splice(that.fields.indexOf(item),1) } }) }, methods:{ /** * 清空 */ resetFields(){//添加resetFields方法使用的时候调用即可 /** * 当前所有当form-item 进行赋值 */ this.fields.forEach(field => { field.resetField(); }); }, /** * 校验 公开方法:全部校验数据,支持 Promise */ validate(callback){ return new Promise(resolve=>{ /** * 当前所有当form-item 进行校验 */ let valid = true; // 默认是通过 let count = 0; // 来匹配当前是否是全部检查完 this.fields.forEach(field => { // 每个实例都会有 validation 的校验的方法 field.validation('',error=>{ // 只要有一个不符合那么当前的校验就是未通过的 if (error) { valid = false; } // 通过当前检查完所有的form-item的时候才会调用 if (++count === this.fields.length) { resolve(valid);// 方法使用then if (typeof callback === 'function') { callback(valid);// 直接调用注入的回调方法 } } }); }); }) } } } </script>
5.form-item
- form-item比较复杂我们一个一个讲
- isRequired来判断当前是否需要必填
- validateState来判断当前校验的状态
- validateMessage当前的错误的值
- inject: ['form'] 我们就可以通过this.from.xxx来调用父组件的事件以及值了
- computed下的fieldValue可能在不停的变化所以我们通过计算属性来使用
- initialValue 默认的值我们在mounted的时候且当前需要进行校验的时候(prop有的时候)会赋值
- mixins: [Emitter]混合器就是里面的方法以及date都可以在当前调用使用频繁的都可以放在混合器里面
- 我们form-item 会传入input的两个方法blur和change(input原生使用的@input)通过form传入的校验rules里面的trigger来判断
form-item.vue <template> <div> <label :class="isRequired">{{label}}</label> <div> <slot></slot> <div class="ai-form-item-message" v-if="validateState==='error'">{{validateMessage}}</div> </div> </div> </template> <script> import Emitter from '../../mixins/emitter'; import schema from 'async-validator'; export default { name: "aiFormItem", mixins: [Emitter], inject: ['form'], props: { label: { type: String, default: '' }, prop:{ type: String }, }, computed:{ fieldValue () { return this.form.model[this.prop]; }, }, data(){ return { initialValue: '', // 储存默认值 isRequired: false, // 当前的是否有问题 validateState: '', // 是否校验成功 validateMessage: '', // 校验失败文案 } }, methods:{ /** * 绑定事件 进行是否 required 校验 */ setRules(){ let that = this; let rules = this.getRules();//拿到父组件过滤后当前需要使用的规则 if (rules.length) { // every 方法用于检测数组所有元素是否都符合指定条件(通过函数提供) // some 只要有一个符合就返回true this.isRequired = rules.some(rule=>{ // 如果当前校验规则中有必填项,则标记出来 return rule.required; }) } /** * blur 事件 */ this.$on('on-form-blur',that.onFieldBlur); /** * change 事件 */ this.$on('on-form-change',that.onFieldChange) }, /** * 从 Form 的 rules 属性中,获取当前 FormItem 的校验规则 */ getRules () { let that = this; let rules = that.form.rules; rules = rules"color: #ff0000">5.input
- value 支持一个入参
- 因为当前是一个 input 注入的参数是不能直接放到 input 里面使用的所以先赋值给了 defaultValue 然后用 watch 来不停给 defaultValue 赋值达到一个父组件修改后的一个绑定
<template> <input type="text" @input="handleInput" // change @blur="handleBlur" :value="defaultValue" > </template> <script> import Emitter from '../../mixins/emitter.js' export default { name: "aiInput", mixins: [Emitter], props: { value: { type: String, default: '' } }, data(){ return { defaultValue: this.value } }, watch:{ value (val) { this.defaultValue = val; } }, methods:{ /** * change 事件 * @param event */ handleInput(event){ // 当前model 赋值 this.defaultValue = event.target.value; // vue 原生的方法 return 出去 this.$emit('input',event.target.value); // 将当前的值发送到 aiFormItem 进行校验 this.dispatch('aiFormItem','on-form-change',event.target.value) }, /** * blur 事件 * @param event */ handleBlur(event){ // vue 原生的方法 return 出去 this.$emit('blur',event.target.value); // 将当前的值发送到 aiFormItem 进行校验 this.dispatch('aiFormItem','on-form-blur',event.target.value) } } } </script>
最后
最后给上一个当前可以的使用方式
<template> <div class="home"> <button @click="changeButton">测试</button> <ai-form ref="formItems" :model="formValidate" :rules="ruleValidate"> <ai-form-item label="用户名" prop="name"> <ai-input v-model="formValidate.name"/> </ai-form-item> </ai-form> </div> </template> <script> import AiForm from "../components/form/form"; import AiFormItem from "../components/form/form-item"; import AiInput from "../components/input/ai-input"; export default { name: 'home', components: {AiInput, AiFormItem, AiForm},], data(){ return{ formValidate: { name: '123z', mail: '' }, ruleValidate: { name: [ { required: true, message: '用户名不能为空', trigger: 'blur' }, ], } } }, methods:{ changeButton(){ this.$refs.formItems.resetFields() // 清空方法 this.$refs.formItems.validate() // 验证方法 .then(res=>{ console.log(res) }) } }, } </script>
小结
可能现在小伙伴还是不懂。。俗话说;师傅领进门,修行在个人。代码上的备注写的也够多了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!
昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。
这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。
而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?
更新动态
- 雨林唱片《赏》新曲+精选集SACD版[ISO][2.3G]
- 罗大佑与OK男女合唱团.1995-再会吧!素兰【音乐工厂】【WAV+CUE】
- 草蜢.1993-宝贝对不起(国)【宝丽金】【WAV+CUE】
- 杨培安.2009-抒·情(EP)【擎天娱乐】【WAV+CUE】
- 周慧敏《EndlessDream》[WAV+CUE]
- 彭芳《纯色角3》2007[WAV+CUE]
- 江志丰2008-今生为你[豪记][WAV+CUE]
- 罗大佑1994《恋曲2000》音乐工厂[WAV+CUE][1G]
- 群星《一首歌一个故事》赵英俊某些作品重唱企划[FLAC分轨][1G]
- 群星《网易云英文歌曲播放量TOP100》[MP3][1G]
- 方大同.2024-梦想家TheDreamer【赋音乐】【FLAC分轨】
- 李慧珍.2007-爱死了【华谊兄弟】【WAV+CUE】
- 王大文.2019-国际太空站【环球】【FLAC分轨】
- 群星《2022超好听的十倍音质网络歌曲(163)》U盘音乐[WAV分轨][1.1G]
- 童丽《啼笑姻缘》头版限量编号24K金碟[低速原抓WAV+CUE][1.1G]