feat(FloatingPanel): add draggable prop (#13773)
Co-authored-by: Junwei Wang <junwei.wang@algento.com>
This commit is contained in:
@@ -29,6 +29,7 @@ export const floatingPanelProps = {
|
|||||||
anchors: makeArrayProp<number>(),
|
anchors: makeArrayProp<number>(),
|
||||||
duration: makeNumericProp(0.3),
|
duration: makeNumericProp(0.3),
|
||||||
magnetic: truthProp,
|
magnetic: truthProp,
|
||||||
|
draggable: truthProp,
|
||||||
contentDraggable: truthProp,
|
contentDraggable: truthProp,
|
||||||
lockScroll: Boolean,
|
lockScroll: Boolean,
|
||||||
safeAreaInsetBottom: truthProp,
|
safeAreaInsetBottom: truthProp,
|
||||||
@@ -97,6 +98,8 @@ export default defineComponent({
|
|||||||
const touch = useTouch();
|
const touch = useTouch();
|
||||||
|
|
||||||
const onTouchstart = (e: TouchEvent) => {
|
const onTouchstart = (e: TouchEvent) => {
|
||||||
|
if (!props.draggable) return;
|
||||||
|
|
||||||
touch.start(e);
|
touch.start(e);
|
||||||
dragging.value = true;
|
dragging.value = true;
|
||||||
startY = -height.value;
|
startY = -height.value;
|
||||||
@@ -104,6 +107,8 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onTouchmove = (e: TouchEvent) => {
|
const onTouchmove = (e: TouchEvent) => {
|
||||||
|
if (!props.draggable) return;
|
||||||
|
|
||||||
touch.move(e);
|
touch.move(e);
|
||||||
|
|
||||||
const target = e.target as Element;
|
const target = e.target as Element;
|
||||||
@@ -130,8 +135,17 @@ export default defineComponent({
|
|||||||
|
|
||||||
const onTouchend = () => {
|
const onTouchend = () => {
|
||||||
maxScroll = -1;
|
maxScroll = -1;
|
||||||
|
|
||||||
|
if (!dragging.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
dragging.value = false;
|
dragging.value = false;
|
||||||
|
|
||||||
|
if (!props.draggable) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (props.magnetic) {
|
if (props.magnetic) {
|
||||||
height.value = closest(anchors.value, height.value);
|
height.value = closest(anchors.value, height.value);
|
||||||
} else {
|
} else {
|
||||||
@@ -162,6 +176,10 @@ export default defineComponent({
|
|||||||
return slots.header();
|
return slots.header();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!props.draggable) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class={bem('header')}>
|
<div class={bem('header')}>
|
||||||
<div class={bem('header-bar')} />
|
<div class={bem('header-bar')} />
|
||||||
|
|||||||
@@ -93,6 +93,18 @@ When `magnetic` is set to `false`, the panel will not automatically snap to anch
|
|||||||
</van-floating-panel>
|
</van-floating-panel>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Disable Dragging
|
||||||
|
|
||||||
|
You can disable the dragging functionality of the panel through the `draggable` attribute. When set to `false`, the panel will not be draggable, and the header drag bar will be hidden.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-floating-panel :draggable="false">
|
||||||
|
<div style="text-align: center; padding: 15px">
|
||||||
|
<p>This panel cannot be dragged</p>
|
||||||
|
</div>
|
||||||
|
</van-floating-panel>
|
||||||
|
```
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
### Props
|
### Props
|
||||||
@@ -104,6 +116,7 @@ When `magnetic` is set to `false`, the panel will not automatically snap to anch
|
|||||||
| duration | Transition duration, unit second | _number \| string_ | `0.3` |
|
| duration | Transition duration, unit second | _number \| string_ | `0.3` |
|
||||||
| magnetic | Whether to enable magnetic adsorption to anchors. When disabled, panel can stop at any position within the anchor boundaries | _boolean_ | `true` |
|
| magnetic | Whether to enable magnetic adsorption to anchors. When disabled, panel can stop at any position within the anchor boundaries | _boolean_ | `true` |
|
||||||
| content-draggable | Allow dragging content | _boolean_ | `true` |
|
| content-draggable | Allow dragging content | _boolean_ | `true` |
|
||||||
|
| draggable | Whether to allow dragging the panel. When disabled, the header drag bar will be hidden | _boolean_ | `true` |
|
||||||
| lock-scroll `v4.6.4` | When not dragging, Whether to lock background scroll | _boolean_ | `false` |
|
| lock-scroll `v4.6.4` | When not dragging, Whether to lock background scroll | _boolean_ | `false` |
|
||||||
| safe-area-inset-bottom | Whether to enable bottom safe area adaptation | _boolean_ | `true` |
|
| safe-area-inset-bottom | Whether to enable bottom safe area adaptation | _boolean_ | `true` |
|
||||||
|
|
||||||
|
|||||||
@@ -93,6 +93,18 @@ export default {
|
|||||||
</van-floating-panel>
|
</van-floating-panel>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 禁用拖拽
|
||||||
|
|
||||||
|
你可以通过 `draggable` 属性来禁用面板的拖拽功能。当设置为 `false` 时,面板将不可拖拽,同时头部拖拽栏也会被隐藏。
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-floating-panel :draggable="false">
|
||||||
|
<div style="text-align: center; padding: 15px">
|
||||||
|
<p>该面板不可拖拽</p>
|
||||||
|
</div>
|
||||||
|
</van-floating-panel>
|
||||||
|
```
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
### Props
|
### Props
|
||||||
@@ -104,6 +116,7 @@ export default {
|
|||||||
| duration | 动画时长,单位秒,设置为 0 可以禁用动画 | _number \| string_ | `0.3` |
|
| duration | 动画时长,单位秒,设置为 0 可以禁用动画 | _number \| string_ | `0.3` |
|
||||||
| magnetic | 是否启用磁力吸附到锚点。禁用后面板可在锚点边界范围内任意位置停留 | _boolean_ | `true` |
|
| magnetic | 是否启用磁力吸附到锚点。禁用后面板可在锚点边界范围内任意位置停留 | _boolean_ | `true` |
|
||||||
| content-draggable | 允许拖拽内容容器 | _boolean_ | `true` |
|
| content-draggable | 允许拖拽内容容器 | _boolean_ | `true` |
|
||||||
|
| draggable | 是否允许拖拽面板。禁用后头部拖拽栏会被隐藏 | _boolean_ | `true` |
|
||||||
| lock-scroll `v4.6.4` | 当不拖拽时,是否锁定背景滚动 | _boolean_ | `false` |
|
| lock-scroll `v4.6.4` | 当不拖拽时,是否锁定背景滚动 | _boolean_ | `false` |
|
||||||
| safe-area-inset-bottom | 是否开启[底部安全区适配](#/zh-CN/advanced-usage#di-bu-an-quan-qu-gua-pei) | _boolean_ | `true` |
|
| safe-area-inset-bottom | 是否开启[底部安全区适配](#/zh-CN/advanced-usage#di-bu-an-quan-qu-gua-pei) | _boolean_ | `true` |
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ const t = useTranslate({
|
|||||||
customAnchors: '自定义锚点',
|
customAnchors: '自定义锚点',
|
||||||
headDragOnly: '仅头部拖拽',
|
headDragOnly: '仅头部拖拽',
|
||||||
disableMagnetic: '禁用吸附',
|
disableMagnetic: '禁用吸附',
|
||||||
|
disableDragging: '禁用拖拽',
|
||||||
|
panelUnDrag: '该面板不可拖拽',
|
||||||
panelShowHeight: '面板显示高度',
|
panelShowHeight: '面板显示高度',
|
||||||
contentUnDrag: '内容不可拖拽',
|
contentUnDrag: '内容不可拖拽',
|
||||||
magneticDisabled: '已禁用磁力吸附,可在边界内任意停留',
|
magneticDisabled: '已禁用磁力吸附,可在边界内任意停留',
|
||||||
@@ -23,6 +25,8 @@ const t = useTranslate({
|
|||||||
customAnchors: 'Custom Anchors',
|
customAnchors: 'Custom Anchors',
|
||||||
headDragOnly: 'Head Drag Only',
|
headDragOnly: 'Head Drag Only',
|
||||||
disableMagnetic: 'Disable Magnetic',
|
disableMagnetic: 'Disable Magnetic',
|
||||||
|
disableDragging: 'Disable Dragging',
|
||||||
|
panelUnDrag: 'This panel cannot be dragged',
|
||||||
panelShowHeight: 'Panel Show Height',
|
panelShowHeight: 'Panel Show Height',
|
||||||
contentUnDrag: 'Content cannot be dragged',
|
contentUnDrag: 'Content cannot be dragged',
|
||||||
magneticDisabled: 'Magnetic disabled, free positioning within boundaries',
|
magneticDisabled: 'Magnetic disabled, free positioning within boundaries',
|
||||||
@@ -76,5 +80,13 @@ const height = ref(anchors[0]);
|
|||||||
</div>
|
</div>
|
||||||
</van-floating-panel>
|
</van-floating-panel>
|
||||||
</van-tab>
|
</van-tab>
|
||||||
|
|
||||||
|
<van-tab :title="t('disableDragging')">
|
||||||
|
<van-floating-panel :draggable="false">
|
||||||
|
<div style="text-align: center; padding: 15px">
|
||||||
|
<p>{{ t('panelUnDrag') }}</p>
|
||||||
|
</div>
|
||||||
|
</van-floating-panel>
|
||||||
|
</van-tab>
|
||||||
</van-tabs>
|
</van-tabs>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -56,6 +56,16 @@ exports[`should render demo and match snapshot 1`] = `
|
|||||||
style="display:none;"
|
style="display:none;"
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
id="van-tab"
|
||||||
|
role="tabpanel"
|
||||||
|
class="van-tab__panel"
|
||||||
|
tabindex="-1"
|
||||||
|
aria-labelledby="van-tabs-4"
|
||||||
|
data-allow-mismatch="attribute"
|
||||||
|
style="display:none;"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -60,6 +60,19 @@ exports[`should render demo and match snapshot 1`] = `
|
|||||||
Disable Magnetic
|
Disable Magnetic
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
id="van-tabs-4"
|
||||||
|
role="tab"
|
||||||
|
class="van-tab van-tab--line van-tab--grow"
|
||||||
|
tabindex="-1"
|
||||||
|
aria-selected="false"
|
||||||
|
aria-controls="van-tab"
|
||||||
|
data-allow-mismatch="attribute"
|
||||||
|
>
|
||||||
|
<span class="van-tab__text">
|
||||||
|
Disable Dragging
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
class="van-tabs__line"
|
class="van-tabs__line"
|
||||||
style="transform: translateX(50px) translateX(-50%);"
|
style="transform: translateX(50px) translateX(-50%);"
|
||||||
@@ -306,6 +319,16 @@ exports[`should render demo and match snapshot 1`] = `
|
|||||||
style="display: none;"
|
style="display: none;"
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
id="van-tab"
|
||||||
|
role="tabpanel"
|
||||||
|
class="van-tab__panel"
|
||||||
|
tabindex="-1"
|
||||||
|
aria-labelledby="van-tabs-4"
|
||||||
|
data-allow-mismatch="attribute"
|
||||||
|
style="display: none;"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -189,3 +189,38 @@ test('should add padding bottom to content when panel is not fully expanded', as
|
|||||||
await wrapper.setProps({ height: 400 });
|
await wrapper.setProps({ height: 400 });
|
||||||
expect(content.style.paddingBottom).toBe('0px');
|
expect(content.style.paddingBottom).toBe('0px');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should not allow dragging when draggable is false', async () => {
|
||||||
|
const wrapper = mount({
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<FloatingPanel
|
||||||
|
anchors={[100, 200, 400]}
|
||||||
|
draggable={false}
|
||||||
|
onHeightChange={(h) => this.$emit('change', h)}
|
||||||
|
>
|
||||||
|
Content
|
||||||
|
</FloatingPanel>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper.find('.van-floating-panel__header').exists()).toBe(false);
|
||||||
|
|
||||||
|
await triggerDrag(wrapper.find('.van-floating-panel__content'), 0, -199);
|
||||||
|
await later();
|
||||||
|
expect(wrapper.emitted('change')).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should render header slot even when draggable is false', () => {
|
||||||
|
const wrapper = mount(FloatingPanel, {
|
||||||
|
props: {
|
||||||
|
draggable: false,
|
||||||
|
},
|
||||||
|
slots: {
|
||||||
|
header: () => 'Custom Header',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper.html()).toContain('Custom Header');
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user