feat: update vc-drawer vc-form

pull/398/head
tangjinzhou 2019-01-01 16:25:50 +08:00
parent d805107543
commit 754d897393
12 changed files with 160 additions and 88 deletions

View File

@ -1,9 +1,9 @@
import classNames from 'classnames' import warning from 'warning'
import VcDrawer from '../vc-drawer/src' import VcDrawer from '../vc-drawer/src'
import PropTypes from '../_util/vue-types' import PropTypes from '../_util/vue-types'
import BaseMixin from '../_util/BaseMixin' import BaseMixin from '../_util/BaseMixin'
import Icon from '../icon' import Icon from '../icon'
import { getComponentFromProp, getOptionProps } from '../_util/props-util' import { getComponentFromProp, getOptionProps, getClass } from '../_util/props-util'
const Drawer = { const Drawer = {
name: 'ADrawer', name: 'ADrawer',
@ -26,6 +26,10 @@ const Drawer = {
}, },
mixins: [BaseMixin], mixins: [BaseMixin],
data () { data () {
warning(
this.wrapClassName === undefined,
'wrapClassName is deprecated, please use className instead.',
)
this.destoryClose = false this.destoryClose = false
this.preVisible = this.$props.visible this.preVisible = this.$props.visible
return { return {
@ -195,16 +199,17 @@ const Drawer = {
open: visible, open: visible,
showMask: props.mask, showMask: props.mask,
placement, placement,
wrapClassName: classNames({
[wrapClassName]: !!wrapClassName,
[haveMask]: !!haveMask,
}),
}, },
on: { on: {
maskClick: this.onMaskClick, maskClick: this.onMaskClick,
...this.$listeners, ...this.$listeners,
}, },
style: this.getRcDrawerStyle(), style: this.getRcDrawerStyle(),
class: {
[wrapClassName]: !!wrapClassName,
...getClass(this),
[haveMask]: !!haveMask,
},
} }
return ( return (
<VcDrawer <VcDrawer

View File

@ -112,6 +112,8 @@ export const ValidationRule = {
// normalize?: (value: any, prevValue: any, allValues: any) => any; // normalize?: (value: any, prevValue: any, allValues: any) => any;
// /** Whether stop validate on first rule of error for this field. */ // /** Whether stop validate on first rule of error for this field. */
// validateFirst?: boolean; // validateFirst?: boolean;
// /** */
// preserve?: boolean;
// }; // };
const Form = { const Form = {

View File

@ -23,6 +23,7 @@ Add or remove form items dynamically.
`names[${k}]`, `names[${k}]`,
{ {
validateTrigger: ['change', 'blur'], validateTrigger: ['change', 'blur'],
preserve: true,
rules: [{ rules: [{
required: true, required: true,
whitespace: true, whitespace: true,

View File

@ -25,7 +25,7 @@ export default {
}, },
getLevelMove (e) { getLevelMove (e) {
const target = e.target const target = e.target
if (target.className === 'drawer1') { if (target.className.indexOf('drawer1') >= 0) {
return [200, 100] return [200, 100]
} }
return 100 return 100
@ -47,7 +47,7 @@ export default {
handler={false} handler={false}
open={this.open} open={this.open}
onMaskClick={this.onClick} onMaskClick={this.onClick}
wrapperClassName='drawer1' class='drawer1'
placement='right' placement='right'
> >
<div> <div>
@ -56,7 +56,7 @@ export default {
handler={false} handler={false}
open={this.openChild} open={this.openChild}
onMaskClick={this.onChildClick} onMaskClick={this.onChildClick}
wrapperClassName='drawer2' class='drawer2'
level='.drawer1' level='.drawer1'
placement='right' placement='right'
levelMove={100} levelMove={100}

View File

@ -35,7 +35,7 @@ export default {
return ( return (
<div > <div >
{this.childShow && ( {this.childShow && (
<Drawer placement={this.placement} width={this.width} hieght={this.height}> <Drawer placement={this.placement} width={this.width} height={this.height}>
<Menu <Menu
defaultSelectedKeys={['1']} defaultSelectedKeys={['1']}
defaultOpenKeys={['sub1']} defaultOpenKeys={['sub1']}

View File

@ -2,7 +2,7 @@ import classnames from 'classnames'
import Vue from 'vue' import Vue from 'vue'
import ref from 'vue-ref' import ref from 'vue-ref'
import BaseMixin from '../../_util/BaseMixin' import BaseMixin from '../../_util/BaseMixin'
import { initDefaultProps, getEvents } from '../../_util/props-util' import { initDefaultProps, getEvents, getClass } from '../../_util/props-util'
import { cloneElement } from '../../_util/vnode' import { cloneElement } from '../../_util/vnode'
import ContainerRender from '../../_util/ContainerRender' import ContainerRender from '../../_util/ContainerRender'
import getScrollBarSize from '../../_util/getScrollBarSize' import getScrollBarSize from '../../_util/getScrollBarSize'
@ -10,7 +10,7 @@ import drawerProps from './drawerProps'
import { import {
dataToArray, dataToArray,
transitionEnd, transitionEnd,
trnasitionStr, transitionStr,
addEventListener, addEventListener,
removeEventListener, removeEventListener,
transformArguments, transformArguments,
@ -40,7 +40,7 @@ const Drawer = {
showMask: true, showMask: true,
handler: true, handler: true,
maskStyle: {}, maskStyle: {},
wrapClassName: '', wrapperClassName: '',
}), }),
data () { data () {
this.levelDom = [] this.levelDom = []
@ -51,8 +51,9 @@ const Drawer = {
this.sFirstEnter = this.firstEnter this.sFirstEnter = this.firstEnter
this.timeout = null this.timeout = null
this.children = null this.children = null
this.drawerId = Number((Date.now() + Math.random()).toString() this.drawerId = Number(
.replace('.', Math.round(Math.random() * 9))).toString(16) (Date.now() + Math.random()).toString().replace('.', Math.round(Math.random() * 9)),
).toString(16)
const open = this.open !== undefined ? this.open : !!this.defaultOpen const open = this.open !== undefined ? this.open : !!this.defaultOpen
currentDrawer[this.drawerId] = open currentDrawer[this.drawerId] = open
this.orignalOpen = this.open this.orignalOpen = this.open
@ -170,7 +171,7 @@ const Drawer = {
onWrapperTransitionEnd (e) { onWrapperTransitionEnd (e) {
if (e.target === this.contentWrapper) { if (e.target === this.contentWrapper) {
this.dom.style.transition = '' this.dom.style.transition = ''
if (!this.sOpen && this.getCrrentDrawerSome()) { if (!this.sOpen && this.getCurrentDrawerSome()) {
document.body.style.overflowX = '' document.body.style.overflowX = ''
if (this.maskDom) { if (this.maskDom) {
this.maskDom.style.left = '' this.maskDom.style.left = ''
@ -185,7 +186,7 @@ const Drawer = {
this.container = this.defaultGetContainer() this.container = this.defaultGetContainer()
} }
}, },
getCrrentDrawerSome () { getCurrentDrawerSome () {
return !Object.keys(currentDrawer).some(key => currentDrawer[key]) return !Object.keys(currentDrawer).some(key => currentDrawer[key])
}, },
getSelfContainer () { getSelfContainer () {
@ -215,8 +216,11 @@ const Drawer = {
if (level === 'all') { if (level === 'all') {
const children = Array.prototype.slice.call(this.parent.children) const children = Array.prototype.slice.call(this.parent.children)
children.forEach(child => { children.forEach(child => {
if (child.nodeName !== 'SCRIPT' && child.nodeName !== 'STYLE' && if (child.nodeName !== 'SCRIPT' &&
child.nodeName !== 'LINK' && child !== this.container) { child.nodeName !== 'STYLE' &&
child.nodeName !== 'LINK' &&
child !== this.container
) {
this.levelDom.push(child) this.levelDom.push(child)
} }
}) })
@ -251,9 +255,12 @@ const Drawer = {
if (getContainer === 'body') { if (getContainer === 'body') {
const eventArray = ['touchstart'] const eventArray = ['touchstart']
const domArray = [document.body, this.maskDom, this.handlerdom, this.contentDom] const domArray = [document.body, this.maskDom, this.handlerdom, this.contentDom]
const right = document.body.scrollHeight > (window.innerHeight || document.documentElement.clientHeight) && const right =
document.body.scrollHeight >
(window.innerHeight || document.documentElement.clientHeight) &&
window.innerWidth > document.body.offsetWidth window.innerWidth > document.body.offsetWidth
? getScrollBarSize(1) : 0 ? getScrollBarSize(1)
: 0
let widthTransition = `width ${duration} ${ease}` let widthTransition = `width ${duration} ${ease}`
const trannsformTransition = `transform ${duration} ${ease}` const trannsformTransition = `transform ${duration} ${ease}`
if (open && document.body.style.overflow !== 'hidden') { if (open && document.body.style.overflow !== 'hidden') {
@ -295,12 +302,12 @@ const Drawer = {
this.passive this.passive
) )
}) })
} else if (this.getCrrentDrawerSome()) { } else if (this.getCurrentDrawerSome()) {
document.body.style.overflow = '' document.body.style.overflow = ''
if ((this.isOpenChange || openTransition) && right) { if ((this.isOpenChange || openTransition) && right) {
document.body.style.position = '' document.body.style.position = ''
document.body.style.width = '' document.body.style.width = ''
if (trnasitionStr) { if (transitionStr) {
document.body.style.overflowX = 'hidden' document.body.style.overflowX = 'hidden'
} }
this.dom.style.transition = 'none' this.dom.style.transition = 'none'
@ -367,21 +374,19 @@ const Drawer = {
maskStyle, maskStyle,
width, width,
height, height,
wrapClassName,
} = this.$props } = this.$props
const children = this.$slots.default const children = this.$slots.default
const wrapperClassname = classnames(prefixCls, { const wrapperClassname = classnames(prefixCls, {
[`${prefixCls}-${placement}`]: true, [`${prefixCls}-${placement}`]: true,
[`${prefixCls}-open`]: open, [`${prefixCls}-open`]: open,
[wrapClassName]: !!wrapClassName, ...getClass(this),
}) })
const isOpenChange = this.isOpenChange const isOpenChange = this.isOpenChange
const isHorizontal = placement === 'left' || placement === 'right' const isHorizontal = placement === 'left' || placement === 'right'
const placementName = `translate${isHorizontal ? 'X' : 'Y'}` const placementName = `translate${isHorizontal ? 'X' : 'Y'}`
// 百分比与像素动画不同步,第一次打用后全用像素动画。 // 百分比与像素动画不同步,第一次打用后全用像素动画。
// const defaultValue = !this.contentDom || !level ? '100%' : `${value}px`; // const defaultValue = !this.contentDom || !level ? '100%' : `${value}px`;
const placementPos = const placementPos = placement === 'left' || placement === 'top' ? '-100%' : '100%'
placement === 'left' || placement === 'top' ? '-100%' : '100%'
const transform = open ? '' : `${placementName}(${placementPos})` const transform = open ? '' : `${placementName}(${placementPos})`
if (isOpenChange === undefined || isOpenChange) { if (isOpenChange === undefined || isOpenChange) {
const contentValue = this.contentDom ? this.contentDom.getBoundingClientRect()[ const contentValue = this.contentDom ? this.contentDom.getBoundingClientRect()[
@ -390,7 +395,7 @@ const Drawer = {
const value = (isHorizontal ? width : height) || contentValue const value = (isHorizontal ? width : height) || contentValue
this.setLevelDomTransform(open, false, placementName, value) this.setLevelDomTransform(open, false, placementName, value)
} }
let handlerCildren let handlerChildren
if (handler !== false) { if (handler !== false) {
const handlerDefalut = ( const handlerDefalut = (
<div class='drawer-handle'> <div class='drawer-handle'>
@ -400,7 +405,7 @@ const Drawer = {
const { handler: handlerSlot } = this.$slots const { handler: handlerSlot } = this.$slots
const handlerSlotVnode = handlerSlot || handlerDefalut const handlerSlotVnode = handlerSlot || handlerDefalut
const { click: handleIconClick } = getEvents(handlerSlotVnode) const { click: handleIconClick } = getEvents(handlerSlotVnode)
handlerCildren = cloneElement(handlerSlotVnode, { handlerChildren = cloneElement(handlerSlotVnode, {
on: { on: {
click: (e) => { click: (e) => {
handleIconClick && handleIconClick() handleIconClick && handleIconClick()
@ -475,7 +480,7 @@ const Drawer = {
> >
{children} {children}
</div> </div>
{handlerCildren} {handlerChildren}
</div> </div>
</div> </div>
) )
@ -484,7 +489,7 @@ const Drawer = {
return this.open !== undefined ? this.open : this.sOpen return this.open !== undefined ? this.open : this.sOpen
}, },
getTouchParentScroll (root, currentTarget, differX, differY) { getTouchParentScroll (root, currentTarget, differX, differY) {
if (!currentTarget) { if (!currentTarget || currentTarget === document) {
return false return false
} }
// root 为 drawer-content 设定了 overflow, 判断为 root 的 parent 时结束滚动; // root 为 drawer-content 设定了 overflow, 判断为 root 的 parent 时结束滚动;
@ -506,20 +511,27 @@ const Drawer = {
*/ */
const t = currentTarget.scrollTop const t = currentTarget.scrollTop
const l = currentTarget.scrollLeft const l = currentTarget.scrollLeft
if (currentTarget.scrollTo) {
currentTarget.scrollTo(currentTarget.scrollLeft + 1, currentTarget.scrollTop + 1) currentTarget.scrollTo(currentTarget.scrollLeft + 1, currentTarget.scrollTop + 1)
}
const currentT = currentTarget.scrollTop const currentT = currentTarget.scrollTop
const currentL = currentTarget.scrollLeft const currentL = currentTarget.scrollLeft
if (currentTarget.scrollTo) {
currentTarget.scrollTo(currentTarget.scrollLeft - 1, currentTarget.scrollTop - 1) currentTarget.scrollTo(currentTarget.scrollLeft - 1, currentTarget.scrollTop - 1)
}
if ( if (
isY && (!scrollY || !(currentT - t) || (isY &&
(scrollY && (currentTarget.scrollTop >= scrollY && differY < 0 || (!scrollY ||
currentTarget.scrollTop <= 0 && differY > 0)) !(currentT - t) ||
) || (scrollY &&
isX && (!scrollX || !(currentL - l) || ((currentTarget.scrollTop >= scrollY && differY < 0) ||
(scrollX && (currentTarget.scrollLeft >= scrollX && differX < 0 || (currentTarget.scrollTop <= 0 && differY > 0))))) ||
currentTarget.scrollLeft <= 0 && differX > 0)) (isX &&
) (!scrollX ||
!(currentL - l) ||
(scrollX &&
((currentTarget.scrollLeft >= scrollX && differX < 0) ||
(currentTarget.scrollLeft <= 0 && differX > 0)))))
) { ) {
return this.getTouchParentScroll(root, currentTarget.parentNode, differX, differY) return this.getTouchParentScroll(root, currentTarget.parentNode, differX, differY)
} }
@ -544,8 +556,8 @@ const Drawer = {
if ( if (
currentTarget === this.maskDom || currentTarget === this.maskDom ||
currentTarget === this.handlerdom || currentTarget === this.handlerdom ||
currentTarget === this.contentDom && (currentTarget === this.contentDom &&
this.getTouchParentScroll(currentTarget, e.target, differX, differY) this.getTouchParentScroll(currentTarget, e.target, differX, differY))
) { ) {
e.preventDefault() e.preventDefault()
} }
@ -588,7 +600,7 @@ const Drawer = {
</div> </div>
) )
} }
if (!this.container || !open && !this.sFirstEnter) { if (!this.container || (!open && !this.sFirstEnter)) {
return null return null
} }
return ( return (

View File

@ -1,7 +1,7 @@
import PropTypes from '../../_util/vue-types' import PropTypes from '../../_util/vue-types'
export default { export default {
wrapClassName: PropTypes.string, wrapperClassName: PropTypes.string,
width: PropTypes.any, width: PropTypes.any,
height: PropTypes.any, height: PropTypes.any,
defaultOpen: PropTypes.bool, defaultOpen: PropTypes.bool,

View File

@ -1,4 +1,4 @@
// base in 1.7.6 // base in 1.7.7
// export this package's api // export this package's api
import Drawer from './Drawer' import Drawer from './Drawer'

View File

@ -4,20 +4,20 @@ export function dataToArray (vars) {
} }
return [vars] return [vars]
} }
const trnasitionEndObject = { const transitionEndObject = {
transition: 'transitionend', transition: 'transitionend',
WebkitTransition: 'webkitTransitionEnd', WebkitTransition: 'webkitTransitionEnd',
MozTransition: 'transitionend', MozTransition: 'transitionend',
OTransition: 'oTransitionEnd otransitionend', OTransition: 'oTransitionEnd otransitionend',
} }
export const trnasitionStr = Object.keys(trnasitionEndObject).filter(key => { export const transitionStr = Object.keys(transitionEndObject).filter(key => {
if (typeof document === 'undefined') { if (typeof document === 'undefined') {
return false return false
} }
const html = document.getElementsByTagName('html')[0] const html = document.getElementsByTagName('html')[0]
return key in (html ? html.style : {}) return key in (html ? html.style : {})
})[0] })[0]
export const transitionEnd = trnasitionEndObject[trnasitionStr] export const transitionEnd = transitionEndObject[transitionStr]
export function addEventListener (target, eventType, callback, options) { export function addEventListener (target, eventType, callback, options) {
if (target.addEventListener) { if (target.addEventListener) {
@ -51,6 +51,6 @@ export function transformArguments (arg, cb) {
return [result] return [result]
} }
export const isNumeric = (value) => { export const isNumeric = value => {
return !isNaN(parseFloat(value)) && isFinite(value);// eslint-disable-line return !isNaN(parseFloat(value)) && isFinite(value);// eslint-disable-line
} }

View File

@ -0,0 +1,29 @@
import { createForm } from '../index'
const Form = {
methods: {
handleSubmit (e) {
e.preventDefault()
const { validateFields } = this.form
validateFields()
.then(console.log)
.catch(console.error)
},
},
render () {
const { getFieldDecorator } = this.form
return (
<form onSubmit={this.handleSubmit}>
{getFieldDecorator('name', {
rules: [{
required: true,
}],
})(<input/>)}
<button type='submit'>submit</button>
</form>
)
},
}
export default createForm()(Form)

View File

@ -34,6 +34,7 @@ function createBaseForm (option = {}, mixins = []) {
fieldMetaProp, fieldMetaProp,
fieldDataProp, fieldDataProp,
formPropName = 'form', formPropName = 'form',
name: formName,
props = {}, props = {},
templateContext, templateContext,
} = option } = option
@ -267,7 +268,7 @@ function createBaseForm (option = {}, mixins = []) {
const inputListeners = {} const inputListeners = {}
const inputAttrs = {} const inputAttrs = {}
if (fieldNameProp) { if (fieldNameProp) {
inputProps[fieldNameProp] = name inputProps[fieldNameProp] = formName ? `${formName}_${name}` : name
} }
const validateRules = normalizeValidateRules(validate, rules, validateTrigger) const validateRules = normalizeValidateRules(validate, rules, validateTrigger)
@ -375,12 +376,15 @@ function createBaseForm (option = {}, mixins = []) {
saveRef (name, _, component) { saveRef (name, _, component) {
if (!component) { if (!component) {
const fieldMeta = this.fieldsStore.getFieldMeta(name)
if (!fieldMeta.preserve) {
// after destroy, delete data // after destroy, delete data
this.clearedFieldMetaCache[name] = { this.clearedFieldMetaCache[name] = {
field: this.fieldsStore.getField(name), field: this.fieldsStore.getField(name),
meta: this.fieldsStore.getFieldMeta(name), meta: fieldMeta,
} }
this.clearField(name) this.clearField(name)
}
delete this.domFields[name] delete this.domFields[name]
return return
} }
@ -401,9 +405,10 @@ function createBaseForm (option = {}, mixins = []) {
cleanUpUselessFields () { cleanUpUselessFields () {
const fieldList = this.fieldsStore.getAllFieldsName() const fieldList = this.fieldsStore.getAllFieldsName()
const removedList = fieldList.filter(field => ( const removedList = fieldList.filter(field => {
!this.renderFields[field] && !this.domFields[field] const fieldMeta = this.fieldsStore.getFieldMeta(field)
)) return (!this.renderFields[field] && !this.domFields[field] && !fieldMeta.preserve)
})
if (removedList.length) { if (removedList.length) {
removedList.forEach(this.clearField) removedList.forEach(this.clearField)
} }
@ -536,7 +541,21 @@ function createBaseForm (option = {}, mixins = []) {
}, },
validateFields (ns, opt, cb) { validateFields (ns, opt, cb) {
const { names, callback, options } = getParams(ns, opt, cb) const pending = new Promise((resolve, reject) => {
const { names, options } = getParams(ns, opt, cb)
let { callback } = getParams(ns, opt, cb)
if (!callback || typeof callback === 'function') {
const oldCb = callback
callback = (errors, values) => {
if (oldCb) {
oldCb(errors, values)
} else if (errors) {
reject({ errors, values })
} else {
resolve(values)
}
}
}
const fieldNames = names const fieldNames = names
? this.fieldsStore.getValidFieldsFullName(names) ? this.fieldsStore.getValidFieldsFullName(names)
: this.fieldsStore.getValidFieldsName() : this.fieldsStore.getValidFieldsName()
@ -565,6 +584,9 @@ function createBaseForm (option = {}, mixins = []) {
fieldNames, fieldNames,
options, options,
}, callback) }, callback)
})
pending.catch((e) => e)
return pending
}, },
isSubmitting () { isSubmitting () {

View File

@ -159,7 +159,8 @@ class FieldsStore {
} }
getNotCollectedFields () { getNotCollectedFields () {
return this.getValidFieldsName() const fieldsName = this.getValidFieldsName()
return fieldsName
.filter(name => !this.fields[name]) .filter(name => !this.fields[name])
.map(name => ({ .map(name => ({
name, name,