@ray-js/smart-ui
Version:
轻量、可靠的智能小程序 UI 组件库
495 lines (413 loc) • 18.3 kB
Markdown
---
category: 反馈
---
# BottomSheet 底部弹窗
### 介绍
通底的底部弹窗面板;与 `Popup` 和 `ActionSheet` 的区别在于,安全区通过内边距覆盖,适用于需要和底部无缝粘合的场景,v2.0.0 开始加入。
### 引入
```jsx
import { BottomSheet } from '@ray-js/smart-ui';
```
## 代码演示
### 基础用法
传入一个 `title` 文本,将会往上弹出现一个带标题的底部弹窗。
```jsx
import React from 'react';
import { BottomSheet, Button } from '@ray-js/smart-ui';
import { View } from '@ray-js/ray';
export default function Demo() {
const [show, setShow] = React.useState(false);
const toggleBottomSheet = React.useCallback(() => setShow(!show), [show]);
return (
<View>
<Button type="primary" onClick={toggleBottomSheet}>
弹出菜单
</Button>
<BottomSheet title="Title" show={show} onClose={toggleBottomSheet} />
</View>
);
}
```
### 自定义
通过传入子元素节点来自定义面板
```jsx
import React from 'react';
import { BottomSheet, Button } from '@ray-js/smart-ui';
import { View } from '@ray-js/ray';
export default function Demo() {
const [show, setShow] = React.useState(false);
const toggleBottomSheet = React.useCallback(() => setShow(!show), [show]);
return (
<View>
<Button type="primary" onClick={toggleBottomSheet}>
弹出菜单
</Button>
<BottomSheet show={show} title="Title" onClose={toggleBottomSheet}>
<View className="content" />
<View className="footer">
<Button type="info" block>完成</Button>
</View>
</BottomSheet>
</View>
);
}
```
```css
.content {
display: flex;
justify-content: center;
font-size: 20px;
background: var(--app-B1, #f6f7fb);
color: var(--app-B4-N1, #3d3d3d);
}
.footer {
margin: 16px 0;
}
```
### 最大高度限制
底部弹窗默认最大高度不允许超过屏幕的 50%,但可以通过 `--bottom-sheet-max-height` 自定义最大高度,在 v2.5.0 版本及之后内容触发最大高度组件内部会自动滚动!
```jsx
import React from 'react';
import { BottomSheet, Button } from '@ray-js/smart-ui';
import { View } from '@ray-js/ray';
export default function Demo() {
const [show, setShow] = React.useState(false);
const toggleBottomSheet = React.useCallback(() => setShow(!show), [show]);
return (
<View>
<Button type="primary" onClick={toggleBottomSheet}>
弹出菜单
</Button>
<BottomSheet show={show} title="Title" onClose={toggleBottomSheet}>
<View style={{ backgroundColor: 'red', height: '100px' }} />
<View style={{ backgroundColor: 'blue', height: '100px' }} />
<View style={{ backgroundColor: 'black', height: '100px' }} />
<View style={{ backgroundColor: 'yellow', height: '100px' }} />
<View style={{ backgroundColor: 'pink', height: '100px' }} />
</BottomSheet>
</View>
);
}
```
### 固定高度 `v2.5.0`
`contentHeight` 可以设置内容区域的高度;当设置了 `contentHeight` 后, 组件的最大高度就会失效,可以自定义在内部书写内容。
```jsx
import React from 'react';
import { BottomSheet, Button } from '@ray-js/smart-ui';
import { View, ScrollView } from '@ray-js/ray';
export default function Demo() {
const [show, setShow] = React.useState(false);
const toggleBottomSheet = React.useCallback(() => setShow(!show), [show]);
return (
<View>
<Button type="primary" onClick={toggleBottomSheet}>
弹出菜单
</Button>
<BottomSheet
show={show}
title="Title"
content-height="500px"
onClose={toggleBottomSheet}
>
<ScrollView scroll-y style={{ height: '300px' }}>
<View style={{ backgroundColor: 'red', height: '100px' }} />
<View style={{ backgroundColor: 'blue', height: '100px' }} />
<View style={{ backgroundColor: 'black', height: '100px' }} />
<View style={{ backgroundColor: 'yellow', height: '100px' }} />
<View style={{ backgroundColor: 'pink', height: '100px' }} />
</ScrollView>
<View style={{ backgroundColor: 'white', height: '100px' }} />
<View style={{ backgroundColor: 'orange', height: '100px' }} />
</BottomSheet>
</View>
);
}
```
### 使用插槽插入标题 `v2.6.1`
```jsx
import React from 'react';
import { BottomSheet, Button } from '@ray-js/smart-ui';
import { View } from '@ray-js/ray';
export default function Demo() {
const [show, setShow] = React.useState(false);
const toggleBottomSheet = React.useCallback(() => setShow(!show), [show]);
return (
<View>
<Button type="primary" onClick={toggleBottomSheet}>
弹出菜单
</Button>
<BottomSheet
show={show}
slot={{
title: <View>Slot Title</View>
}}
onClose={toggleBottomSheet}
>
<View style={{ backgroundColor: 'orange', height: '100px' }} />
</BottomSheet>
</View>
);
}
```
### 可拖拽 `v2.7.2`
通过设置 `draggable` 属性,可以让底部弹窗支持拖拽调整高度。
```jsx
import React, { useEffect, useState } from 'react';
import { BottomSheet, Button } from '@ray-js/smart-ui';
import { View, getSystemInfoSync } from '@ray-js/ray';
export default function Demo() {
const [show, setShow] = React.useState(false);
const [closeDragHeight, setCloseDragHeight] = useState(0);
useEffect(() => {
const systemInfo = getSystemInfoSync();
setCloseDragHeight(systemInfo.windowHeight * 0.4);
}, []);
const toggleBottomSheet = React.useCallback(() => setShow(!show), [show]);
return (
<View>
<Button type="primary" onClick={toggleBottomSheet}>
弹出菜单
</Button>
<BottomSheet
show={show}
draggable
closeDragHeight={closeDragHeight}
midDragHeight={300}
onClose={toggleBottomSheet}
>
<View style={{ backgroundColor: 'red', height: '300px' }} />
</BottomSheet>
</View>
);
}
```
### 设置拖拽范围 `v2.7.2`
通过设置 `minDragHeight`、`maxDragHeight`、`midDragHeight` 和 `closeDragHeight` 来控制拖拽的范围。
```jsx
import React from 'react';
import { BottomSheet, Button } from '@ray-js/smart-ui';
import { View } from '@ray-js/ray';
export default function Demo() {
const [show, setShow] = React.useState(false);
const toggleBottomSheet = React.useCallback(() => setShow(!show), [show]);
return (
<View>
<Button type="primary" onClick={toggleBottomSheet}>
弹出菜单
</Button>
<BottomSheet
show={show}
draggable
midDragHeight={300}
minDragHeight={300}
maxDragHeight={300}
closeDragHeight={300}
onClose={toggleBottomSheet}
>
<View style={{ backgroundColor: 'red', height: '300px' }} />
</BottomSheet>
</View>
);
}
```
### 带标题的拖拽 `v2.7.2`
拖拽功能可以与标题一起使用。
```jsx
import React from 'react';
import { BottomSheet, Button } from '@ray-js/smart-ui';
import { View } from '@ray-js/ray';
export default function Demo() {
const [show, setShow] = React.useState(false);
const toggleBottomSheet = React.useCallback(() => setShow(!show), [show]);
return (
<View>
<Button type="primary" onClick={toggleBottomSheet}>
弹出菜单
</Button>
<BottomSheet
title="带标题的拖拽"
show={show}
draggable
midDragHeight={300}
minDragHeight={300}
maxDragHeight={300}
closeDragHeight={300}
onClose={toggleBottomSheet}
>
<View style={{ backgroundColor: 'red', height: '300px' }} />
</BottomSheet>
</View>
);
}
```
### 监听拖拽位置 `v2.7.2`
通过 `onDragPosition` 事件可以监听拖拽结束时的面板位置。
```jsx
import React, { useState } from 'react';
import { BottomSheet, Button } from '@ray-js/smart-ui';
import { View, Text } from '@ray-js/ray';
export default function Demo() {
const [show, setShow] = React.useState(false);
const [dragPosition, setDragPosition] = useState<'max' | 'mid' | 'min' | ''>('');
const toggleBottomSheet = React.useCallback(() => setShow(!show), [show]);
const onDragPosition = React.useCallback((e: any) => {
const position = e.detail; // 'max' | 'mid' | 'min'
setDragPosition(position);
}, []);
const getDragPositionText = () => {
const positionMap = {
max: '最大',
mid: '中间',
min: '最小',
};
return positionMap[dragPosition as keyof typeof positionMap] || dragPosition;
};
return (
<View>
<Button type="primary" onClick={toggleBottomSheet}>
弹出菜单
</Button>
<BottomSheet
show={show}
draggable
midDragHeight={300}
minDragHeight={100}
maxDragHeight={600}
onDragPosition={onDragPosition}
onClose={toggleBottomSheet}
>
{dragPosition && (
<View
style={{
marginTop: '16px',
padding: '12px',
backgroundColor: '#f0f0f0',
borderRadius: '4px',
}}
>
<Text>当前面板位置: {getDragPositionText()}</Text>
</View>
)}
</BottomSheet>
</View>
);
}
```
### 锁定最大拖拽高度 `v2.9.0`
通过设置 `lockMaxDrag` 属性为 `true`,可以锁定最大拖拽高度,拖拽过程中面板高度不会超过 `maxDragHeight`。
```jsx
import React from 'react';
import { BottomSheet, Button } from '@ray-js/smart-ui';
import { View } from '@ray-js/ray';
export default function Demo() {
const [show, setShow] = React.useState(false);
const toggleBottomSheet = React.useCallback(() => setShow(!show), [show]);
return (
<View>
<Button type="primary" onClick={toggleBottomSheet}>
弹出菜单
</Button>
<BottomSheet
show={show}
draggable
lockMaxDrag
midDragHeight={300}
minDragHeight={100}
maxDragHeight={500}
closeDragHeight={200}
onClose={toggleBottomSheet}
>
<View style={{ backgroundColor: 'red', height: '300px' }} />
</BottomSheet>
</View>
);
}
```
## API
### Props
| 参数 | 说明 | 类型 | 默认值 |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | --------------------------------------- |
| closeIconAriaLabel `v2.13.0` | 标题关闭按钮的无障碍读屏文案,透传至内部 `smart-icon` 的 `aria-label`;不传时关闭图标仍为 `button` 角色(由 `aria-role` 声明),便于业务按需传入多语言 | _string_ | - |
| closeDragHeight `v2.7.2` | 拖拽关闭时的临界高度,低于该高度将自动关闭 | _number_ | `windowHeight * 0.4` |
| closeOnClickOverlay | 点击遮罩是否关闭菜单 | _boolean_ | `true` |
| contentHeight `v2.5.0` | 内容区域高度,当设置此值时,组件的 max-height 将会失效。当设置 draggable 时此值无效。 | _number \| string_ | `false` |
| draggable `v2.7.2` | 是否支持拖拽,可用于实现拖拽调整面板高度 | _boolean_ | `false` |
| iconColor | 标题中关闭按钮的颜色 | _string_ | `--app-B4-N3` \|\| `rgba(0, 0, 0, 0.5)` |
| iconSize | 标题中关闭按钮的大小 | _string \| number_ | `24` |
| lockMaxDrag `v2.9.0` | 是否锁定最大拖拽高度,设置为 `true` 时,拖拽过程中面板高度不会超过 `max-drag-height` | _boolean_ | `false` |
| lockScroll `v2.9.0` | 是否锁定背景滚动 | _boolean_ | `true` |
| maxDragHeight `v2.7.2` | 拖拽时允许的最大高度 | _number_ | `windowHeight * 0.5` |
| maxHeight `v2.6.0` | 整个组件的最大高度 | _number \| string_ | - |
| midDragHeight `v2.7.2` | 拖拽时中间态高度 | _number_ | `windowHeight * 0.1` |
| minDragHeight `v2.7.2` | 拖拽时允许的最小高度 | _number_ | `windowHeight * 0.8` |
| nativeDisabled `v2.5.0` | 开启弹框期间是否禁用本地手势; 会在弹框开始进入动画时调用 `ty.nativeDisabled(true)`, 在弹框关闭动画结束时调用 `ty.nativeDisabled(false)` 恢复异层组件的点击能力;由于`ty.nativeDisabled` 是全局生效的,所以多个弹框组件同时打开时注意是否传 `native-disabled`属性和关闭的时机,防止 `native-disabled` 属性失效 | _boolean_ | `false` |
| overlay | 是否显示遮罩层 | _boolean_ | `true` |
| round | 是否显示圆角 | _boolean_ | `true` |
| show | 是否显示底部弹窗 | _boolean_ | `false` |
| showClose `v2.6.1` | 是否展示关闭图标。当设置 draggable 时此值无效。 | _boolean_ | `true` |
| title | 标题 | _string_ | - |
| zIndex | z-index 层级 | _number_ | `100` |
| fullCoverView `v2.11.1` | 是否使用 cover-view 包裹弹层,用于覆盖原生组件(如 map、video)时使用 | _boolean_ | `false` |
### Events
| 事件名 | 说明 | 参数 |
| --------------------------- | -------------------------------- | --------------------------------------------- |
| onAfterEnter | 遮罩进入后触发 | - |
| onAfterLeave | 遮罩离开后触发 | - |
| onBeforeEnter | 遮罩进入前触发 | - |
| onBeforeLeave | 遮罩离开前触发 | - |
| onClickOverlay | 点击遮罩层时触发 | - |
| onClose | 点击关闭按钮时触发 | - |
| onDragPosition `v2.7.2` | 拖拽结束时触发,返回当前面板位置 | _event.detail_: `'max'` \| `'mid'` \| `'min'` |
| onEnter | 遮罩进入中触发 | - |
| onLeave | 遮罩离开中触发 | - |
### Slot
| 名称 | 说明 |
| -------------- | -------- |
| - | 内容 |
| title `v2.6.1` | 标题插槽 |
### 外部样式类
| 类名 | 说明 |
| ------------ | ------------ |
| customClass | 根节点样式类 |
### 样式变量
组件提供了下列 CSS 变量,可用于自定义样式,使用方法请参考 [ConfigProvider 组件](/material/smartui?comId=config-provider)。
| 名称 | 默认值 | 描述 |
| -------------------------------------------------- | ------------------------------------ | -------------------------- |
| --bottom-sheet-dragger-node-background `v2.7.2` | _rgba(0, 0, 0, 0.3)_ | 拖拽手柄的背景色 |
| --bottom-sheet-dragger-node-border-radius `v2.7.2` | _2px_ | 拖拽手柄的圆角 |
| --bottom-sheet-dragger-node-height `v2.7.2` | _4px_ | 拖拽手柄的高度 |
| --bottom-sheet-dragger-node-width `v2.7.2` | _30px_ | 拖拽手柄的宽度 |
| --bottom-sheet-dragger-padding `v2.7.2` | _8px 0_ | 拖拽手柄区域的内边距 |
| --bottom-sheet-font-color | _var(--app-B4-N1, rgba(0, 0, 0, 1))_ | 底部弹窗的文字颜色 |
| --bottom-sheet-header-color | _var(--app-B4-N1, rgba(0, 0, 0, 1))_ | 底部弹窗的头部文字颜色 |
| --bottom-sheet-header-font-size | _17px_ | 底部弹窗的头部文字大小 |
| --bottom-sheet-header-font-weight | _600_ | 底部弹窗的头部字重 |
| --bottom-sheet-header-height | _56px_ | 底部弹窗的头部高度 |
| --bottom-sheet-header-padding `v2.5.0` | _0 16px_ | 底部弹窗头部的内边距 |
| --bottom-sheet-icon-margin | _16px 16px 0 0_ | 底部弹窗的关闭 icon 外边距 |
| --bottom-sheet-max-height | _50%_ | 底部弹窗的最大高度 |
| --bottom-sheet-min-height | _auto_ | 底部弹窗的最小高度 |
| --bottom-sheet-padding | _0 16px_ | 底部弹窗内容区域的内边距 |
| --bottom-sheet-width | _100%_ | 底部弹窗的宽度 |
| --popup-background-color | _var(--app-B4, #ffffff)_ | 弹框背景色 |
## 常见问题
### 组件内容高度到一定程度无法增加
BottomSheet 组件内部有 max-height 限制组件的最大高度需要覆盖组件的样式才可以实现例如:
```css
.my-bottom-sheet {
--bottom-sheet-max-height: 100%;
}
```
在 v2.5.0 及之后版本可以设置 `contentHeight` 设置内容区域的高度,此时 max-height 将会失效
### 组件内容过高后在真机上无法滚动问题
1. 可以升级到最新的 v2.5.0 修复了此问题, 过高后会自动滚动
2. 或者在内容区域套一个 ScrollView 组件,下面为 max-height 为 50% 为例,其中 `env(safe-area-inset-bottom)` 为底部安全距离
```jsx
<BottomSheet show>
<ScrollView style={{ height: 'calc(50vh - 56px - env(safe-area-inset-bottom))'}} scrollY>
<View style={{ height: 2000 }}><View>
<ScrollView>
</BottomSheet>
```
### 组件内容中绝对定位在底部的内容在真机上会被遮挡
升级到最新的 v2.5.0 后,可以参考 固定高度 例子,将需要绝对定位的内容放置在底部,将其余内容用 ScrollView 包裹