新建form表单

elementui 数字大小验证 element校验_elementui 数字大小验证

传递的是响应式对象,直接把当前对象传递过去,this指代是当前表单的实例。

elementui 数字大小验证 element校验_element子组件中的校验_02

model:model作用:统一管理;prop:为了获取当前输入框中的值

elementui 数字大小验证 element校验_Boo_03

elementui 数字大小验证 element校验_ide_04

elementui 数字大小验证 element校验_element子组件中的校验_05

开始校验

思考:(1)在什么地方通知校验?

KInput组件中通知,当数值发生变化时,会通知校验开始。

(2)如果触发事件为blur该怎样做?

???

告诉父组件该去做校验了

你是否第一时间想到的是这样做?

elementui 数字大小验证 element校验_Boo_06

然而在KFormItem中,仍然是个slot,不能在slot中加事件

elementui 数字大小验证 element校验_vue rules 两个输入框不能相等_07

如果用event bus则强制用户必须设置一个bus(弃之)

所以是不是应该这样

通过父组件去派发事件

elementui 数字大小验证 element校验_ide_08

KFormitem中,自己派发自己监听

elementui 数字大小验证 element校验_vue rules 两个输入框不能相等_09

导入使用库,Schme:当前校验的规则

elementui 数字大小验证 element校验_elementui 数字大小验证_10

elementui 数字大小验证 element校验_vue rules 两个输入框不能相等_11

elementui 数字大小验证 element校验_ide_12

elementui 数字大小验证 element校验_vue rules 两个输入框不能相等_13

elementui 数字大小验证 element校验_vue rules 两个输入框不能相等_14

添加一个登录按钮

elementui 数字大小验证 element校验_Boo_15

elementui 数字大小验证 element校验_Boo_16

实现一个全局校验方法

思考:若用户不按套路出牌的情况下,以下代码将不健壮,该怎样做?

elementui 数字大小验证 element校验_vue rules 两个输入框不能相等_17

意想不到的事情发生了

elementui 数字大小验证 element校验_ide_18

思考:为什么会这样呢?

formItem中并不是所有的项都有prop属性,所以需要过滤一下

elementui 数字大小验证 element校验_ide_19

解决方法如下:

elementui 数字大小验证 element校验_element子组件中的校验_20

思考:以上写法中不严谨的地方,可以怎样改进?

(第一处)

elementui 数字大小验证 element校验_elementui 数字大小验证_21

(第二处)

elementui 数字大小验证 element校验_Boo_22

实现弹框组件

弹窗这类组件的特点是它们在当前vue实例之外独立存在,通常挂载于body;它们是通过JS动态创建的,不需要在任何组件中声明。常⻅使用方式:

this.$create(Notice, {title: '村长喊你来搬砖',message: '提示信息',duration: 1000
}).show()

;

实现:

挂载是一种覆盖行为,不能直接mount(‘body’)

elementui 数字大小验证 element校验_Boo_23

elementui 数字大小验证 element校验_elementui 数字大小验证_24

create函数:返回组件实例

elementui 数字大小验证 element校验_ide_25

通知组件

建通知组件,Notice.vue

{{title}}
{{message}}
 
  
export default {
  props: {
    title: {
      type: String,
      default: ""
}, message: {
      type: String,
      default: ""
    },
    duration: {
      type: Number,
      default: 1000
} },
  data() {
    return {
      isShow: false
    };
}, methods: {
show() {
this.isShow=true;
setTimeout(this.hide, this.duration);
    },hide() {      this.isShow = false;      this.remove();} }
};
.box {  position: fixed;  width: 100%;  top: 16px;  left: 0;  text-align: center;  pointer-events: none;  background-color: #fff;  border: grey 3px solid;  box-sizing: border-box;}.box-content {width: 200px;  margin: 10px auto;  font-size: 14px;  padding: 8px 16px;  background: #fff;  border-radius: 3px;  margin-bottom: 8px;}

使用

elementui 数字大小验证 element校验_ide_26

elementui 数字大小验证 element校验_elementui 数字大小验证_27

关于作业

elementui 数字大小验证 element校验_ide_28

思考拓展

1、修正input中$parent写法的问题

跟组件从上往下去广播?,从跟组件自上而下去广播,告诉大家发生了什么事件,让大家去做监听

elementui 数字大小验证 element校验_ide_29

从下网上,从里往外

elementui 数字大小验证 element校验_Boo_30

2、学习element源码

链接地址:github.com/ElemenFE/element

elementui 数字大小验证 element校验_element子组件中的校验_31

思考问题讲解:

1、修正input中$parent写法问题

修正formItem中因父组件找不到问题

(1)mixin emitter
    (2)声明componentName
    (3)dispatch()
广播:自上而下派发事件
function broadcast(componentName, eventName, params) {
//遍历所有的子元素,如果子元素componentName和传入的相同则派发事件
  this.$children.forEach(child => {
    var name = child.$options.componentName;
    if (name === componentName) {
      child.$emit.apply(child, [eventName].concat(params));
    } else {
      broadcast.apply(child, [componentName, eventName].concat([params]));
    }
  });
}
export default {
  methods: {
//冒泡查找compantName相同的组件并派发事件
    dispatch(componentName, eventName, params) {
      var parent = this.$parent || this.$root;
      var name = parent.$options.componentName;
//向上查找直到找到相同名称的组件
      while (parent && (!name || name !== componentName)) {
        parent = parent.$parent;
        if (parent) {
          name = parent.$options.componentName;
        }
      }
//如果找到就派发事件
      if (parent) {
//通过apply的方式指定上下文,所有的参数会用concat进行拼接,结果依然是个数组
        parent.$emit.apply(parent, [eventName].concat(params));
      }
    },
    broadcast(componentName, eventName, params) {
      broadcast.call(this, componentName, eventName, params);
    }
  }
};

elementui 数字大小验证 element校验_Boo_32

elementui 数字大小验证 element校验_elementui 数字大小验证_33

elementui 数字大小验证 element校验_elementui 数字大小验证_34

elementui 数字大小验证 element校验_elementui 数字大小验证_35

修改$children

element源码参考:

import objectAssign from 'element-ui/src/utils/merge';
  export default {
    name: 'ElForm',
    componentName: 'ElForm',
    provide() {
      return {
        elForm: this
      };
    },
    props: {
      model: Object,
      rules: Object,
      labelPosition: String,
      labelWidth: String,
      labelSuffix: {
        type: String,
        default: ''
      },
      inline: Boolean,
      inlineMessage: Boolean,
      statusIcon: Boolean,
      showMessage: {
        type: Boolean,
        default: true
      },
      size: String,
      disabled: Boolean,
      validateOnRuleChange: {
        type: Boolean,
        default: true
      },
      hideRequiredAsterisk: {
        type: Boolean,
        default: false
      }
    },
    watch: {
      rules() {
        // remove then add event listeners on form-item after form rules change
        this.fields.forEach(field => {
          field.removeValidateEvents();
          field.addValidateEvents();
        });
        if (this.validateOnRuleChange) {
          this.validate(() => {});
        }
      }
    },
    computed: {
      autoLabelWidth() {
        if (!this.potentialLabelWidthArr.length) return 0;
        const max = Math.max(...this.potentialLabelWidthArr);
        return max ? `${max}px` : '';
      }
    },
    data() {
      return {
        fields: [],
        potentialLabelWidthArr: [] // use this array to calculate auto width
      };
    },
    created() {
      this.$on('el.form.addField', (field) => {
        if (field) {
          this.fields.push(field);
        }
      });
      /* istanbul ignore next */
      this.$on('el.form.removeField', (field) => {
        if (field.prop) {
          this.fields.splice(this.fields.indexOf(field), 1);
        }
      });
    },
    methods: {
      resetFields() {
        if (!this.model) {
          console.warn('[Element Warn][Form]model is required for resetFields to work.');
          return;
        }
        this.fields.forEach(field => {
          field.resetField();
        });
      },
      clearValidate(props = []) {
        const fields = props.length
          ? (typeof props === 'string'
            ? this.fields.filter(field => props === field.prop)
            : this.fields.filter(field => props.indexOf(field.prop) > -1)
          ) : this.fields;
        fields.forEach(field => {
          field.clearValidate();
        });
      },
      validate(callback) {
        if (!this.model) {
          console.warn('[Element Warn][Form]model is required for validate to work!');
          return;
        }
        let promise;
        // if no callback, return promise
        if (typeof callback !== 'function' && window.Promise) {
          promise = new window.Promise((resolve, reject) => {
            callback = function(valid) {
              valid ? resolve(valid) : reject(valid);
            };
          });
        }
        let valid = true;
        let count = 0;
        // 如果需要验证的fields为空,调用验证时立刻返回callback
        if (this.fields.length === 0 && callback) {
          callback(true);
        }
        let invalidFields = {};
        this.fields.forEach(field => {
          field.validate('', (message, field) => {
            if (message) {
              valid = false;
            }
            invalidFields = objectAssign({}, invalidFields, field);
            if (typeof callback === 'function' && ++count === this.fields.length) {
              callback(valid, invalidFields);
            }
          });
        });
        if (promise) {
          return promise;
        }
      },
      validateField(props, cb) {
        props = [].concat(props);
        const fields = this.fields.filter(field => props.indexOf(field.prop) !== -1);
        if (!fields.length) {
          console.warn('[Element Warn]please pass correct props!');
          return;
        }
        fields.forEach(field => {
          field.validate('', cb);
        });
      },
      getLabelWidthIndex(width) {
        const index = this.potentialLabelWidthArr.indexOf(width);
        // it's impossible
        if (index === -1) {
          throw new Error('[ElementForm]unpected width ', width);
        }
        return index;
      },
      registerLabelWidth(val, oldVal) {
        if (val && oldVal) {
          const index = this.getLabelWidthIndex(oldVal);
          this.potentialLabelWidthArr.splice(index, 1, val);
        } else if (val) {
          this.potentialLabelWidthArr.push(val);
        }
      },
      deregisterLabelWidth(val) {
        const index = this.getLabelWidthIndex(val);
        this.potentialLabelWidthArr.splice(index, 1);
      }
    }
  };

自己实现:

elementui 数字大小验证 element校验_element子组件中的校验_36

elementui 数字大小验证 element校验_elementui 数字大小验证_37

elementui 数字大小验证 element校验_element子组件中的校验_38

elementui 数字大小验证 element校验_vue rules 两个输入框不能相等_39

2、使用vue.extend方式实现create方法

Vue.extend
const comp={data:{},props:{}}
const Ctor=Vue.extend(comp)
new Ctor({propsData:{}})

elementui 数字大小验证 element校验_vue rules 两个输入框不能相等_40

elementui 数字大小验证 element校验_Boo_41