refactor: float-button

pull/6348/head
tangjinzhou 2023-03-03 16:58:47 +08:00
parent 355c41b4aa
commit add208aefb
17 changed files with 136 additions and 146 deletions

View File

@ -33,7 +33,7 @@ export type BackTopProps = Partial<ExtractPropTypes<typeof backTopProps>>;
const BackTop = defineComponent({ const BackTop = defineComponent({
compatConfig: { MODE: 3 }, compatConfig: { MODE: 3 },
name: 'ABackTop', name: 'ABackTopLegacy',
inheritAttrs: false, inheritAttrs: false,
props: backTopProps(), props: backTopProps(),
// emits: ['click'], // emits: ['click'],

View File

@ -13,9 +13,6 @@ export { default as Alert } from './alert';
export type { AvatarProps } from './avatar'; export type { AvatarProps } from './avatar';
export { default as Avatar, AvatarGroup } from './avatar'; export { default as Avatar, AvatarGroup } from './avatar';
export type { BackTopProps } from './back-top';
export { default as BackTop } from './back-top';
export type { BadgeProps } from './badge'; export type { BadgeProps } from './badge';
export { default as Badge, BadgeRibbon } from './badge'; export { default as Badge, BadgeRibbon } from './badge';
@ -76,8 +73,12 @@ export { default as Drawer } from './drawer';
export type { EmptyProps } from './empty'; export type { EmptyProps } from './empty';
export { default as Empty } from './empty'; export { default as Empty } from './empty';
export type { FloatButtonProps, FloatButtonGroupProps } from './float-button/interface'; export type {
export { default as FloatButton, FloatButtonGroup } from './float-button'; FloatButtonProps,
FloatButtonGroupProps,
BackTopProps,
} from './float-button/interface';
export { default as FloatButton, FloatButtonGroup, BackTop } from './float-button';
export type { FormProps, FormItemProps, FormInstance, FormItemInstance } from './form'; export type { FormProps, FormItemProps, FormInstance, FormItemInstance } from './form';
export { default as Form, FormItem, FormItemRest } from './form'; export { default as Form, FormItem, FormItemRest } from './form';

View File

@ -11,16 +11,16 @@ import {
watch, watch,
onDeactivated, onDeactivated,
} from 'vue'; } from 'vue';
import FloatButton from './FloatButton'; import FloatButton, { floatButtonPrefixCls } from './FloatButton';
import useConfigInject from '../config-provider/hooks/useConfigInject'; import useConfigInject from '../config-provider/hooks/useConfigInject';
import getScroll from '../_util/getScroll'; import getScroll from '../_util/getScroll';
import scrollTo from '../_util/scrollTo'; import scrollTo from '../_util/scrollTo';
import throttleByAnimationFrame from '../_util/throttleByAnimationFrame'; import throttleByAnimationFrame from '../_util/throttleByAnimationFrame';
import { initDefaultProps } from '../_util/props-util'; import { initDefaultProps } from '../_util/props-util';
import { backTopProps } from './interface'; import { backTopProps } from './interface';
import { floatButtonPrefixCls } from './FloatButton';
import useStyle from './style'; import useStyle from './style';
import { useInjectFloatButtonGroupContext } from './context';
const BackTop = defineComponent({ const BackTop = defineComponent({
compatConfig: { MODE: 3 }, compatConfig: { MODE: 3 },
@ -30,6 +30,8 @@ const BackTop = defineComponent({
visibilityHeight: 400, visibilityHeight: 400,
target: () => window, target: () => window,
duration: 450, duration: 450,
type: 'default',
shape: 'circle',
}), }),
// emits: ['click'], // emits: ['click'],
setup(props, { slots, attrs, emit }) { setup(props, { slots, attrs, emit }) {
@ -39,7 +41,7 @@ const BackTop = defineComponent({
const domRef = ref(); const domRef = ref();
const state = reactive({ const state = reactive({
visible: false, visible: props.visibilityHeight === 0,
scrollEvent: null, scrollEvent: null,
}); });
@ -106,7 +108,7 @@ const BackTop = defineComponent({
onBeforeUnmount(() => { onBeforeUnmount(() => {
scrollRemove(); scrollRemove();
}); });
const floatButtonGroupContext = useInjectFloatButtonGroupContext();
return () => { return () => {
const defaultElement = ( const defaultElement = (
<div class={`${prefixCls.value}-content`}> <div class={`${prefixCls.value}-content`}>
@ -115,8 +117,9 @@ const BackTop = defineComponent({
</div> </div>
</div> </div>
); );
const divProps = { const floatButtonProps = {
...attrs, ...attrs,
shape: floatButtonGroupContext?.shape.value || props.shape,
onClick: scrollToTop, onClick: scrollToTop,
class: { class: {
[`${prefixCls.value}`]: true, [`${prefixCls.value}`]: true,
@ -128,7 +131,7 @@ const BackTop = defineComponent({
const transitionProps = getTransitionProps('fade'); const transitionProps = getTransitionProps('fade');
return wrapSSR( return wrapSSR(
<Transition {...transitionProps}> <Transition {...transitionProps}>
<FloatButton v-show={state.visible} {...divProps} ref={domRef}> <FloatButton v-show={state.visible} {...floatButtonProps} ref={domRef}>
{{ {{
icon: () => <VerticalAlignTopOutlined />, icon: () => <VerticalAlignTopOutlined />,
default: () => slots.default?.() || defaultElement, default: () => slots.default?.() || defaultElement,

View File

@ -1,10 +1,9 @@
import classNames from '../_util/classNames'; import classNames from '../_util/classNames';
import { defineComponent, computed, CSSProperties, ref } from 'vue'; import { defineComponent, computed, ref } from 'vue';
import Tooltip from '../tooltip'; import Tooltip from '../tooltip';
import Content from './FloatButtonContent'; import Content from './FloatButtonContent';
import type { FloatButtonContentProps } from './interface';
import useConfigInject from '../config-provider/hooks/useConfigInject'; import useConfigInject from '../config-provider/hooks/useConfigInject';
import FloatButtonGroupContext from './context'; import { useInjectFloatButtonGroupContext } from './context';
import warning from '../_util/warning'; import warning from '../_util/warning';
import { initDefaultProps } from '../_util/props-util'; import { initDefaultProps } from '../_util/props-util';
import { floatButtonProps } from './interface'; import { floatButtonProps } from './interface';
@ -20,39 +19,30 @@ const FloatButton = defineComponent({
name: 'AFloatButton', name: 'AFloatButton',
inheritAttrs: false, inheritAttrs: false,
props: initDefaultProps(floatButtonProps(), { type: 'default', shape: 'circle' }), props: initDefaultProps(floatButtonProps(), { type: 'default', shape: 'circle' }),
setup(props, { attrs, slots, expose }) { setup(props, { attrs, slots }) {
const { prefixCls, direction } = useConfigInject(floatButtonPrefixCls, props); const { prefixCls, direction } = useConfigInject(floatButtonPrefixCls, props);
const [wrapSSR, hashId] = useStyle(prefixCls); const [wrapSSR, hashId] = useStyle(prefixCls);
const { shape: groupShape } = FloatButtonGroupContext.useInject(); const { shape: groupShape } = useInjectFloatButtonGroupContext();
const floatButtonRef = ref(null); const floatButtonRef = ref<HTMLAnchorElement | HTMLButtonElement>(null);
const mergeShape = computed(() => { const mergeShape = computed(() => {
return groupShape?.value || props.shape; return groupShape?.value || props.shape;
}); });
expose({
floatButtonEl: floatButtonRef,
});
return () => { return () => {
const { const {
prefixCls: customPrefixCls, prefixCls: customPrefixCls,
type = 'default', type = 'default',
shape = 'circle', shape = 'circle',
description, description = slots.description?.(),
tooltip, tooltip,
...restProps ...restProps
} = props; } = props;
const contentProps: FloatButtonContentProps = {
prefixCls: prefixCls.value,
description,
};
const classString = classNames( const classString = classNames(
prefixCls.value, prefixCls.value,
`${prefixCls.value}-${props.type}`, `${prefixCls.value}-${type}`,
`${prefixCls.value}-${mergeShape.value}`, `${prefixCls.value}-${mergeShape.value}`,
{ {
[`${prefixCls.value}-rtl`]: direction.value === 'rtl', [`${prefixCls.value}-rtl`]: direction.value === 'rtl',
@ -62,24 +52,26 @@ const FloatButton = defineComponent({
); );
const buttonNode = ( const buttonNode = (
<Tooltip placement="left"> <Tooltip
{{ placement="left"
v-slots={{
title: title:
slots.tooltip || tooltip slots.tooltip || tooltip
? () => (slots.tooltip && slots.tooltip()) || tooltip ? () => (slots.tooltip && slots.tooltip()) || tooltip
: undefined, : undefined,
default: () => ( default: () => (
<div class={`${prefixCls.value}-body`}> <div class={`${prefixCls.value}-body`}>
<Content {...contentProps}> <Content
{{ prefixCls={prefixCls.value}
v-slots={{
icon: slots.icon, icon: slots.icon,
description: slots.description, description: () => description,
}} }}
</Content> ></Content>
</div> </div>
), ),
}} }}
</Tooltip> ></Tooltip>
); );
if (process.env.NODE_ENV !== 'production') { if (process.env.NODE_ENV !== 'production') {
@ -92,24 +84,11 @@ const FloatButton = defineComponent({
return wrapSSR( return wrapSSR(
props.href ? ( props.href ? (
<a <a ref={floatButtonRef} {...attrs} {...(restProps as any)} class={classString}>
ref={floatButtonRef}
{...attrs}
{...(restProps as any)}
class={classString}
style={attrs.style as CSSProperties}
>
{buttonNode} {buttonNode}
</a> </a>
) : ( ) : (
<button <button ref={floatButtonRef} {...attrs} {...restProps} class={classString} type="button">
ref={floatButtonRef}
{...attrs}
{...restProps}
class={classString}
style={attrs.style as CSSProperties}
type="button"
>
{buttonNode} {buttonNode}
</button> </button>
), ),

View File

@ -1,7 +1,7 @@
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import FileTextOutlined from '@ant-design/icons-vue/FileTextOutlined'; import FileTextOutlined from '@ant-design/icons-vue/FileTextOutlined';
import classNames from '../_util/classNames';
import { floatButtonContentProps } from './interface'; import { floatButtonContentProps } from './interface';
import { filterEmpty } from '../_util/props-util';
const FloatButtonContent = defineComponent({ const FloatButtonContent = defineComponent({
compatConfig: { MODE: 3 }, compatConfig: { MODE: 3 },
@ -10,27 +10,22 @@ const FloatButtonContent = defineComponent({
props: floatButtonContentProps(), props: floatButtonContentProps(),
setup(props, { attrs, slots }) { setup(props, { attrs, slots }) {
return () => { return () => {
const { description, prefixCls } = props; const { prefixCls } = props;
const description = filterEmpty(slots.description?.());
const defaultElement = (
<div class={`${prefixCls}-icon`}>
<FileTextOutlined />
</div>
);
return ( return (
<div {...attrs} class={classNames(attrs.class, `${prefixCls}-content`)}> <div {...attrs} class={[attrs.class, `${prefixCls}-content`]}>
{slots.icon || description ? ( {slots.icon || description.length ? (
<> <>
{slots.icon && <div class={`${prefixCls}-icon`}>{slots.icon()}</div>} {slots.icon && <div class={`${prefixCls}-icon`}>{slots.icon()}</div>}
{(slots.description || description) && ( {description.length ? (
<div class={`${prefixCls}-description`}> <div class={`${prefixCls}-description`}>{description}</div>
{(slots.description && slots.description()) || description} ) : null}
</div>
)}
</> </>
) : ( ) : (
defaultElement <div class={`${prefixCls}-icon`}>
<FileTextOutlined />
</div>
)} )}
</div> </div>
); );

View File

@ -1,17 +1,18 @@
import { defineComponent, ref, computed, watch } from 'vue'; import { defineComponent, ref, computed, watch, onBeforeUnmount } from 'vue';
import CloseOutlined from '@ant-design/icons-vue/CloseOutlined'; import CloseOutlined from '@ant-design/icons-vue/CloseOutlined';
import FileTextOutlined from '@ant-design/icons-vue/FileTextOutlined'; import FileTextOutlined from '@ant-design/icons-vue/FileTextOutlined';
import classNames from '../_util/classNames'; import classNames from '../_util/classNames';
import { getTransitionProps, Transition } from '../_util/transition'; import { getTransitionProps, Transition } from '../_util/transition';
import FloatButton, { floatButtonPrefixCls } from './FloatButton'; import FloatButton, { floatButtonPrefixCls } from './FloatButton';
import useConfigInject from '../config-provider/hooks/useConfigInject'; import useConfigInject from '../config-provider/hooks/useConfigInject';
import FloatButtonGroupContext from './context'; import { useProvideFloatButtonGroupContext } from './context';
import { initDefaultProps } from '../_util/props-util'; import { findDOMNode, initDefaultProps } from '../_util/props-util';
import { floatButtonGroupProps } from './interface'; import { floatButtonGroupProps } from './interface';
import type { FloatButtonGroupProps } from './interface'; import type { FloatButtonGroupProps } from './interface';
// CSSINJS // CSSINJS
import useStyle from './style'; import useStyle from './style';
import useMergedState from '../_util/hooks/useMergedState';
const FloatButtonGroup = defineComponent({ const FloatButtonGroup = defineComponent({
compatConfig: { MODE: 3 }, compatConfig: { MODE: 3 },
@ -21,63 +22,68 @@ const FloatButtonGroup = defineComponent({
type: 'default', type: 'default',
shape: 'circle', shape: 'circle',
} as FloatButtonGroupProps), } as FloatButtonGroupProps),
setup(props, { attrs, slots }) { setup(props, { attrs, slots, emit }) {
const { prefixCls, direction } = useConfigInject(floatButtonPrefixCls, props); const { prefixCls, direction } = useConfigInject(floatButtonPrefixCls, props);
// style // style
const [wrapSSR, hashId] = useStyle(prefixCls); const [wrapSSR, hashId] = useStyle(prefixCls);
const open = ref(props.open); const [open, setOpen] = useMergedState(false, { value: computed(() => props.open) });
const floatButtonGroupRef = ref<HTMLDivElement>(null); const floatButtonGroupRef = ref<HTMLDivElement>(null);
const floatButtonRef = ref<HTMLButtonElement | HTMLAnchorElement>(null); const floatButtonRef = ref<HTMLButtonElement | HTMLAnchorElement>(null);
FloatButtonGroupContext.useProvide({ useProvideFloatButtonGroupContext({
shape: computed(() => props.shape), shape: computed(() => props.shape),
}); });
const hoverTypeAction = {
onMouseenter() {
setOpen(true);
emit('update:open', true);
props.onOpenChange?.(true);
},
onMouseleave() {
setOpen(false);
emit('update:open', false);
props.onOpenChange?.(false);
},
};
const hoverAction = computed(() => { const hoverAction = computed(() => {
const hoverTypeAction = {
onMouseenter() {
open.value = true;
props.onOpenChange?.(true);
},
onMouseleave() {
open.value = false;
props.onOpenChange?.(false);
},
};
return props.trigger === 'hover' ? hoverTypeAction : {}; return props.trigger === 'hover' ? hoverTypeAction : {};
}); });
const handleOpenChange = () => { const handleOpenChange = () => {
open.value = !open.value; const nextOpen = !open.value;
props.onOpenChange?.(!open.value); emit('update:open', nextOpen);
props.onOpenChange?.(nextOpen);
setOpen(nextOpen);
}; };
const onClick = (e: MouseEvent) => { const onClick = (e: MouseEvent) => {
if (floatButtonGroupRef.value?.contains(e.target as Node)) { if (floatButtonGroupRef.value?.contains(e.target as Node)) {
if ((floatButtonRef.value as any)?.floatButtonEl?.contains(e.target as Node)) { if (findDOMNode(floatButtonRef.value)?.contains(e.target as Node)) {
handleOpenChange(); handleOpenChange();
} }
return; return;
} }
open.value = false; setOpen(false);
emit('update:open', false);
props.onOpenChange?.(false); props.onOpenChange?.(false);
}; };
watch( watch(
computed(() => props.trigger), computed(() => props.trigger),
value => { value => {
document.removeEventListener('click', onClick);
if (value === 'click') { if (value === 'click') {
document.addEventListener('click', onClick); document.addEventListener('click', onClick);
return () => {
document.removeEventListener('click', onClick);
};
} }
}, },
{ immediate: true }, { immediate: true },
); );
onBeforeUnmount(() => {
document.removeEventListener('click', onClick);
});
return () => { return () => {
const { shape = 'circle', type = 'default', tooltip, description, trigger } = props; const { shape = 'circle', type = 'default', tooltip, description, trigger } = props;
@ -99,7 +105,7 @@ const FloatButtonGroup = defineComponent({
{trigger && ['click', 'hover'].includes(trigger) ? ( {trigger && ['click', 'hover'].includes(trigger) ? (
<> <>
<Transition {...transitionProps}> <Transition {...transitionProps}>
<div v-show={open.value} class={classNames(wrapperCls)}> <div v-show={open.value} class={wrapperCls}>
{slots.default && slots.default()} {slots.default && slots.default()}
</div> </div>
</Transition> </Transition>
@ -109,19 +115,18 @@ const FloatButtonGroup = defineComponent({
shape={shape} shape={shape}
tooltip={tooltip} tooltip={tooltip}
description={description} description={description}
> v-slots={{
{{
icon: () => icon: () =>
open.value open.value
? (slots.closeIcon && slots.closeIcon()) || <CloseOutlined /> ? slots.closeIcon?.() || <CloseOutlined />
: (slots.icon && slots.icon()) || <FileTextOutlined />, : slots.icon?.() || <FileTextOutlined />,
tooltip: slots.tooltip, tooltip: slots.tooltip,
description: slots.description, description: slots.description,
}} }}
</FloatButton> ></FloatButton>
</> </>
) : ( ) : (
slots.default && slots.default() slots.default?.()
)} )}
</div>, </div>,
); );

View File

@ -1,29 +1,19 @@
import type { Ref } from 'vue'; import type { Ref, InjectionKey } from 'vue';
import { inject, provide } from 'vue'; import { inject, provide, ref } from 'vue';
import type { FloatButtonShape } from './interface'; import type { FloatButtonShape } from './interface';
function createContext<T extends Record<string, any>>(defaultValue?: T) { interface FloatButtonGroupContext {
const contextKey = Symbol('floatButtonGroupContext'); shape: Ref<FloatButtonShape>;
const useProvide = (props: T) => {
provide(contextKey, props);
return props;
};
const useInject = () => {
return inject(contextKey, defaultValue as T) || ({} as T);
};
return {
useProvide,
useInject,
};
} }
const contextKey: InjectionKey<FloatButtonGroupContext> = Symbol('floatButtonGroupContext');
const FloatButtonGroupContext = createContext<{ shape: Ref<FloatButtonShape> } | undefined>( export const useProvideFloatButtonGroupContext = (props: FloatButtonGroupContext) => {
undefined, provide(contextKey, props);
);
export default FloatButtonGroupContext; return props;
};
export const useInjectFloatButtonGroupContext = () => {
return inject(contextKey, { shape: ref() } as FloatButtonGroupContext);
};

View File

@ -32,10 +32,8 @@ title:
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import { FileTextOutlined } from '@ant-design/icons-vue';
export default defineComponent({ export default defineComponent({
components: { FileTextOutlined },
setup() { setup() {
return {}; return {};
}, },

View File

@ -25,7 +25,7 @@ When multiple buttons are used together, `<FloatButton.Group />` is recommended.
</template> </template>
</a-float-button> </a-float-button>
<a-float-button /> <a-float-button />
<a-back-top :visibilityHeight="0" /> <a-back-top :visibility-height="0" />
</a-float-button-group> </a-float-button-group>
<a-float-button-group shape="square" :style="{ right: '94px' }"> <a-float-button-group shape="square" :style="{ right: '94px' }">
<a-float-button> <a-float-button>
@ -40,7 +40,7 @@ When multiple buttons are used together, `<FloatButton.Group />` is recommended.
<SyncOutlined /> <SyncOutlined />
</template> </template>
</a-float-button> </a-float-button>
<a-back-top :visibilityHeight="0" /> <a-back-top :visibility-height="0" />
</a-float-button-group> </a-float-button-group>
</template> </template>

View File

@ -25,18 +25,28 @@ FloatButton. Available since `4.0.0`.
| tooltip | The text shown in the tooltip | string \| slot | | | | tooltip | The text shown in the tooltip | string \| slot | | |
| type | Setting button type | `default` \| `primary` | `default` | | | type | Setting button type | `default` \| `primary` | `default` | |
| shape | Setting button shape | `circle` \| `square` | `circle` | | | shape | Setting button shape | `circle` \| `square` | `circle` | |
| onClick | Set the handler to handle `click` event | (event) => void | - | |
| href | The target of hyperlink | string | - | | | href | The target of hyperlink | string | - | |
| target | Specifies where to display the linked URL | string | - | | | target | Specifies where to display the linked URL | string | - | |
### common events
| Events Name | Description | Arguments | Version |
| ----------- | --------------------------------------- | ----------------- | ------- |
| click | Set the handler to handle `click` event | `(event) => void` | - |
### FloatButton.Group ### FloatButton.Group
| Property | Description | Type | Default | Version | | Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- |
| shape | Setting button shape of children | `circle` \| `square` | `circle` | | | shape | Setting button shape of children | `circle` \| `square` | `circle` | |
| trigger | Which action can trigger menu open/close | `click` \| `hover` | - | | | trigger | Which action can trigger menu open/close | `click` \| `hover` | - | |
| open | Whether the menu is visible or not | boolean | - | | | open(v-model) | Whether the menu is visible or not | boolean | - | |
| onOpenChange | Callback executed when active menu is changed | (open: boolean) => void | - | |
### FloatButton.Group Events
| Events Name | Description | Arguments | Version |
| ----------- | --------------------------------------------- | ----------------------- | ------- |
| openChange | Callback executed when active menu is changed | (open: boolean) => void | - |
### FloatButton.BackTop ### FloatButton.BackTop
@ -45,4 +55,3 @@ FloatButton. Available since `4.0.0`.
| duration | Time to return to topms | number | 450 | | | duration | Time to return to topms | number | 450 | |
| target | Specifies the scrollable area dom node | () => HTMLElement | () => window | | | target | Specifies the scrollable area dom node | () => HTMLElement | () => window | |
| visibilityHeight | The BackTop button will not show until the scroll height reaches this value | number | 400 | | | visibilityHeight | The BackTop button will not show until the scroll height reaches this value | number | 400 | |
| onClick | A callback function, which can be executed when you click the button | () => void | - | |

View File

@ -33,7 +33,7 @@ FloatButton.install = function (app: App) {
return app; return app;
}; };
export { FloatButtonGroup }; export { FloatButtonGroup, BackTop };
export default FloatButton as typeof FloatButton & export default FloatButton as typeof FloatButton &
Plugin & { Plugin & {

View File

@ -30,14 +30,25 @@ cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*HS-wTIIwu0kAAAAAAA
| href | 点击跳转的地址,指定此属性 button 的行为和 a 链接一致 | string | - | | | href | 点击跳转的地址,指定此属性 button 的行为和 a 链接一致 | string | - | |
| target | 相当于 a 标签的 target 属性href 存在时生效 | string | - | | | target | 相当于 a 标签的 target 属性href 存在时生效 | string | - | |
### common events
| 事件名称 | 说明 | 回调参数 | 版本 |
| -------- | --------------------------------------- | ----------------- | ---- |
| click | Set the handler to handle `click` event | `(event) => void` | - |
### FloatButton.Group ### FloatButton.Group
| 参数 | 说明 | 类型 | 默认值 | 版本 | | 参数 | 说明 | 类型 | 默认值 | 版本 |
| ------------ | -------------------------------- | ----------------------- | -------- | ---- | | ------------- | -------------------------------- | -------------------- | -------- | ---- |
| shape | 设置包含的 FloatButton 按钮形状 | `circle` \| `square` | `circle` | | | shape | 设置包含的 FloatButton 按钮形状 | `circle` \| `square` | `circle` | |
| trigger | 触发方式(有触发方式为菜单模式) | `click` \| `hover` | - | | | trigger | 触发方式(有触发方式为菜单模式) | `click` \| `hover` | - | |
| open | 受控展开 | boolean | - | | | open(v-model) | 受控展开 | boolean | - | |
| onOpenChange | 展开收起时的回调 | (open: boolean) => void | - | |
### FloatButton.Group Events
| 事件名称 | 说明 | 回调参数 | 版本 |
| ---------- | ---------------- | ----------------------- | ---- |
| openChange | 展开收起时的回调 | (open: boolean) => void | - |
### FloatButton.BackTop ### FloatButton.BackTop

View File

@ -27,7 +27,6 @@ export type FloatButtonProps = Partial<ExtractPropTypes<ReturnType<typeof floatB
export const floatButtonContentProps = () => { export const floatButtonContentProps = () => {
return { return {
prefixCls: stringType<FloatButtonProps['prefixCls']>(), prefixCls: stringType<FloatButtonProps['prefixCls']>(),
description: PropTypes.any,
}; };
}; };
@ -42,9 +41,10 @@ export const floatButtonGroupProps = () => {
// 触发方式 (有触发方式为菜单模式) // 触发方式 (有触发方式为菜单模式)
trigger: stringType<FloatButtonGroupTrigger>(), trigger: stringType<FloatButtonGroupTrigger>(),
// 受控展开 // 受控展开
open: booleanType(false), open: booleanType(),
// 展开收起的回调 // 展开收起的回调
onOpenChange: functionType<(open: boolean) => void>(), onOpenChange: functionType<(open: boolean) => void>(),
'onUpdate:open': functionType<(open: boolean) => void>(),
}; };
}; };

View File

@ -12,7 +12,7 @@ Used when the link needs to be converted into a QR Code.
## API ## API
| Property | Description | Type | Default | | Property | Description | Type | Default |
| :-- | :-- | :-- | :-- | | --- | --- | --- | --- |
| value | scanned link | string | - | | value | scanned link | string | - |
| icon | include image url (only image link are supported) | string | - | | icon | include image url (only image link are supported) | string | - |
| size | QRCode size | number | 128 | | size | QRCode size | number | 128 |
@ -25,7 +25,7 @@ Used when the link needs to be converted into a QR Code.
### events ### events
| Events Name | Description | Arguments | Version | | Events Name | Description | Arguments | Version |
| :---------- | :---------- | :----------- | :------ | | ----------- | ----------- | ------------ | ------- |
| refresh | callback | `() => void` | - | | refresh | callback | `() => void` | - |
## FAQ ## FAQ

View File

@ -1,5 +1,5 @@
import { defineComponent, computed, ref } from 'vue'; import { defineComponent, computed, ref } from 'vue';
import type { CSSProperties } from 'vue'; import type { CSSProperties, ExtractPropTypes } from 'vue';
import useConfigInject from '../config-provider/hooks/useConfigInject'; import useConfigInject from '../config-provider/hooks/useConfigInject';
import useStyle from './style'; import useStyle from './style';
import { useLocaleReceiver } from '../locale/LocaleReceiver'; import { useLocaleReceiver } from '../locale/LocaleReceiver';
@ -10,9 +10,9 @@ import { ReloadOutlined } from '@ant-design/icons-vue';
import { useToken } from '../theme/internal'; import { useToken } from '../theme/internal';
import { QRCodeCanvas } from './QRCodeCanvas'; import { QRCodeCanvas } from './QRCodeCanvas';
import warning from '../_util/warning'; import warning from '../_util/warning';
import type { QRCodeProps } from './interface';
import { qrcodeProps } from './interface'; import { qrcodeProps } from './interface';
export type QRCodeProps = Partial<ExtractPropTypes<ReturnType<typeof qrcodeProps>>>;
const QRCode = defineComponent({ const QRCode = defineComponent({
name: 'AQrcode', name: 'AQrcode',
inheritAttrs: false, inheritAttrs: false,

View File

@ -13,7 +13,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*M4PBTZ_n9OgAAA
## API ## API
| 参数 | 说明 | 类型 | 默认值 | | 参数 | 说明 | 类型 | 默认值 |
| :-- | :-- | :-- | :-- | | --- | --- | --- | --- |
| value | 扫描后的地址 | string | - | | value | 扫描后的地址 | string | - |
| icon | 二维码中图片的地址(目前只支持图片地址) | string | - | | icon | 二维码中图片的地址(目前只支持图片地址) | string | - |
| size | 二维码大小 | number | 160 | | size | 二维码大小 | number | 160 |
@ -26,7 +26,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*M4PBTZ_n9OgAAA
### 事件 ### 事件
| 事件名称 | 说明 | 回调参数 | 版本 | | 事件名称 | 说明 | 回调参数 | 版本 |
| :------- | :------------------- | :----------- | :--- | | -------- | -------------------- | ------------ | ---- |
| refresh | 点击"点击刷新"的回调 | `() => void` | - | | refresh | 点击"点击刷新"的回调 | `() => void` | - |
## FAQ ## FAQ

View File

@ -1,5 +1,5 @@
import { objectType, stringType } from '../_util/type'; import { objectType, stringType } from '../_util/type';
import type { ExtractPropTypes } from 'vue';
interface ImageSettings { interface ImageSettings {
src: string; src: string;
height: number; height: number;
@ -30,7 +30,6 @@ export const qrcodeProps = () => {
bordered: { type: Boolean, default: true }, bordered: { type: Boolean, default: true },
}; };
}; };
export type QRCodeProps = Partial<ExtractPropTypes<ReturnType<typeof qrcodeProps>>>;
export interface QRCodeCanvasColor { export interface QRCodeCanvasColor {
dark?: string; // 默认#000000ff dark?: string; // 默认#000000ff