diff --git a/src/fab/fab.en-US.md b/src/fab/fab.en-US.md index bf6ab2cc8..a2e72ddc6 100644 --- a/src/fab/fab.en-US.md +++ b/src/fab/fab.en-US.md @@ -10,6 +10,7 @@ buttonProps | Object | - | Typescript:`ButtonProps`,[Button API Documents](. icon | Slot / Function | - | Typescript:`TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N style | String | right: 16px; bottom: 32px; | \- | N text | String | - | \- | N +draggable | Boolean | false | set draggable | N onClick | Function | | Typescript:`(context: {e: MouseEvent}) => void`
| N ### Fab Events diff --git a/src/fab/fab.md b/src/fab/fab.md index f3defd30e..db4b734d0 100644 --- a/src/fab/fab.md +++ b/src/fab/fab.md @@ -10,6 +10,7 @@ buttonProps | Object | - | 透传至 Button 组件。TS 类型:`ButtonProps` icon | Slot / Function | - | 图标。TS 类型:`TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N style | String | right: 16px; bottom: 32px; | 悬浮按钮的样式,常用于调整位置 | N text | String | - | 文本内容 | N +draggable | Boolean | false | 是否可拖动 | N onClick | Function | | TS 类型:`(context: {e: MouseEvent}) => void`
悬浮按钮点击事件 | N ### Fab Events diff --git a/src/fab/fab.tsx b/src/fab/fab.tsx index cee02acc3..0961c6407 100644 --- a/src/fab/fab.tsx +++ b/src/fab/fab.tsx @@ -1,4 +1,4 @@ -import { defineComponent } from 'vue'; +import { defineComponent, ref, computed, onMounted, watch } from 'vue'; import config from '../config'; import FabProps from './props'; import { useTNodeJSX } from '../hooks/tnode'; @@ -15,15 +15,121 @@ export default defineComponent({ const renderTNodeJSX = useTNodeJSX(); const fabClass = usePrefixClass('fab'); + const fabRef = ref(); const handleClick = (e: MouseEvent) => { props.onClick?.({ e }); }; + const mounted = ref(false); + const btnSwitchPos = ref({ + x: 16, + y: 32, + }); + const switchPos = ref({ + hasMoved: false, // exclude click event + x: btnSwitchPos.value.x, // right + y: btnSwitchPos.value.y, // bottom + startX: 0, + startY: 0, + endX: 0, + endY: 0, + }); + + const onTouchStart = (e: TouchEvent) => { + switchPos.value.startX = e.touches[0].pageX; + switchPos.value.startY = e.touches[0].pageY; + }; + + const onTouchMove = (e: TouchEvent) => { + e.stopPropagation(); + e.preventDefault(); + + if (!props.draggable) { + return; + } + + if (e.touches.length <= 0) { + return; + } + const offsetX = e.touches[0].pageX - switchPos.value.startX; + const offsetY = e.touches[0].pageY - switchPos.value.startY; + const x = Math.floor(switchPos.value.x - offsetX); + const y = Math.floor(switchPos.value.y - offsetY); + btnSwitchPos.value.x = x; + btnSwitchPos.value.y = y; + switchPos.value.endX = x; + switchPos.value.endY = y; + switchPos.value.hasMoved = true; + }; + + const onTouchEnd = (e: TouchEvent) => { + if (!switchPos.value.hasMoved) { + return; + } + switchPos.value.startX = 0; + switchPos.value.startY = 0; + switchPos.value.hasMoved = false; + setSwitchPosition(switchPos.value.endX, switchPos.value.endY); + }; + + const setSwitchPosition = (switchX: number, switchY: number) => { + switchPos.value.x = switchX; + switchPos.value.y = switchY; + btnSwitchPos.value.x = switchX; + btnSwitchPos.value.y = switchY; + }; + + const fabStyle = computed(() => ({ + right: `${btnSwitchPos.value.x}px`, + bottom: `${btnSwitchPos.value.y}px`, + })); + + onMounted(() => { + mounted.value = true; + resetDraggableParams(); + }); + + const getFabOriginStyle = () => { + const info = window.getComputedStyle(fabRef.value); + const { right, bottom } = info || {}; + const getNumber = (num: string) => num.replace(/[^\d]/g, ''); + + return { + right: +(getNumber(right) || 0), + bottom: +(getNumber(bottom) || 0), + }; + }; + + const resetDraggableParams = () => { + const { right, bottom } = getFabOriginStyle(); + + btnSwitchPos.value.x = right; + btnSwitchPos.value.y = bottom; + + switchPos.value.x = right; + switchPos.value.y = bottom; + }; + + watch( + () => props.style, + () => { + resetDraggableParams(); + }, + ); + return () => { const icon = () => renderTNodeJSX('icon'); return ( -
+
, + /** 是否可拖拽 */ + draggable: { + type: Boolean, + default: false, + } };