Commit 14ff09a4 authored by lei.jiang's avatar lei.jiang Committed by 花裤衩

修改MDinput组件

1.使之能兼容elementui的表单验证功能
2.增加icon属性,能够使用elementui的图标
3.优化显示效果
parent a14547aa
<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
} }
}
},
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: { methods: {
type: String, handleModelInput(event) {
default: null const value = event.target.value
}, this.$emit('input', value)
max: { if (this.$parent.$options.componentName === 'ElFormItem') {
type: String, if (this.validateEvent) {
default: null this.$parent.$emit('el.form.change', [value])
}, }
minlength: { }
type: Number, this.$emit('change', value)
default: null // this.handleValidation()
}, },
maxlength: { handleMdFocus(event) {
type: Number, this.focus = true
default: null this.$emit('focus', event)
}, if (this.placeholder && this.placeholder !== '') {
required: { this.fillPlaceHolder = this.placeholder
type: Boolean, }
default: true },
}, handleMdBlur(event) {
autocomplete: { this.focus = false
type: String, this.$emit('blur', event)
default: 'off' this.fillPlaceHolder = null
if (this.$parent.$options.componentName === 'ElFormItem') {
if (this.validateEvent) {
this.$parent.$emit('el.form.blur', [this.currentValue])
}
}
}
}, },
errorMessages: { props: {
type: [Array, String], icon: String,
default: null 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
}
} }
} }
}
</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; .material-input-bar {
padding: $spacer $spacer $spacer $spacer / 2; position: relative;
display: block; display: block;
width: 100%; width: 100%;
border: none; &:before {
border-radius: 0; @extend %base-bar-pseudo;
&:focus { left: 50%;
outline: none; }
border: none; &:after {
border-bottom: 1px solid transparent; // fixes the height issue @extend %base-bar-pseudo;
} right: 50%;
} }
.material-label { }
font-size: $font-size-base; // Disabled state:
font-weight: $font-weight-normal; &.material--disabled {
position: absolute; .material-input {
pointer-events: none; border-bottom-style: dashed;
left: 0; }
top: $spacer; }
transition: $transition; // Raised state:
} &.material--raised {
.material-input-bar { .material-label {
position: relative; @include slided-top();
display: block; }
width: 100%; }
&:before { // Active state:
@extend %base-bar-pseudo; &.material--active {
left: 50%; .material-input-bar {
} &:before,
&:after { &:after {
@extend %base-bar-pseudo; width: 50%;
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;
}
} }
}
} }
}
// 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;
.material-label { }
color: $color-grey; }
} // Active state:
.material-input-bar { &.material--active {
&:before, .material-label {
&:after { color: $color-blue;
background: $color-blue; }
} }
} // Errors:
// Active state: &.material--has-errors {
&.material--active { &.material--active .material-label {
.material-label { color: $color-red;
color: $color-blue; }
} .material-input-bar {
&:before,
&:after {
background: transparent;
} }
// Errors: }
&.material--has-errors { /*.material-errors {
&.material--active .material-label {
color: $color-red;
}
.material-input-bar {
&:before,
&:after {
background: $color-red;
}
}
.material-errors {
color: $color-red; color: $color-red;
} }*/
}
} }
}
</style> </style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment