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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -4,20 +4,20 @@ export function dataToArray (vars) {
}
return [vars]
}
const trnasitionEndObject = {
const transitionEndObject = {
transition: 'transitionend',
WebkitTransition: 'webkitTransitionEnd',
MozTransition: 'transitionend',
OTransition: 'oTransitionEnd otransitionend',
}
export const trnasitionStr = Object.keys(trnasitionEndObject).filter(key => {
export const transitionStr = Object.keys(transitionEndObject).filter(key => {
if (typeof document === 'undefined') {
return false
}
const html = document.getElementsByTagName('html')[0]
return key in (html ? html.style : {})
})[0]
export const transitionEnd = trnasitionEndObject[trnasitionStr]
export const transitionEnd = transitionEndObject[transitionStr]
export function addEventListener (target, eventType, callback, options) {
if (target.addEventListener) {
@ -51,6 +51,6 @@ export function transformArguments (arg, cb) {
return [result]
}
export const isNumeric = (value) => {
export const isNumeric = value => {
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,
fieldDataProp,
formPropName = 'form',
name: formName,
props = {},
templateContext,
} = option
@ -267,7 +268,7 @@ function createBaseForm (option = {}, mixins = []) {
const inputListeners = {}
const inputAttrs = {}
if (fieldNameProp) {
inputProps[fieldNameProp] = name
inputProps[fieldNameProp] = formName ? `${formName}_${name}` : name
}
const validateRules = normalizeValidateRules(validate, rules, validateTrigger)
@ -375,12 +376,15 @@ function createBaseForm (option = {}, mixins = []) {
saveRef (name, _, component) {
if (!component) {
const fieldMeta = this.fieldsStore.getFieldMeta(name)
if (!fieldMeta.preserve) {
// after destroy, delete data
this.clearedFieldMetaCache[name] = {
field: this.fieldsStore.getField(name),
meta: this.fieldsStore.getFieldMeta(name),
this.clearedFieldMetaCache[name] = {
field: this.fieldsStore.getField(name),
meta: fieldMeta,
}
this.clearField(name)
}
this.clearField(name)
delete this.domFields[name]
return
}
@ -401,9 +405,10 @@ function createBaseForm (option = {}, mixins = []) {
cleanUpUselessFields () {
const fieldList = this.fieldsStore.getAllFieldsName()
const removedList = fieldList.filter(field => (
!this.renderFields[field] && !this.domFields[field]
))
const removedList = fieldList.filter(field => {
const fieldMeta = this.fieldsStore.getFieldMeta(field)
return (!this.renderFields[field] && !this.domFields[field] && !fieldMeta.preserve)
})
if (removedList.length) {
removedList.forEach(this.clearField)
}
@ -536,35 +541,52 @@ function createBaseForm (option = {}, mixins = []) {
},
validateFields (ns, opt, cb) {
const { names, callback, options } = getParams(ns, opt, cb)
const fieldNames = names
? this.fieldsStore.getValidFieldsFullName(names)
: this.fieldsStore.getValidFieldsName()
const fields = fieldNames
.filter(name => {
const fieldMeta = this.fieldsStore.getFieldMeta(name)
return hasRules(fieldMeta.validate)
}).map((name) => {
const field = this.fieldsStore.getField(name)
field.value = this.fieldsStore.getFieldValue(name)
return field
})
if (!fields.length) {
if (callback) {
callback(null, this.fieldsStore.getFieldsValue(fieldNames))
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)
}
}
}
return
}
if (!('firstFields' in options)) {
options.firstFields = fieldNames.filter((name) => {
const fieldMeta = this.fieldsStore.getFieldMeta(name)
return !!fieldMeta.validateFirst
})
}
this.validateFieldsInternal(fields, {
fieldNames,
options,
}, callback)
const fieldNames = names
? this.fieldsStore.getValidFieldsFullName(names)
: this.fieldsStore.getValidFieldsName()
const fields = fieldNames
.filter(name => {
const fieldMeta = this.fieldsStore.getFieldMeta(name)
return hasRules(fieldMeta.validate)
}).map((name) => {
const field = this.fieldsStore.getField(name)
field.value = this.fieldsStore.getFieldValue(name)
return field
})
if (!fields.length) {
if (callback) {
callback(null, this.fieldsStore.getFieldsValue(fieldNames))
}
return
}
if (!('firstFields' in options)) {
options.firstFields = fieldNames.filter((name) => {
const fieldMeta = this.fieldsStore.getFieldMeta(name)
return !!fieldMeta.validateFirst
})
}
this.validateFieldsInternal(fields, {
fieldNames,
options,
}, callback)
})
pending.catch((e) => e)
return pending
},
isSubmitting () {

View File

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