Skip to content

Commit 3e90fa6

Browse files
authored
refactor(alert): use composition api (#3654)
* refactor(alert): use composition api * feat: export alert props type
1 parent ab75379 commit 3e90fa6

File tree

1 file changed

+107
-100
lines changed

1 file changed

+107
-100
lines changed

components/alert/index.tsx

+107-100
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { inject, cloneVNode, defineComponent } from 'vue';
1+
import { inject, cloneVNode, defineComponent, ref, ExtractPropTypes } from 'vue';
22
import CloseOutlined from '@ant-design/icons-vue/CloseOutlined';
33
import CheckCircleOutlined from '@ant-design/icons-vue/CheckCircleOutlined';
44
import ExclamationCircleOutlined from '@ant-design/icons-vue/ExclamationCircleOutlined';
@@ -9,15 +9,18 @@ import ExclamationCircleFilled from '@ant-design/icons-vue/ExclamationCircleFill
99
import InfoCircleFilled from '@ant-design/icons-vue/InfoCircleFilled';
1010
import CloseCircleFilled from '@ant-design/icons-vue/CloseCircleFilled';
1111
import classNames from '../_util/classNames';
12-
import BaseMixin from '../_util/BaseMixin';
1312
import PropTypes from '../_util/vue-types';
1413
import { getTransitionProps, Transition } from '../_util/transition';
15-
import { getComponent, isValidElement, findDOMNode } from '../_util/props-util';
14+
import { isValidElement } from '../_util/props-util';
1615
import { defaultConfigProvider } from '../config-provider';
1716
import { tuple, withInstall } from '../_util/type';
1817

1918
function noop() {}
2019

20+
function getDefaultSlot(slots: Record<string, any>, props: Record<string, any>, prop: string) {
21+
return slots[prop]?.() ?? props[prop];
22+
}
23+
2124
const iconMapFilled = {
2225
success: CheckCircleFilled,
2326
info: InfoCircleFilled,
@@ -32,11 +35,15 @@ const iconMapOutlined = {
3235
warning: ExclamationCircleOutlined,
3336
};
3437

35-
export const AlertProps = {
38+
const AlertTypes = tuple('success', 'info', 'warning', 'error');
39+
40+
export type AlertType = typeof AlertTypes[number];
41+
42+
const alertProps = () => ({
3643
/**
3744
* Type of Alert styles, options: `success`, `info`, `warning`, `error`
3845
*/
39-
type: PropTypes.oneOf(tuple('success', 'info', 'warning', 'error')),
46+
type: PropTypes.oneOf(AlertTypes),
4047
/** Whether Alert can be closed */
4148
closable: PropTypes.looseBool,
4249
/** Close text to show */
@@ -55,114 +62,114 @@ export const AlertProps = {
5562
banner: PropTypes.looseBool,
5663
icon: PropTypes.VNodeChild,
5764
onClose: PropTypes.VNodeChild,
58-
};
65+
});
66+
67+
export type AlertProps = Partial<ExtractPropTypes<ReturnType<typeof alertProps>>>;
5968

6069
const Alert = defineComponent({
6170
name: 'AAlert',
62-
mixins: [BaseMixin],
71+
props: alertProps(),
6372
inheritAttrs: false,
64-
props: AlertProps,
6573
emits: ['close'],
66-
setup() {
67-
return {
68-
configProvider: inject('configProvider', defaultConfigProvider),
69-
};
70-
},
71-
data() {
72-
return {
73-
closing: false,
74-
closed: false,
75-
};
76-
},
77-
methods: {
78-
handleClose(e: Event) {
74+
setup(props, { slots, emit, attrs }) {
75+
const configProvider = inject('configProvider', defaultConfigProvider);
76+
const closing = ref(false);
77+
const closed = ref(false);
78+
const alertNode = ref();
79+
80+
const handleClose = (e: MouseEvent) => {
7981
e.preventDefault();
80-
const dom = findDOMNode(this);
82+
83+
const dom = alertNode.value;
84+
8185
dom.style.height = `${dom.offsetHeight}px`;
8286
// Magic code
8387
// 重复一次后才能正确设置 height
8488
dom.style.height = `${dom.offsetHeight}px`;
8589

86-
this.setState({
87-
closing: true,
88-
});
89-
this.$emit('close', e);
90-
},
91-
animationEnd() {
92-
this.setState({
93-
closing: false,
94-
closed: true,
90+
closing.value = true;
91+
emit('close', e);
92+
};
93+
94+
const animationEnd = () => {
95+
closing.value = false;
96+
closed.value = true;
97+
props.afterClose?.();
98+
};
99+
100+
return () => {
101+
const { prefixCls: customizePrefixCls, banner } = props;
102+
const { getPrefixCls } = configProvider;
103+
const prefixCls = getPrefixCls('alert', customizePrefixCls);
104+
105+
let { closable, type, showIcon } = props;
106+
107+
const closeText = getDefaultSlot(slots, props, 'closeText');
108+
const description = getDefaultSlot(slots, props, 'description');
109+
const message = getDefaultSlot(slots, props, 'message');
110+
const icon = getDefaultSlot(slots, props, 'icon');
111+
112+
// banner模式默认有 Icon
113+
showIcon = banner && showIcon === undefined ? true : showIcon;
114+
// banner模式默认为警告
115+
type = banner && type === undefined ? 'warning' : type || 'info';
116+
117+
const IconType = (description ? iconMapOutlined : iconMapFilled)[type] || null;
118+
119+
// closeable when closeText is assigned
120+
if (closeText) {
121+
closable = true;
122+
}
123+
124+
const alertCls = classNames(prefixCls, {
125+
[`${prefixCls}-${type}`]: true,
126+
[`${prefixCls}-closing`]: closing.value,
127+
[`${prefixCls}-with-description`]: !!description,
128+
[`${prefixCls}-no-icon`]: !showIcon,
129+
[`${prefixCls}-banner`]: !!banner,
130+
[`${prefixCls}-closable`]: closable,
95131
});
96-
this.afterClose();
97-
},
98-
},
99132

100-
render() {
101-
const { prefixCls: customizePrefixCls, banner, closing, closed, $attrs } = this;
102-
const { getPrefixCls } = this.configProvider;
103-
const prefixCls = getPrefixCls('alert', customizePrefixCls);
104-
105-
let { closable, type, showIcon } = this;
106-
const closeText = getComponent(this, 'closeText');
107-
const description = getComponent(this, 'description');
108-
const message = getComponent(this, 'message');
109-
const icon = getComponent(this, 'icon');
110-
// banner模式默认有 Icon
111-
showIcon = banner && showIcon === undefined ? true : showIcon;
112-
// banner模式默认为警告
113-
type = banner && type === undefined ? 'warning' : type || 'info';
114-
115-
const IconType = (description ? iconMapOutlined : iconMapFilled)[type] || null;
116-
117-
// closeable when closeText is assigned
118-
if (closeText) {
119-
closable = true;
120-
}
121-
122-
const alertCls = classNames(prefixCls, {
123-
[`${prefixCls}-${type}`]: true,
124-
[`${prefixCls}-closing`]: closing,
125-
[`${prefixCls}-with-description`]: !!description,
126-
[`${prefixCls}-no-icon`]: !showIcon,
127-
[`${prefixCls}-banner`]: !!banner,
128-
[`${prefixCls}-closable`]: closable,
129-
});
130-
131-
const closeIcon = closable ? (
132-
<button
133-
type="button"
134-
onClick={this.handleClose}
135-
class={`${prefixCls}-close-icon`}
136-
tabindex={0}
137-
>
138-
{closeText ? <span class={`${prefixCls}-close-text`}>{closeText}</span> : <CloseOutlined />}
139-
</button>
140-
) : null;
141-
142-
const iconNode = (icon &&
143-
(isValidElement(icon) ? (
144-
cloneVNode(icon, {
145-
class: `${prefixCls}-icon`,
146-
})
147-
) : (
148-
<span class={`${prefixCls}-icon`}>{icon}</span>
149-
))) || <IconType class={`${prefixCls}-icon`} />;
150-
// h(iconType, { class: `${prefixCls}-icon` });
151-
152-
const transitionProps = getTransitionProps(`${prefixCls}-slide-up`, {
153-
appear: false,
154-
onAfterLeave: this.animationEnd,
155-
});
156-
return closed ? null : (
157-
<Transition {...transitionProps}>
158-
<div {...$attrs} v-show={!closing} class={[$attrs.class, alertCls]} data-show={!closing}>
159-
{showIcon ? iconNode : null}
160-
<span class={`${prefixCls}-message`}>{message}</span>
161-
<span class={`${prefixCls}-description`}>{description}</span>
162-
{closeIcon}
163-
</div>
164-
</Transition>
165-
);
133+
const closeIcon = closable ? (
134+
<button type="button" onClick={handleClose} class={`${prefixCls}-close-icon`} tabindex={0}>
135+
{closeText ? (
136+
<span class={`${prefixCls}-close-text`}>{closeText}</span>
137+
) : (
138+
<CloseOutlined />
139+
)}
140+
</button>
141+
) : null;
142+
143+
const iconNode = (icon &&
144+
(isValidElement(icon) ? (
145+
cloneVNode(icon, {
146+
class: `${prefixCls}-icon`,
147+
})
148+
) : (
149+
<span class={`${prefixCls}-icon`}>{icon}</span>
150+
))) || <IconType class={`${prefixCls}-icon`} />;
151+
152+
const transitionProps = getTransitionProps(`${prefixCls}-slide-up`, {
153+
appear: false,
154+
onAfterLeave: animationEnd,
155+
});
156+
return closed.value ? null : (
157+
<Transition {...transitionProps}>
158+
<div
159+
{...attrs}
160+
v-show={!closing.value}
161+
class={[attrs.class, alertCls]}
162+
data-show={!closing.value}
163+
ref={alertNode}
164+
>
165+
{showIcon ? iconNode : null}
166+
<span class={`${prefixCls}-message`}>{message}</span>
167+
<span class={`${prefixCls}-description`}>{description}</span>
168+
{closeIcon}
169+
</div>
170+
</Transition>
171+
);
172+
};
166173
},
167174
});
168175

0 commit comments

Comments
 (0)