|
|
@@ -18,22 +18,40 @@
|
|
|
>
|
|
|
<view
|
|
|
:style="{
|
|
|
- width: `${props.leftWidth}px`,
|
|
|
- marginLeft: `-${props.leftWidth}px`,
|
|
|
+ width: leftWidth ? `${leftWidth}px` : 'auto',
|
|
|
+ marginLeft: `-${leftWidth}px`,
|
|
|
}"
|
|
|
class="left"
|
|
|
+ id="left"
|
|
|
>
|
|
|
- <slot name="left" />
|
|
|
+ <slot name="left">
|
|
|
+ <Button
|
|
|
+ v-for="action in leftActions"
|
|
|
+ :key="action.text" shape="square"
|
|
|
+ :type="action.type"
|
|
|
+ :text="action.text"
|
|
|
+ @click="action.onClick"
|
|
|
+ />
|
|
|
+ </slot>
|
|
|
</view>
|
|
|
<slot />
|
|
|
<view
|
|
|
+ id="right"
|
|
|
:style="{
|
|
|
- width: `${props.rightWidth}px`,
|
|
|
- marginRight: `-${props.rightWidth}px`,
|
|
|
+ width: rightWidth ? `${rightWidth}px` : 'auto',
|
|
|
+ marginRight: `-${rightWidth}px`,
|
|
|
}"
|
|
|
class="right"
|
|
|
>
|
|
|
- <slot name="right" />
|
|
|
+ <slot name="right">
|
|
|
+ <Button
|
|
|
+ v-for="action in rightActions"
|
|
|
+ :key="action.text" shape="square"
|
|
|
+ :type="action.type"
|
|
|
+ :text="action.text"
|
|
|
+ @click="action.onClick"
|
|
|
+ />
|
|
|
+ </slot>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
@@ -41,21 +59,45 @@
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
|
-import { nextTick, ref } from 'vue';
|
|
|
+import { computed, getCurrentInstance, nextTick, onMounted, onUpdated, ref } from 'vue';
|
|
|
import { useTheme } from '../theme/ThemeDefine';
|
|
|
import { RandomUtils } from '@imengyu/imengyu-utils';
|
|
|
+import Button, { type ButtonType } from '../basic/Button.vue';
|
|
|
|
|
|
const themeContext = useTheme();
|
|
|
|
|
|
+export interface SwipeRowAction {
|
|
|
+ /**
|
|
|
+ * 操作按钮的文本
|
|
|
+ */
|
|
|
+ text: string,
|
|
|
+ /**
|
|
|
+ * 操作按钮的类型
|
|
|
+ */
|
|
|
+ type: ButtonType,
|
|
|
+ /**
|
|
|
+ * 操作按钮的点击事件
|
|
|
+ */
|
|
|
+ onClick?: (e: any) => void,
|
|
|
+}
|
|
|
+
|
|
|
export interface SwipeRowProps {
|
|
|
/**
|
|
|
- * 左侧宽度
|
|
|
+ * 手动设置左侧宽度,单位为px
|
|
|
*/
|
|
|
- leftWidth?: number,
|
|
|
+ leftWidth?: number|undefined,
|
|
|
/**
|
|
|
- * 右侧宽度
|
|
|
+ * 左侧操作按钮
|
|
|
*/
|
|
|
- rightWidth?: number,
|
|
|
+ leftActions?: SwipeRowAction[],
|
|
|
+ /**
|
|
|
+ * 手动设置右侧宽度,单位为px
|
|
|
+ */
|
|
|
+ rightWidth?: number|undefined,
|
|
|
+ /**
|
|
|
+ * 右侧操作按钮
|
|
|
+ */
|
|
|
+ rightActions?: SwipeRowAction[],
|
|
|
/**
|
|
|
* 是否禁用
|
|
|
*/
|
|
|
@@ -77,6 +119,31 @@ const props = withDefaults(defineProps<SwipeRowProps>(), {
|
|
|
const themeStyles = themeContext.useThemeStyles({
|
|
|
});
|
|
|
|
|
|
+const instance = getCurrentInstance();
|
|
|
+const measuredLeftWidth = ref(0);
|
|
|
+const measuredRightWidth = ref(0);
|
|
|
+
|
|
|
+function measureWidth() {
|
|
|
+ function measuredEle(id: string) {
|
|
|
+ uni.createSelectorQuery()
|
|
|
+ .in(instance)
|
|
|
+ .select(`#${id}`)
|
|
|
+ .boundingClientRect()
|
|
|
+ .exec((res) => {
|
|
|
+ if (res[0]) {
|
|
|
+ if (id === 'left')
|
|
|
+ measuredLeftWidth.value = res[0].width;
|
|
|
+ else if (id === 'right')
|
|
|
+ measuredRightWidth.value = res[0].width;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ nextTick(() => {
|
|
|
+ measuredEle('left');
|
|
|
+ measuredEle('right');
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
const currentAnim = ref(false);
|
|
|
const currentOffset = ref(0);
|
|
|
|
|
|
@@ -86,15 +153,16 @@ let pressed = false;
|
|
|
let startOffset = 0;
|
|
|
let lastMovedSize = 0;
|
|
|
|
|
|
+const leftWidth = computed(() => props.leftWidth && props.leftWidth > 0 ? props.leftWidth : measuredLeftWidth.value);
|
|
|
+const rightWidth = computed(() => props.rightWidth && props.rightWidth > 0 ? props.rightWidth : measuredRightWidth.value);
|
|
|
+
|
|
|
function handleDrag(x: number) {
|
|
|
const movedSize = x - startX;
|
|
|
lastMovedSize = movedSize;
|
|
|
if (movedSize > 0) {
|
|
|
- if (props.leftWidth > 0)
|
|
|
- currentOffset.value = Math.min(startOffset + movedSize, props.leftWidth);
|
|
|
+ currentOffset.value = Math.min(startOffset + movedSize, leftWidth.value);
|
|
|
} else {
|
|
|
- if (props.rightWidth > 0)
|
|
|
- currentOffset.value = Math.max(startOffset + movedSize, -props.rightWidth);
|
|
|
+ currentOffset.value = Math.max(startOffset + movedSize, -rightWidth.value);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -121,10 +189,10 @@ function handleTouchEnd(e: any) {
|
|
|
currentAnim.value = true;
|
|
|
nextTick(() => {
|
|
|
if (Math.abs(lastMovedSize) > 10) {
|
|
|
- if (currentOffset.value > props.leftWidth / 2)
|
|
|
- currentOffset.value = props.leftWidth;
|
|
|
- else if (currentOffset.value < -props.rightWidth / 2)
|
|
|
- currentOffset.value = -props.rightWidth;
|
|
|
+ if (currentOffset.value > leftWidth.value / 2)
|
|
|
+ currentOffset.value = leftWidth.value;
|
|
|
+ else if (currentOffset.value < -rightWidth.value / 2)
|
|
|
+ currentOffset.value = -rightWidth.value;
|
|
|
else
|
|
|
currentOffset.value = 0;
|
|
|
} else if (props.autoClose)
|
|
|
@@ -132,6 +200,12 @@ function handleTouchEnd(e: any) {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
+onMounted(() => {
|
|
|
+ measureWidth();
|
|
|
+});
|
|
|
+onUpdated(() => {
|
|
|
+ measureWidth();
|
|
|
+});
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss">
|