zoukankan      html  css  js  c++  java
  • Button按钮--inject与provide

    inject 和 provider 是vue中的组合选项,需要一起使用。目的是允许一个祖先组件向其所有子孙后代注入依赖(简单地说就是祖先组件向子孙后代传值的一种方法,祖先组件通过provider提供变量,子孙后代通过inject注入接收变量)

    provider: Object || () => Object

    inject: Array || Object

    Eg.

    button.vue:

     1 <template>
     2   <button
     3     class="el-button"
     4     @click="handleClick"
     5     :disabled="buttonDisabled || loading"
     6     :autofocus="autofocus"
     7     :type="nativeType"
     8     :class="[
     9       type ? 'el-button--' + type : '',
    10       buttonSize ? 'el-button--' + buttonSize : '',
    11       {
    12         'is-disabled': buttonDisabled,
    13         'is-loading': loading,
    14         'is-plain': plain,
    15         'is-round': round,
    16         'is-circle': circle
    17       }
    18     ]"
    19   >
    20     <i class="el-icon-loading" v-if="loading"></i>
    21     <i :class="icon" v-if="icon && !loading"></i>
    22     <span v-if="$slots.default"><slot></slot></span>
    23   </button>
    24 </template>
    25 <script>
    26   export default {
    27     name: 'ElButton',
    28 
    29 //  通过inject向button中注入变量 
    30     inject: {
    31       elForm: {
    32         default: ''
    33       },
    34       elFormItem: {
    35         default: ''
    36       }
    37     },
    38 
    39     props: {
    40       type: {
    41         type: String,
    42         default: 'default'
    43       },
    44       size: String,
    45       icon: {
    46         type: String,
    47         default: ''
    48       },
    49       nativeType: {
    50         type: String,
    51         default: 'button'
    52       },
    53       loading: Boolean,
    54       disabled: Boolean,
    55       plain: Boolean,
    56       autofocus: Boolean,
    57       round: Boolean,
    58       circle: Boolean
    59     },
    60 
    61     computed: {
    62       _elFormItemSize() {
    63         return (this.elFormItem || {}).elFormItemSize;
    64       },
    65       buttonSize() {
    66         return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;   
    67       },
    68       buttonDisabled() {
    69         return this.disabled || (this.elForm || {}).disabled; // 通过inject注入的form变量,获得祖先节点form的disabled属性
    70       }
    71     },
    72 
    73     methods: {
    74       handleClick(evt) {
    75         this.$emit('click', evt);
    76       }
    77     }
    78   };
    79 </script>
    View Code

     form.vue:

      1 <template>
      2   <form class="el-form" :class="[
      3     labelPosition ? 'el-form--label-' + labelPosition : '',
      4     { 'el-form--inline': inline }
      5   ]">
      6     <slot></slot>
      7   </form>
      8 </template>
      9 <script>
     10   import objectAssign from 'element-ui/src/utils/merge';
     11 
     12   export default {
     13     name: 'ElForm',
     14 
     15     componentName: 'ElForm',
     16 
     17     // 通过provider向子孙后代注入变量elform,讲this(即form)注入给子孙后代,后代通过获取此变量获取form中的各种配置,如disabled属性等
     18     provide() {
     19       return {
     20         elForm: this
     21       };
     22     },
     23 
     24     props: {
     25       model: Object,
     26       rules: Object,
     27       labelPosition: String,
     28       labelWidth: String,
     29       labelSuffix: {
     30         type: String,
     31         default: ''
     32       },
     33       inline: Boolean,
     34       inlineMessage: Boolean,
     35       statusIcon: Boolean,
     36       showMessage: {
     37         type: Boolean,
     38         default: true
     39       },
     40       size: String,
     41       disabled: Boolean,
     42       validateOnRuleChange: {
     43         type: Boolean,
     44         default: true
     45       },
     46       hideRequiredAsterisk: {
     47         type: Boolean,
     48         default: false
     49       }
     50     },
     51     watch: {
     52       rules() {
     53         if (this.validateOnRuleChange) {
     54           this.validate(() => {});
     55         }
     56       }
     57     },
     58     data() {
     59       return {
     60         fields: []
     61       };
     62     },
     63     created() {
     64       this.$on('el.form.addField', (field) => {
     65         if (field) {
     66           this.fields.push(field);
     67         }
     68       });
     69       /* istanbul ignore next */
     70       this.$on('el.form.removeField', (field) => {
     71         if (field.prop) {
     72           this.fields.splice(this.fields.indexOf(field), 1);
     73         }
     74       });
     75     },
     76     methods: {
     77       resetFields() {
     78         if (!this.model) {
     79           process.env.NODE_ENV !== 'production' &&
     80           console.warn('[Element Warn][Form]model is required for resetFields to work.');
     81           return;
     82         }
     83         this.fields.forEach(field => {
     84           field.resetField();
     85         });
     86       },
     87       clearValidate(props = []) {
     88         const fields = props.length
     89           ? this.fields.filter(field => props.indexOf(field.prop) > -1)
     90           : this.fields;
     91         fields.forEach(field => {
     92           field.clearValidate();
     93         });
     94       },
     95       validate(callback) {
     96         if (!this.model) {
     97           console.warn('[Element Warn][Form]model is required for validate to work!');
     98           return;
     99         }
    100 
    101         let promise;
    102         // if no callback, return promise
    103         if (typeof callback !== 'function' && window.Promise) {
    104           promise = new window.Promise((resolve, reject) => {
    105             callback = function(valid) {
    106               valid ? resolve(valid) : reject(valid);
    107             };
    108           });
    109         }
    110 
    111         let valid = true;
    112         let count = 0;
    113         // 如果需要验证的fields为空,调用验证时立刻返回callback
    114         if (this.fields.length === 0 && callback) {
    115           callback(true);
    116         }
    117         let invalidFields = {};
    118         this.fields.forEach(field => {
    119           field.validate('', (message, field) => {
    120             if (message) {
    121               valid = false;
    122             }
    123             invalidFields = objectAssign({}, invalidFields, field);
    124             if (typeof callback === 'function' && ++count === this.fields.length) {
    125               callback(valid, invalidFields);
    126             }
    127           });
    128         });
    129 
    130         if (promise) {
    131           return promise;
    132         }
    133       },
    134       validateField(prop, cb) {
    135         let field = this.fields.filter(field => field.prop === prop)[0];
    136         if (!field) { throw new Error('must call validateField with valid prop string!'); }
    137 
    138         field.validate('', cb);
    139       }
    140     }
    141   };
    142 </script>
    View Code

    form-item.vue

      1 <template>
      2   <div class="el-form-item" :class="[{
      3       'el-form-item--feedback': elForm && elForm.statusIcon,
      4       'is-error': validateState === 'error',
      5       'is-validating': validateState === 'validating',
      6       'is-success': validateState === 'success',
      7       'is-required': isRequired || required,
      8       'is-no-asterisk': elForm && elForm.hideRequiredAsterisk
      9     },
     10     sizeClass ? 'el-form-item--' + sizeClass : ''
     11   ]">
     12     <label :for="labelFor" class="el-form-item__label" :style="labelStyle" v-if="label || $slots.label">
     13       <slot name="label">{{label + form.labelSuffix}}</slot>
     14     </label>
     15     <div class="el-form-item__content" :style="contentStyle">
     16       <slot></slot>
     17       <transition name="el-zoom-in-top">
     18         <slot 
     19           v-if="validateState === 'error' && showMessage && form.showMessage" 
     20           name="error" 
     21           :error="validateMessage">
     22           <div
     23             class="el-form-item__error"
     24             :class="{
     25               'el-form-item__error--inline': typeof inlineMessage === 'boolean'
     26                 ? inlineMessage
     27                 : (elForm && elForm.inlineMessage || false)
     28             }"
     29           >
     30             {{validateMessage}}
     31           </div>
     32         </slot>
     33       </transition>
     34     </div>
     35   </div>
     36 </template>
     37 <script>
     38   import AsyncValidator from 'async-validator';
     39   import emitter from 'element-ui/src/mixins/emitter';
     40   import objectAssign from 'element-ui/src/utils/merge';
     41   import { noop, getPropByPath } from 'element-ui/src/utils/util';
     42 
     43   export default {
     44     name: 'ElFormItem',
     45 
     46     componentName: 'ElFormItem',
     47 
     48     mixins: [emitter],
     49 
     50     // 通过provider向子孙后代注入变量elform,讲this(即form-item)注入给子孙后代,后代通过获取此变量获取form中的各种配置,如size属性等
     51     provide() {
     52       return {
     53         elFormItem: this
     54       };
     55     },
     56 
     57     inject: ['elForm'],
     58 
     59     props: {
     60       label: String,
     61       labelWidth: String,
     62       prop: String,
     63       required: {
     64         type: Boolean,
     65         default: undefined
     66       },
     67       rules: [Object, Array],
     68       error: String,
     69       validateStatus: String,
     70       for: String,
     71       inlineMessage: {
     72         type: [String, Boolean],
     73         default: ''
     74       },
     75       showMessage: {
     76         type: Boolean,
     77         default: true
     78       },
     79       size: String
     80     },
     81     watch: {
     82       error: {
     83         immediate: true,
     84         handler(value) {
     85           this.validateMessage = value;
     86           this.validateState = value ? 'error' : '';
     87         }
     88       },
     89       validateStatus(value) {
     90         this.validateState = value;
     91       }
     92     },
     93     computed: {
     94       labelFor() {
     95         return this.for || this.prop;
     96       },
     97       labelStyle() {
     98         const ret = {};
     99         if (this.form.labelPosition === 'top') return ret;
    100         const labelWidth = this.labelWidth || this.form.labelWidth;
    101         if (labelWidth) {
    102           ret.width = labelWidth;
    103         }
    104         return ret;
    105       },
    106       contentStyle() {
    107         const ret = {};
    108         const label = this.label;
    109         if (this.form.labelPosition === 'top' || this.form.inline) return ret;
    110         if (!label && !this.labelWidth && this.isNested) return ret;
    111         const labelWidth = this.labelWidth || this.form.labelWidth;
    112         if (labelWidth) {
    113           ret.marginLeft = labelWidth;
    114         }
    115         return ret;
    116       },
    117       form() {
    118         let parent = this.$parent;
    119         let parentName = parent.$options.componentName;
    120         while (parentName !== 'ElForm') {
    121           if (parentName === 'ElFormItem') {
    122             this.isNested = true;
    123           }
    124           parent = parent.$parent;
    125           parentName = parent.$options.componentName;
    126         }
    127         return parent;
    128       },
    129       fieldValue() {
    130         const model = this.form.model;
    131         if (!model || !this.prop) { return; }
    132 
    133         let path = this.prop;
    134         if (path.indexOf(':') !== -1) {
    135           path = path.replace(/:/, '.');
    136         }
    137 
    138         return getPropByPath(model, path, true).v;
    139       },
    140       isRequired() {
    141         let rules = this.getRules();
    142         let isRequired = false;
    143 
    144         if (rules && rules.length) {
    145           rules.every(rule => {
    146             if (rule.required) {
    147               isRequired = true;
    148               return false;
    149             }
    150             return true;
    151           });
    152         }
    153         return isRequired;
    154       },
    155       _formSize() {
    156         return this.elForm.size;
    157       },
    158       elFormItemSize() {
    159         return this.size || this._formSize;
    160       },
    161       sizeClass() {
    162         return this.elFormItemSize || (this.$ELEMENT || {}).size;
    163       }
    164     },
    165     data() {
    166       return {
    167         validateState: '',
    168         validateMessage: '',
    169         validateDisabled: false,
    170         validator: {},
    171         isNested: false
    172       };
    173     },
    174     methods: {
    175       validate(trigger, callback = noop) {
    176         this.validateDisabled = false;
    177         const rules = this.getFilteredRule(trigger);
    178         if ((!rules || rules.length === 0) && this.required === undefined) {
    179           callback();
    180           return true;
    181         }
    182 
    183         this.validateState = 'validating';
    184 
    185         const descriptor = {};
    186         if (rules && rules.length > 0) {
    187           rules.forEach(rule => {
    188             delete rule.trigger;
    189           });
    190         }
    191         descriptor[this.prop] = rules;
    192 
    193         const validator = new AsyncValidator(descriptor);
    194         const model = {};
    195 
    196         model[this.prop] = this.fieldValue;
    197 
    198         validator.validate(model, { firstFields: true }, (errors, invalidFields) => {
    199           this.validateState = !errors ? 'success' : 'error';
    200           this.validateMessage = errors ? errors[0].message : '';
    201 
    202           callback(this.validateMessage, invalidFields);
    203           this.elForm && this.elForm.$emit('validate', this.prop, !errors, this.validateMessage || null);
    204         });
    205       },
    206       clearValidate() {
    207         this.validateState = '';
    208         this.validateMessage = '';
    209         this.validateDisabled = false;
    210       },
    211       resetField() {
    212         this.validateState = '';
    213         this.validateMessage = '';
    214 
    215         let model = this.form.model;
    216         let value = this.fieldValue;
    217         let path = this.prop;
    218         if (path.indexOf(':') !== -1) {
    219           path = path.replace(/:/, '.');
    220         }
    221 
    222         let prop = getPropByPath(model, path, true);
    223 
    224         this.validateDisabled = true;
    225         if (Array.isArray(value)) {
    226           prop.o[prop.k] = [].concat(this.initialValue);
    227         } else {
    228           prop.o[prop.k] = this.initialValue;
    229         }
    230 
    231         this.broadcast('ElTimeSelect', 'fieldReset', this.initialValue);
    232       },
    233       getRules() {
    234         let formRules = this.form.rules;
    235         const selfRules = this.rules;
    236         const requiredRule = this.required !== undefined ? { required: !!this.required } : [];
    237 
    238         const prop = getPropByPath(formRules, this.prop || '');
    239         formRules = formRules ? (prop.o[this.prop || ''] || prop.v) : [];
    240 
    241         return [].concat(selfRules || formRules || []).concat(requiredRule);
    242       },
    243       getFilteredRule(trigger) {
    244         const rules = this.getRules();
    245 
    246         return rules.filter(rule => {
    247           if (!rule.trigger || trigger === '') return true;
    248           if (Array.isArray(rule.trigger)) {
    249             return rule.trigger.indexOf(trigger) > -1;
    250           } else {
    251             return rule.trigger === trigger;
    252           }
    253         }).map(rule => objectAssign({}, rule));
    254       },
    255       onFieldBlur() {
    256         this.validate('blur');
    257       },
    258       onFieldChange() {
    259         if (this.validateDisabled) {
    260           this.validateDisabled = false;
    261           return;
    262         }
    263 
    264         this.validate('change');
    265       }
    266     },
    267     mounted() {
    268       if (this.prop) {
    269         this.dispatch('ElForm', 'el.form.addField', [this]);
    270 
    271         let initialValue = this.fieldValue;
    272         if (Array.isArray(initialValue)) {
    273           initialValue = [].concat(initialValue);
    274         }
    275         Object.defineProperty(this, 'initialValue', {
    276           value: initialValue
    277         });
    278 
    279         let rules = this.getRules();
    280 
    281         if (rules.length || this.required !== undefined) {
    282           this.$on('el.form.blur', this.onFieldBlur);
    283           this.$on('el.form.change', this.onFieldChange);
    284         }
    285       }
    286     },
    287     beforeDestroy() {
    288       this.dispatch('ElForm', 'el.form.removeField', [this]);
    289     }
    290   };
    291 </script>
    View Code
  • 相关阅读:
    Python爬取网页信息
    C++面向程序设计(第二版)课后习题答案解析
    蓝桥杯——算法分析
    python爬虫——数据爬取和具体解析
    python爬虫——爬取网页数据和解析数据
    Python文件的读写操作
    C++第三章课后作业答案及解析---指针的使用
    C语言蓝桥杯比赛原题和解析
    Web开发技术---简单的登录验证
    C++面向对象程序设计第三章习题答案解析
  • 原文地址:https://www.cnblogs.com/hihao/p/9747662.html
Copyright © 2011-2022 走看看