修改MDinput组件
1.使之能兼容elementui的表单验证功能 2.增加icon属性,能够使用elementui的图标 3.优化显示效果
This commit is contained in:
		| @@ -1,297 +1,294 @@ | |||||||
| <template> | <template> | ||||||
|   <div class="material-input__component" :class="computedClasses"> |   <div class="material-input__component" :class="computedClasses"> | ||||||
|     <input v-if="type === 'email'" type="email" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy" |     <div :class="{iconClass:icon}"> | ||||||
|       :readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :required="required" @focus="handleFocus(true)" |       <i class="el-input__icon material-input__icon" :class="['el-icon-' + icon]" v-if="icon"></i> | ||||||
|       @blur="handleFocus(false)" @input="handleModelInput"> |       <input v-if="type === 'email'" type="email" class="material-input" :name="name" | ||||||
|     <input v-if="type === 'url'" type="url" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy" |              :placeholder="fillPlaceHolder" v-model="currentValue" | ||||||
|       :readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :required="required" @focus="handleFocus(true)" |              :readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :required="required" | ||||||
|       @blur="handleFocus(false)" @input="handleModelInput"> |              @focus="handleMdFocus" | ||||||
|     <input v-if="type === 'number'" type="number" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy" |              @blur="handleMdBlur" @input="handleModelInput"> | ||||||
|       :readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :max="max" :min="min" :minlength="minlength" :maxlength="maxlength" |       <input v-if="type === 'url'" type="url" class="material-input" :name="name" | ||||||
|       :required="required" @focus="handleFocus(true)" @blur="handleFocus(false)" @input="handleModelInput"> |              :placeholder="fillPlaceHolder" | ||||||
|     <input v-if="type === 'password'" type="password" class="material-input" :name="name" :id="id" :placeholder="placeholder" |              v-model="currentValue" | ||||||
|       v-model="valueCopy" :readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :max="max" :min="min" :required="required" |              :readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :required="required" | ||||||
|       @focus="handleFocus(true)" @blur="handleFocus(false)" @input="handleModelInput"> |              @focus="handleMdFocus" | ||||||
|     <input v-if="type === 'tel'" type="tel" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy" |              @blur="handleMdBlur" @input="handleModelInput"> | ||||||
|       :readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :required="required" @focus="handleFocus(true)" |       <input v-if="type === 'number'" type="number" class="material-input" :name="name" | ||||||
|       @blur="handleFocus(false)" @input="handleModelInput"> |              :placeholder="fillPlaceHolder" v-model="currentValue" :step="step" | ||||||
|     <input v-if="type === 'text'" type="text" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy" |              :readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :max="max" :min="min" | ||||||
|       :readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :minlength="minlength" :maxlength="maxlength" |              :minlength="minlength" :maxlength="maxlength" | ||||||
|       :required="required" @focus="handleFocus(true)" @blur="handleFocus(false)" @input="handleModelInput"> |              :required="required" @focus="handleMdFocus" @blur="handleMdBlur" @input="handleModelInput"> | ||||||
|  |       <input v-if="type === 'password'" type="password" class="material-input" :name="name" | ||||||
|  |              :placeholder="fillPlaceHolder" | ||||||
|  |              v-model="currentValue" :readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :max="max" | ||||||
|  |              :min="min" :required="required" | ||||||
|  |              @focus="handleMdFocus" @blur="handleMdBlur" @input="handleModelInput"> | ||||||
|  |       <input v-if="type === 'tel'" type="tel" class="material-input" :name="name" | ||||||
|  |              :placeholder="fillPlaceHolder" | ||||||
|  |              v-model="currentValue" | ||||||
|  |              :readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :required="required" | ||||||
|  |              @focus="handleMdFocus" | ||||||
|  |              @blur="handleMdBlur" @input="handleModelInput"> | ||||||
|  |       <input v-if="type === 'text'" type="text" class="material-input" :name="name" | ||||||
|  |              :placeholder="fillPlaceHolder" v-model="currentValue" | ||||||
|  |              :readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :minlength="minlength" | ||||||
|  |              :maxlength="maxlength" | ||||||
|  |              :required="required" @focus="handleMdFocus" @blur="handleMdBlur" @input="handleModelInput"> | ||||||
|  |  | ||||||
|     <span class="material-input-bar"></span> |       <span class="material-input-bar"></span> | ||||||
|  |  | ||||||
|  |       <label class="material-label"> | ||||||
|  |         <slot></slot> | ||||||
|  |       </label> | ||||||
|  |  | ||||||
|     <label class="material-label"> |  | ||||||
|             <slot></slot> |  | ||||||
|         </label> |  | ||||||
|     <div v-if="errorMessages" class="material-errors"> |  | ||||||
|       <div v-for="error in computedErrors" class="material-error" :key='error'> |  | ||||||
|         {{ error }} |  | ||||||
|       </div> |  | ||||||
|     </div> |     </div> | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script> | <script> | ||||||
| 	// source:https://github.com/wemake-services/vue-material-input/blob/master/src/components/MaterialInput.vue |   // source:https://github.com/wemake-services/vue-material-input/blob/master/src/components/MaterialInput.vue | ||||||
| export default { |  | ||||||
|   name: 'material-input', |   export default { | ||||||
|   computed: { |  | ||||||
|     computedErrors() { |     name: 'md-input', | ||||||
|       return typeof this.errorMessages === 'string' |     computed: { | ||||||
|                         ? [this.errorMessages] : this.errorMessages |       computedClasses() { | ||||||
|  |         return { | ||||||
|  |           'material--active': this.focus, | ||||||
|  |           'material--disabled': this.disabled, | ||||||
|  |           'material--raised': Boolean(this.focus || this.currentValue) // has value | ||||||
|  |         } | ||||||
|  |       } | ||||||
|     }, |     }, | ||||||
|     computedClasses() { |     data() { | ||||||
|       return { |       return { | ||||||
|         'material--active': this.focus, |         currentValue: this.value, | ||||||
|         'material--disabled': this.disabled, |         focus: false, | ||||||
|         'material--has-errors': Boolean(!this.valid || (this.errorMessages && this.errorMessages.length)), |         fillPlaceHolder: null | ||||||
|         'material--raised': Boolean(this.focus || this.valueCopy || // has value |       } | ||||||
|                             (this.placeholder && !this.valueCopy)) // has placeholder |     }, | ||||||
|  |     methods: { | ||||||
|  |       handleModelInput(event) { | ||||||
|  |         const value = event.target.value | ||||||
|  |         this.$emit('input', value) | ||||||
|  |         if (this.$parent.$options.componentName === 'ElFormItem') { | ||||||
|  |           if (this.validateEvent) { | ||||||
|  |             this.$parent.$emit('el.form.change', [value]) | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |         this.$emit('change', value) | ||||||
|  | //				this.handleValidation() | ||||||
|  |       }, | ||||||
|  |       handleMdFocus(event) { | ||||||
|  |         this.focus = true | ||||||
|  |         this.$emit('focus', event) | ||||||
|  |         if (this.placeholder && this.placeholder !== '') { | ||||||
|  |           this.fillPlaceHolder = this.placeholder | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       handleMdBlur(event) { | ||||||
|  |         this.focus = false | ||||||
|  |         this.$emit('blur', event) | ||||||
|  |         this.fillPlaceHolder = null | ||||||
|  |         if (this.$parent.$options.componentName === 'ElFormItem') { | ||||||
|  |           if (this.validateEvent) { | ||||||
|  |             this.$parent.$emit('el.form.blur', [this.currentValue]) | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     props: { | ||||||
|  |       icon: String, | ||||||
|  |       name: String, | ||||||
|  |       type: { | ||||||
|  |         type: String, | ||||||
|  |         default: 'text' | ||||||
|  |       }, | ||||||
|  |       value: [String, Number], | ||||||
|  |       placeholder: String, | ||||||
|  |       readonly: Boolean, | ||||||
|  |       disabled: Boolean, | ||||||
|  |       min: String, | ||||||
|  |       max: String, | ||||||
|  |       step: String, | ||||||
|  |       minlength: Number, | ||||||
|  |       maxlength: Number, | ||||||
|  |       required: { | ||||||
|  |         type: Boolean, | ||||||
|  |         default: true | ||||||
|  |       }, | ||||||
|  |       autoComplete: { | ||||||
|  |         type: String, | ||||||
|  |         default: 'off' | ||||||
|  |       }, | ||||||
|  |       validateEvent: { | ||||||
|  |         type: Boolean, | ||||||
|  |         default: true | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   }, |  | ||||||
|   data() { |  | ||||||
|     return { |  | ||||||
|       valueCopy: null, |  | ||||||
|       focus: false, |  | ||||||
|       valid: true |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   beforeMount() { |  | ||||||
|         // Here we are following the Vue2 convention on custom v-model: |  | ||||||
|         // https://github.com/vuejs/vue/issues/2873#issuecomment-223759341 |  | ||||||
|     this.copyValue(this.value) |  | ||||||
|   }, |  | ||||||
|   methods: { |  | ||||||
|     handleModelInput(event) { |  | ||||||
|       this.$emit('input', event.target.value, event) |  | ||||||
|       this.handleValidation() |  | ||||||
|     }, |  | ||||||
|     handleFocus(focused) { |  | ||||||
|       this.focus = focused |  | ||||||
|     }, |  | ||||||
|     handleValidation() { |  | ||||||
|       this.valid = this.$el ? this.$el.querySelector('.material-input').validity.valid : this.valid |  | ||||||
|     }, |  | ||||||
|     copyValue(value) { |  | ||||||
|       this.valueCopy = value |  | ||||||
|       this.handleValidation() |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   watch: { |  | ||||||
|     value(newValue) { |  | ||||||
|       this.copyValue(newValue) |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   props: { |  | ||||||
|     id: { |  | ||||||
|       type: String, |  | ||||||
|       default: null |  | ||||||
|     }, |  | ||||||
|     name: { |  | ||||||
|       type: String, |  | ||||||
|       default: null |  | ||||||
|     }, |  | ||||||
|     type: { |  | ||||||
|       type: String, |  | ||||||
|       default: 'text' |  | ||||||
|     }, |  | ||||||
|     value: { |  | ||||||
|       default: null |  | ||||||
|     }, |  | ||||||
|     placeholder: { |  | ||||||
|       type: String, |  | ||||||
|       default: null |  | ||||||
|     }, |  | ||||||
|     readonly: { |  | ||||||
|       type: Boolean, |  | ||||||
|       default: false |  | ||||||
|     }, |  | ||||||
|     disabled: { |  | ||||||
|       type: Boolean, |  | ||||||
|       default: false |  | ||||||
|     }, |  | ||||||
|     min: { |  | ||||||
|       type: String, |  | ||||||
|       default: null |  | ||||||
|     }, |  | ||||||
|     max: { |  | ||||||
|       type: String, |  | ||||||
|       default: null |  | ||||||
|     }, |  | ||||||
|     minlength: { |  | ||||||
|       type: Number, |  | ||||||
|       default: null |  | ||||||
|     }, |  | ||||||
|     maxlength: { |  | ||||||
|       type: Number, |  | ||||||
|       default: null |  | ||||||
|     }, |  | ||||||
|     required: { |  | ||||||
|       type: Boolean, |  | ||||||
|       default: true |  | ||||||
|     }, |  | ||||||
|     autocomplete: { |  | ||||||
|       type: String, |  | ||||||
|       default: 'off' |  | ||||||
|     }, |  | ||||||
|     errorMessages: { |  | ||||||
|       type: [Array, String], |  | ||||||
|       default: null |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
| } |  | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <style rel="stylesheet/scss" lang="scss" scoped> | <style rel="stylesheet/scss" lang="scss" scoped> | ||||||
|     // Fonts: |   // Fonts: | ||||||
|     $font-size-base: 16px; |   $font-size-base: 16px; | ||||||
|     $font-size-small: 18px; |   $font-size-small: 18px; | ||||||
|     $font-size-smallest: 12px; |   $font-size-smallest: 12px; | ||||||
|     $font-weight-normal: normal; |   $font-weight-normal: normal; | ||||||
|     // Utils |   $font-weight-bold: bold; | ||||||
|     $spacer: 12px; |   $apixel: 1px; | ||||||
|     $transition: 0.2s ease all; |   // Utils | ||||||
|     // Base clases: |   $spacer: 12px; | ||||||
|     %base-bar-pseudo { |   $transition: 0.2s ease all; | ||||||
|         content: ''; |   $index: 0px; | ||||||
|         height: 1px; |   $index-has-icon: 30px; | ||||||
|         width: 0; |   // Theme: | ||||||
|         bottom: 0; |   $color-white: white; | ||||||
|  |   $color-grey: #9E9E9E; | ||||||
|  |   $color-grey-light: #E0E0E0; | ||||||
|  |   $color-blue: #2196F3; | ||||||
|  |   $color-red: #F44336; | ||||||
|  |   $color-black: black; | ||||||
|  |   // Base clases: | ||||||
|  |   %base-bar-pseudo { | ||||||
|  |     content: ''; | ||||||
|  |     height: 1px; | ||||||
|  |     width: 0; | ||||||
|  |     bottom: 0; | ||||||
|  |     position: absolute; | ||||||
|  |     transition: $transition; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Mixins: | ||||||
|  |   @mixin slided-top() { | ||||||
|  |     top: - ($font-size-base + $spacer); | ||||||
|  |     left: 0; | ||||||
|  |     font-size: $font-size-base; | ||||||
|  |     font-weight: $font-weight-bold; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Component: | ||||||
|  |   .material-input__component { | ||||||
|  |     margin-top: 36px; | ||||||
|  |     position: relative; | ||||||
|  |     * { | ||||||
|  |       box-sizing: border-box; | ||||||
|  |     } | ||||||
|  |     .iconClass { | ||||||
|  |       .material-input__icon { | ||||||
|         position: absolute; |         position: absolute; | ||||||
|         transition: $transition; |         left: 0; | ||||||
|  |         color: $color-blue; | ||||||
|  |         top: $spacer; | ||||||
|  |         width: $index-has-icon; | ||||||
|  |         height: $font-size-base; | ||||||
|  |         font-size: $font-size-base; | ||||||
|  |         font-weight: $font-weight-normal; | ||||||
|  |         pointer-events: none; | ||||||
|  |       } | ||||||
|  |       .material-label { | ||||||
|  |         left: $index-has-icon; | ||||||
|  |       } | ||||||
|  |       .material-input { | ||||||
|  |         text-indent: $index-has-icon; | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|  |     .material-input { | ||||||
|     // Mixins: |       font-size: $font-size-base; | ||||||
|     @mixin slided-top() { |       padding: $spacer $spacer $spacer - $apixel * 10 $spacer / 2; | ||||||
|         top: -2 * $spacer; |       display: block; | ||||||
|         font-size: $font-size-small; |       width: 100%; | ||||||
|  |       border: none; | ||||||
|  |       line-height: 1; | ||||||
|  |       border-radius: 0; | ||||||
|  |       &:focus { | ||||||
|  |         outline: none; | ||||||
|  |         border: none; | ||||||
|  |         border-bottom: 1px solid transparent; // fixes the height issue | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|  |     .material-label { | ||||||
|     // Component: |       font-weight: $font-weight-normal; | ||||||
|     .material-input__component { |       position: absolute; | ||||||
|         /*margin-top: 30px;*/ |       pointer-events: none; | ||||||
|         position: relative; |       left: $index; | ||||||
|         * { |       top: 0; | ||||||
|             box-sizing: border-box; |       transition: $transition; | ||||||
|         } |       font-size: $font-size-small; | ||||||
|         .material-input { |  | ||||||
|             font-size: $font-size-base; |  | ||||||
|             padding: $spacer $spacer $spacer $spacer / 2; |  | ||||||
|             display: block; |  | ||||||
|             width: 100%; |  | ||||||
|             border: none; |  | ||||||
|             border-radius: 0; |  | ||||||
|             &:focus { |  | ||||||
|                 outline: none; |  | ||||||
|                 border: none; |  | ||||||
|                 border-bottom: 1px solid transparent; // fixes the height issue |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         .material-label { |  | ||||||
|             font-size: $font-size-base; |  | ||||||
|             font-weight: $font-weight-normal; |  | ||||||
|             position: absolute; |  | ||||||
|             pointer-events: none; |  | ||||||
|             left: 0; |  | ||||||
|             top: $spacer; |  | ||||||
|             transition: $transition; |  | ||||||
|         } |  | ||||||
|         .material-input-bar { |  | ||||||
|             position: relative; |  | ||||||
|             display: block; |  | ||||||
|             width: 100%; |  | ||||||
|             &:before { |  | ||||||
|                 @extend %base-bar-pseudo; |  | ||||||
|                 left: 50%; |  | ||||||
|             } |  | ||||||
|             &:after { |  | ||||||
|                 @extend %base-bar-pseudo; |  | ||||||
|                 right: 50%; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         // Disabled state: |  | ||||||
|         &.material--disabled { |  | ||||||
|             .material-input { |  | ||||||
|                 border-bottom-style: dashed; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         // Raised state: |  | ||||||
|         &.material--raised { |  | ||||||
|             .material-label { |  | ||||||
|                 @include slided-top(); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         // Active state: |  | ||||||
|         &.material--active { |  | ||||||
|             .material-input-bar { |  | ||||||
|                 &:before, |  | ||||||
|                 &:after { |  | ||||||
|                     width: 50%; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         // Errors: |  | ||||||
|         .material-errors { |  | ||||||
|             position: relative; |  | ||||||
|             overflow: hidden; |  | ||||||
|             .material-error { |  | ||||||
|                 font-size: $font-size-smallest; |  | ||||||
|                 line-height: $font-size-smallest + 2px; |  | ||||||
|                 overflow: hidden; |  | ||||||
|                 margin-top: 0; |  | ||||||
|                 padding-top: $spacer / 2; |  | ||||||
|                 padding-right: $spacer / 2; |  | ||||||
|                 padding-left: 0; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |     .material-input-bar { | ||||||
|  |       position: relative; | ||||||
|  |       display: block; | ||||||
|  |       width: 100%; | ||||||
|  |       &:before { | ||||||
|  |         @extend %base-bar-pseudo; | ||||||
|  |         left: 50%; | ||||||
|  |       } | ||||||
|  |       &:after { | ||||||
|  |         @extend %base-bar-pseudo; | ||||||
|  |         right: 50%; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     // Disabled state: | ||||||
|  |     &.material--disabled { | ||||||
|  |       .material-input { | ||||||
|  |         border-bottom-style: dashed; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     // Raised state: | ||||||
|  |     &.material--raised { | ||||||
|  |       .material-label { | ||||||
|  |         @include slided-top(); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     // Active state: | ||||||
|  |     &.material--active { | ||||||
|  |       .material-input-bar { | ||||||
|  |         &:before, | ||||||
|  |         &:after { | ||||||
|  |           width: 50%; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|     // Theme: |   .material-input__component { | ||||||
|     $color-white: white; |     background: $color-white; | ||||||
|     $color-grey: #9E9E9E; |     .material-input { | ||||||
|     $color-grey-light: #E0E0E0; |       background: none; | ||||||
|     $color-blue: #2196F3; |       color: $color-black; | ||||||
|     $color-red: #F44336; |       text-indent: $index; | ||||||
|     $color-black: black; |       border-bottom: 1px solid $color-grey-light; | ||||||
|     .material-input__component { |     } | ||||||
|         background: $color-white; |     .material-label { | ||||||
|         .material-input { |       color: $color-grey; | ||||||
|             background: none; |     } | ||||||
|             color: $color-black; |     .material-input-bar { | ||||||
|             text-indent: 30px; |       &:before, | ||||||
|             border-bottom: 1px solid $color-grey-light; |       &:after { | ||||||
|  |         background: $color-blue; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     // Active state: | ||||||
|  |     &.material--active { | ||||||
|  |       .material-label { | ||||||
|  |         color: $color-blue; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     // Errors: | ||||||
|  |     &.material--has-errors { | ||||||
|  |       &.material--active .material-label { | ||||||
|  |         color: $color-red; | ||||||
|  |       } | ||||||
|  |       .material-input-bar { | ||||||
|  |         &:before, | ||||||
|  |         &:after { | ||||||
|  |           background: transparent; | ||||||
|         } |         } | ||||||
|         .material-label { |       } | ||||||
|             color: $color-grey; |       /*.material-errors { | ||||||
|         } |  | ||||||
|         .material-input-bar { |  | ||||||
|             &:before, |  | ||||||
|             &:after { |  | ||||||
|                 background: $color-blue; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         // Active state: |  | ||||||
|         &.material--active { |  | ||||||
|             .material-label { |  | ||||||
|                 color: $color-blue; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         // Errors: |  | ||||||
|         &.material--has-errors { |  | ||||||
|             &.material--active .material-label { |  | ||||||
|                 color: $color-red; |                 color: $color-red; | ||||||
|             } |             }*/ | ||||||
|             .material-input-bar { |  | ||||||
|                 &:before, |  | ||||||
|                 &:after { |  | ||||||
|                     background: $color-red; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             .material-errors { |  | ||||||
|                 color: $color-red; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |   } | ||||||
| </style> | </style> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user