refactor(form-item): refactor event mechanism

This commit is contained in:
07akioni 2019-11-02 23:09:36 +08:00
parent fdad44af2b
commit 2621d152f9
7 changed files with 113 additions and 43 deletions

View File

@ -6,13 +6,13 @@
:value="formValue"
ref="form"
>
<n-form-item label="Name" path="name">
<n-input v-model="formValue.name" placeholder="Input Name" />
<n-form-item label="Name" path="user.name" required>
<n-input v-model="formValue.user.name" placeholder="Input Name" />
</n-form-item>
<n-form-item label="Age" path="age">
<n-input placeholder="Input Age" v-model="formValue.age"/>
<n-form-item label="Age" path="user.age" required>
<n-input placeholder="Input Age" v-model="formValue.user.age"/>
</n-form-item>
<n-form-item label="Phone" path="phone">
<n-form-item label="Phone" path="phone" required>
<n-input placeholder="Phone Number" v-model="formValue.phone"/>
</n-form-item>
<n-form-item v-model="formValue.phone">
@ -29,8 +29,10 @@ export default {
data () {
return {
formValue: {
user: {
name: '',
age: '',
age: ''
},
phone: ''
}
}

View File

@ -26,7 +26,12 @@
>
<slot />
<div :class="`n-form-item-explain`">
{{ explain }}
<transition name="n-fade-down">
<span
v-if="explain"
class="n-form-item-explain__content"
>{{ explain }}</span>
</transition>
</div>
</div>
</div>
@ -131,10 +136,17 @@ export default {
},
synthesizedRules () {
let rules = []
const validator = (rule, value) => {
if (value !== undefined && value !== null && value !== '') {
return true
}
return Error(`${this.label || this.path} is required!`)
}
if (this.required) {
rules.push({
trigger: 'blur',
required: true
trigger: ['blur', 'change', 'input'],
required: true,
validator
})
}
if (this.rule) {
@ -156,6 +168,11 @@ export default {
}
},
created () {
/**
* This is buggy!
* Because if it's child change, rules is not updated
* However I need to make it work first
*/
this.addValidationEventListeners()
},
methods: {
@ -165,6 +182,12 @@ export default {
handleContentChange () {
this.validate('change')
},
handleContentFocus () {
this.validate('focus')
},
handleContentInput () {
this.validate('input')
},
validate (trigger = null, callback = null) {
if (!this.path) {
return
@ -172,10 +195,17 @@ export default {
const rules = this.synthesizedRules
const path = this.path
const value = get(this.NForm.value, this.path, null)
const activeRules = !trigger ? rules : rules.filter(rule => rule.trigger === trigger)
const activeRules = !trigger ? rules : rules.filter(rule => {
if (Array.isArray(rule.trigger)) {
return rule.trigger.includes(trigger)
} else {
return rule.trigger === trigger
}
})
if (!activeRules.length) return
const asyncValidator = new AsyncValidator({ [path]: activeRules })
asyncValidator.validate({ [path]: value }, (errors, fields) => {
console.log('validate', errors, fields)
if (errors) {
this.explain = errors[0].message
this.validated = true
@ -192,8 +222,10 @@ export default {
addValidationEventListeners () {
const rules = this.synthesizedRules
if (rules.length >= 0) {
this.$on('form-item-blur', this.handleContentBlur)
this.$on('form-item-change', this.handleContentChange)
this.$on('blur', this.handleContentBlur)
this.$on('input', this.handleContentInput)
this.$on('focus', this.handleContentFocus)
this.$on('change', this.handleContentChange)
}
}
}

View File

@ -29,7 +29,7 @@ export default {
},
labelPosition: {
type: String,
default: 'top' // ['top', 'right', 'left', 'center']
default: 'top'
},
value: {
type: Object,

View File

@ -124,22 +124,17 @@
</template>
<script>
import Emitter from '../../../mixins/emitter'
import NCancelMark from '../../../base/CancelMark'
import withapp from '../../../mixins/withapp'
import themeable from '../../../mixins/themeable'
import asformitem from '../../../mixins/asformitem'
export default {
name: 'NInput',
components: {
NCancelMark
},
mixins: [ withapp, themeable, Emitter ],
inject: {
NFormItem: {
default: null
}
},
mixins: [ withapp, themeable, asformitem() ],
props: {
type: {
type: String,
@ -322,9 +317,6 @@ export default {
this.focus = false
this.triggerBlur(e)
}
if (this.NFormItem) {
this.dispatch('NFormItem', 'form-item-blur', e.target.value)
}
},
handleInputFocus (e) {
this.$emit('input-focus')
@ -347,9 +339,6 @@ export default {
this.$emit('keyup', e)
},
handleChange (e) {
if (this.NFormItem) {
this.dispatch('NFormItem', 'form-item-change', e.target.value)
}
this.$emit('change', e.target.value)
},
handleClick (e) {

View File

@ -0,0 +1,24 @@
export default function (events = {
change: 'change',
blur: 'blur',
focus: 'focus',
input: 'input'
}) {
return {
inject: {
NFormItem: {
default: null
}
},
created () {
Object.keys(events).forEach(event => {
const asEvent = events[event]
this.$on(event, function (value) {
if (this.NFormItem) {
this.NFormItem.$emit(asEvent, value)
}
})
})
}
}
}

View File

@ -6,13 +6,15 @@
font-size: 14px;
color: rgba(255, 255, 255, 1);
@include m(inline) {
width: auto;
width: 100%;
display: inline-flex;
align-items: flex-end;
align-content: space-around;
flex-wrap: nowrap;
.n-form-item:not(:last-child) {
margin-right: 10px;
@include b(form-item) {
width: auto;
&:last-child {
margin-right: 0;
}
}
}
.n-form-item__label--top {
@ -71,21 +73,25 @@
height: 22px;
box-sizing: border-box;
font-size: 13px;
flex-grow: 0;
overflow-wrap: break-word;
@include e(span) {
display: inline-block;
}
}
@include b(form-item-content) {
position: relative;
flex-grow: 1;
}
@include b(form-item-explain) {
min-height: 22px;
box-sizing: border-box;
margin-top: 4px;
min-height: 20px;
line-height: 1.5;
color: rgba(255, 146, 164, 1);
font-size: 14px;
font-size: 13px;
padding-left: 2px;
transform-origin: top left;
@include e(content) {
display: inline-block;
@include fade-down-transition($from-offset: -3px);
// @include fade-in-scale-up-transition();
}
}
.n-form-item__content--pass {
.n-form-item__validate {

View File

@ -220,20 +220,37 @@ $default-cubic-bezier: cubic-bezier(.4, 0, .2, 1);
}
}
@mixin fade-down-transition ($name: 'fade-down', $from-offset: -4px) {
&.#{$namespace}-#{$name}-enter, &.#{$namespace}-#{$name}-leave-to {
opacity: 0;
transform: translateY($from-offset);
}
&.#{$namespace}-#{$name}-enter-to, &.#{$namespace}-#{$name}-leave {
opacity: 1;
transform: translateY(0);
}
&.#{$namespace}-#{$name}-leave-active {
transition: opacity .3s $default-cubic-bezier, transform .3s $default-cubic-bezier;
}
&.#{$namespace}-#{$name}-enter-active {
transition: opacity .3s $default-cubic-bezier, transform .3s $default-cubic-bezier;
}
}
@mixin fade-up-transition($block) {
.#{$namespace}-#{$block}--transition-enter, .#{$namespace}-#{$block}--transition-leave-to {
&.#{$namespace}-#{$block}--transition-enter, .#{$namespace}-#{$block}--transition-leave-to {
opacity: 0;
transform: translateY(4px);
}
.#{$namespace}-#{$block}--transition-leave-active {
&.#{$namespace}-#{$block}--transition-leave-active {
transition: opacity .3s $slow-out-cubic-bezier, transform .3s $slow-out-cubic-bezier;
}
.#{$namespace}-#{$block}--transition-enter-active {
&.#{$namespace}-#{$block}--transition-enter-active {
transition: opacity .3s $fast-in-cubic-bezier, transform .3s $fast-in-cubic-bezier;
}
}
@mixin fade-in-scale-up-transition($block: 'fade-in-scale-up', $origin: inherit, $duration: .2s) {
@mixin fade-in-scale-up-transition($block: 'fade-in-scale-up', $origin: inherit, $duration: .2s, $start-scale: 0.9) {
&.#{$namespace}-#{$block}--transition-leave-active {
transform-origin: $origin;
transition: opacity $duration $slow-out-cubic-bezier, transform $duration $slow-out-cubic-bezier;
@ -244,7 +261,7 @@ $default-cubic-bezier: cubic-bezier(.4, 0, .2, 1);
}
&.#{$namespace}-#{$block}--transition-enter, &.#{$namespace}-#{$block}--transition-leave-to {
opacity: 0;
transform: scale(.9);
transform: scale($start-scale);
}
&.#{$namespace}-#{$block}--transition-leave, &.#{$namespace}-#{$block}--transition-enter-to {
opacity: 1;