feat: update drawer (#2324)

pull/2351/head
zdw 2020-06-02 22:09:34 +08:00 committed by GitHub
parent 3c292a51e1
commit 3642b09db8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 259 additions and 161 deletions

View File

@ -0,0 +1,30 @@
import { nextTick } from 'vue';
const antvRef = {
beforeMount: function bind(el, binding, vnode) {
nextTick(function() {
binding.value(el, vnode.key);
});
binding.value(el, vnode.key);
},
updated: function update(el, binding, vnode, oldVnode) {
if (oldVnode && oldVnode.directives) {
let oldBinding = oldVnode.directives.find(function(directive) {
return directive === antvRef;
});
if (oldBinding && oldBinding.value !== binding.value) {
oldBinding && oldBinding.value(null, oldVnode.key);
binding.value(el, vnode.key);
return;
}
}
// Should not have this situation
if (vnode.el !== oldVnode.el) {
binding.value(el, vnode.key);
}
},
unmounted: function unbind(el, binding, vnode) {
binding.value(null, vnode.key);
},
};
export default antvRef;

View File

@ -203,12 +203,20 @@ const getKey = ele => {
export function getEvents(child) {
let events = {};
if (child.componentOptions && child.componentOptions.listeners) {
events = child.componentOptions.listeners;
} else if (child.data && child.data.on) {
events = child.data.on;
for (let key in child) {
if (/^on/.test(key)) {
key = key.toLowerCase();
events[key] = child[key];
}
}
return { ...events };
return events;
// let events = {};
// if (child.componentOptions && child.componentOptions.listeners) {
// events = child.componentOptions.listeners;
// } else if (child.data && child.data.on) {
// events = child.data.on;
// }
// return { ...events };
}
// 获取 xxx.native 或者 原生标签 事件

View File

@ -1,3 +1,4 @@
import { inject, provide, nextTick } from 'vue';
import classnames from 'classnames';
import omit from 'omit.js';
import VcDrawer from '../vc-drawer/src';
@ -42,17 +43,28 @@ const Drawer = {
_push: false,
};
},
inject: {
parentDrawer: {
default: () => null,
},
configProvider: { default: () => ConfigConsumerProps },
},
provide() {
setup() {
const configProvider = inject('configProvider', ConfigConsumerProps);
return {
parentDrawer: this,
configProvider,
};
},
// inject: {
// parentDrawer: {
// default: () => null,
// },
// configProvider: { default: () => ConfigConsumerProps },
// },
// provide() {
// return {
// parentDrawer: this,
// };
// },
beforeCreate() {
const parentDrawer = inject('parentDrawer', null);
provide('parentDrawer', this);
this.parentDrawer = parentDrawer;
},
mounted() {
// fix: delete drawer in child and re-render, no push started.
// <Drawer>{show && <Drawer />}</Drawer>
@ -62,7 +74,7 @@ const Drawer = {
}
},
updated() {
this.$nextTick(() => {
nextTick(() => {
if (this.preVisible !== this.visible && this.parentDrawer) {
if (this.visible) {
this.parentDrawer.push();
@ -133,7 +145,9 @@ const Drawer = {
},
renderHeader(prefixCls) {
const { closable, headerStyle } = this.$props;
const title = getComponentFromProp(this, 'title');
// TODO
// const title = getComponentFromProp(this, 'title');
const title = null;
if (!title && !closable) {
return null;
}
@ -181,7 +195,7 @@ const Drawer = {
>
{this.renderHeader(prefixCls)}
<div key="body" class={`${prefixCls}-body`} style={bodyStyle}>
{this.$slots.default}
{this.$slots.default && this.$slots.default()}
</div>
</div>
);
@ -206,53 +220,59 @@ const Drawer = {
} else {
offsetStyle.height = typeof height === 'number' ? `${height}px` : height;
}
const handler = getComponentFromProp(this, 'handle') || false;
// TODO
// const handler = getComponentFromProp(this, 'handle') || false;
const handler = false;
const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('drawer', customizePrefixCls);
const vcDrawerProps = {
props: {
...omit(rest, [
'closable',
'destroyOnClose',
'drawerStyle',
'headerStyle',
'bodyStyle',
'title',
'push',
'visible',
'getPopupContainer',
'rootPrefixCls',
'getPrefixCls',
'renderEmpty',
'csp',
'pageHeader',
'autoInsertSpaceInButton',
]),
handler,
...offsetStyle,
prefixCls,
open: visible,
showMask: mask,
placement,
className: classnames({
[wrapClassName]: !!wrapClassName,
[haveMask]: !!haveMask,
}),
wrapStyle: this.getRcDrawerStyle(),
},
on: {
...getListeners(this),
},
...omit(rest, [
'closable',
'destroyOnClose',
'drawerStyle',
'headerStyle',
'bodyStyle',
'title',
'push',
'visible',
'getPopupContainer',
'rootPrefixCls',
'getPrefixCls',
'renderEmpty',
'csp',
'pageHeader',
'autoInsertSpaceInButton',
]),
handler,
...offsetStyle,
prefixCls,
open: visible,
showMask: mask,
placement,
className: classnames({
[wrapClassName]: !!wrapClassName,
[haveMask]: !!haveMask,
}),
wrapStyle: this.getRcDrawerStyle(),
};
return <VcDrawer {...vcDrawerProps}>{this.renderBody(prefixCls)}</VcDrawer>;
return (
<VcDrawer
{...vcDrawerProps}
on={{
...getListeners(this), //TODO
}}
>
{this.renderBody(prefixCls)}
</VcDrawer>
);
},
};
/* istanbul ignore next */
Drawer.install = function(Vue) {
Vue.use(Base);
Vue.component(Drawer.name, Drawer);
Drawer.install = function(app) {
app.use(Base);
app.component(Drawer.name, Drawer);
};
export default Drawer;

View File

@ -1,9 +1,9 @@
import classnames from 'classnames';
import Vue from 'vue';
import ref from 'vue-ref';
import { cloneVNode, withDirectives, Teleport, nextTick } from 'vue';
import antRef from '../../_util/ant-ref';
import BaseMixin from '../../_util/BaseMixin';
import { initDefaultProps, getEvents, getListeners } from '../../_util/props-util';
import { cloneElement } from '../../_util/vnode';
import { initDefaultProps, getEvents, getListeners, getSlot } from '../../_util/props-util';
// import { cloneElement } from '../../_util/vnode';
import getScrollBarSize from '../../_util/getScrollBarSize';
import { IDrawerProps } from './IDrawerPropTypes';
import KeyCode from '../../_util/KeyCode';
@ -16,7 +16,7 @@ import {
transformArguments,
isNumeric,
} from './utils';
import Portal from '../../_util/Portal';
// import Portal from '../../_util/Portal';
function noop() {}
@ -27,9 +27,10 @@ const windowIsUndefined = !(
window.document.createElement
);
Vue.use(ref, { name: 'ant-ref' });
// Vue.use(ref, { name: 'ant-ref' });
const Drawer = {
mixins: [BaseMixin],
directives: { 'ant-ref': antRef },
props: initDefaultProps(IDrawerProps, {
prefixCls: 'drawer',
placement: 'left',
@ -65,7 +66,7 @@ const Drawer = {
};
},
mounted() {
this.$nextTick(() => {
nextTick(() => {
if (!windowIsUndefined) {
let passiveSupported = false;
window.addEventListener(
@ -119,7 +120,7 @@ const Drawer = {
},
},
updated() {
this.$nextTick(() => {
nextTick(() => {
// dom 没渲染时,重走一遍。
if (!this.sFirstEnter && this.container) {
this.$forceUpdate();
@ -362,7 +363,9 @@ const Drawer = {
}
}
}
const { change } = getListeners(this);
// TODO
// const { change } = getListeners(this);
const change = false;
if (change && this.isOpenChange && this.sFirstEnter) {
change(open);
this.isOpenChange = false;
@ -382,7 +385,7 @@ const Drawer = {
keyboard,
maskClosable,
} = this.$props;
const children = this.$slots.default;
const children = getSlot(this);
const wrapperClassname = classnames(prefixCls, {
[`${prefixCls}-${placement}`]: true,
[`${prefixCls}-open`]: open,
@ -411,73 +414,80 @@ const Drawer = {
</div>
);
const { handler: handlerSlot } = this;
const handlerSlotVnode = (handlerSlot && handlerSlot[0]) || handlerDefalut;
const { click: handleIconClick } = getEvents(handlerSlotVnode);
handlerChildren = cloneElement(handlerSlotVnode, {
on: {
click: e => {
const handlerSlotVnode = handlerSlot || handlerDefalut;
const { onclick: handleIconClick } = getEvents(handlerSlotVnode);
handlerChildren = withDirectives(
cloneVNode(handlerSlotVnode, {
onClick: e => {
handleIconClick && handleIconClick();
this.onIconTouchEnd(e);
},
},
directives: [
{
name: 'ant-ref',
value: c => {
}),
[
[
antRef, //directive
c => {
this.handlerdom = c;
},
},
}, // value
],
],
});
);
}
const domContProps = {
class: wrapperClassname,
directives: [
{
name: 'ant-ref',
value: c => {
this.dom = c;
},
},
],
on: {
transitionend: this.onWrapperTransitionEnd,
keydown: open && keyboard ? this.onKeyDown : noop,
},
// directives: [
// {
// name: 'ant-ref',
// value: c => {
// this.dom = c;
// },
// },
// ],
onTransitionend: this.onWrapperTransitionEnd,
onKeydown: open && keyboard ? this.onKeyDown : noop,
style: wrapStyle,
};
const directivesMaskDom = [
{
name: 'ant-ref',
value: c => {
this.maskDom = c;
},
},
];
const directivesContentWrapper = [
{
name: 'ant-ref',
value: c => {
this.contentWrapper = c;
},
},
];
const directivesContentDom = [
{
name: 'ant-ref',
value: c => {
this.contentDom = c;
},
},
];
// const directivesMaskDom = [
// {
// name: 'ant-ref',
// value: c => {
// this.maskDom = c;
// },
// },
// ];
// const directivesContentWrapper = [
// {
// name: 'ant-ref',
// value: c => {
// this.contentWrapper = c;
// },
// },
// ];
// const directivesContentDom = [
// {
// name: 'ant-ref',
// value: c => {
// this.contentDom = c;
// },
// },
// ];
return (
<div {...domContProps} tabIndex={-1}>
<div
v-ant-ref={c => {
this.dom = c;
}}
{...domContProps}
tabIndex={-1}
>
{showMask && (
<div
class={`${prefixCls}-mask`}
onClick={maskClosable ? this.onMaskTouchEnd : noop}
style={maskStyle}
{...{ directives: directivesMaskDom }}
v-ant-ref={c => {
this.maskDom = c;
}}
// {...{ directives: directivesMaskDom }}
/>
)}
<div
@ -488,11 +498,17 @@ const Drawer = {
width: isNumeric(width) ? `${width}px` : width,
height: isNumeric(height) ? `${height}px` : height,
}}
{...{ directives: directivesContentWrapper }}
v-ant-ref={c => {
this.contentWrapper = c;
}}
// {...{ directives: directivesContentWrapper }}
>
<div
class={`${prefixCls}-content`}
{...{ directives: directivesContentDom }}
v-ant-ref={c => {
this.contentDom = c;
}}
// {...{ directives: directivesContentDom }}
onTouchstart={open ? this.removeStartHandler : noop} // 跑用例用
onTouchmove={open ? this.removeMoveHandler : noop} // 跑用例用
>
@ -604,16 +620,21 @@ const Drawer = {
currentDrawer[this.drawerId] = open ? this.container : open;
const children = this.getChildToRender(this.sFirstEnter ? open : false);
if (!getContainer) {
const directives = [
{
name: 'ant-ref',
value: c => {
this.container = c;
},
},
];
// const directives = [
// {
// name: 'ant-ref',
// value: c => {
// this.container = c;
// },
// },
// ];
return (
<div class={wrapperClassName} {...{ directives }}>
<div
class={wrapperClassName}
v-ant-ref={c => {
this.container = c;
}}
>
{children}
</div>
);
@ -624,7 +645,7 @@ const Drawer = {
// 如果有 handler 为内置强制渲染;
const $forceRender = !!handler || forceRender;
if ($forceRender || open || this.dom) {
portal = <Portal getContainer={this.getSelfContainer} children={children}></Portal>;
portal = <Teleport to={this.getSelfContainer()}>{children}</Teleport>;
}
return portal;
},

View File

@ -1,47 +1,63 @@
<template>
<a-config-provider>
<a-button-group class="dddd" style="color: red" @click="onClick">
<a-button>Cancel</a-button>
<a-button type="primary">
OK
</a-button>
</a-button-group>
<a-button
:class="['test']"
class="aaa"
style="display: inline"
block
:type="type"
@click="onClick"
<div>
<a-button type="primary" @click="showDrawer">Open</a-button>
<a-drawer
title="Multi-level drawer"
width="520"
:closable="false"
:visible="visible"
@close="onClose"
>
Primary
</a-button>
<a-button block>
Default
</a-button>
<a-button type="dashed" block>
Dashed
</a-button>
<a-button type="danger" block>
Danger
</a-button>
<a-button type="link" block>
Link
</a-button>
</a-config-provider>
<a-button type="primary" @click="showChildrenDrawer">Two-level drawer</a-button>
<a-drawer
title="Two-level Drawer"
width="320"
:closable="false"
:visible="childrenDrawer"
@close="onChildrenDrawerClose"
>
<a-button type="primary" @click="showChildrenDrawer">This is two-level drawer</a-button>
</a-drawer>
<div
:style="{
position: 'absolute',
bottom: 0,
width: '100%',
borderTop: '1px solid #e8e8e8',
padding: '10px 16px',
textAlign: 'right',
left: 0,
background: '#fff',
borderRadius: '0 0 4px 4px',
boxSizing: 'border-box',
}"
>
<a-button style="marginRight: 8px" @click="onClose">Cancel</a-button>
<a-button type="primary" @click="onClose">Submit</a-button>
</div>
</a-drawer>
</div>
</template>
<script>
export default {
name: 'Demo',
data() {
return {
type: 'primary',
visible: false,
childrenDrawer: false,
};
},
methods: {
onClick() {
console.log(1);
showDrawer() {
this.visible = true;
},
onClose() {
this.visible = false;
},
showChildrenDrawer() {
this.childrenDrawer = true;
},
onChildrenDrawerClose() {
this.childrenDrawer = false;
},
},
};

View File

@ -2,10 +2,13 @@ import '@babel/polyfill';
import { createApp } from 'vue';
import App from './App.vue';
import Button from 'ant-design-vue/button';
import Drawer from 'ant-design-vue/drawer';
import ConfigProvider from 'ant-design-vue/config-provider';
import 'ant-design-vue/button/style/index.less';
import 'ant-design-vue/drawer/style/index.less';
createApp(App)
.use(Button)
.use(ConfigProvider)
.use(Drawer)
.mount('#app');