@ray-js/smart-ui
Version:
轻量、可靠的智能小程序 UI 组件库
613 lines (521 loc) • 20.1 kB
Markdown
---
category: 反馈
---
# ActionSheet 动作面板
### 介绍
底部弹起的模态面板,包含与当前情境相关的多个选项。
### 引入
```jsx
import { ActionSheet } from '@ray-js/smart-ui';
```
## 代码演示
### 基础用法
需要传入一个`actions`的数组,数组的每一项是一个对象,对象属性见文档下方表格。
```jsx
import React from 'react';
import { ActionSheet, Button } from '@ray-js/smart-ui';
import { View } from '@ray-js/ray';
export default function Demo() {
const [show, setShow] = React.useState(false);
const [actions, setActions] = React.useState([
{ id: 0, name: 'Action', checked: true },
{ id: 1, name: 'Action', checked: false },
{ id: 2, name: 'Action', checked: false },
{ id: 3, name: 'Action', checked: false },
{ id: 4, name: 'Action', checked: false },
{ id: 5, name: 'Action', checked: false },
{ id: 6, name: 'Action', checked: false },
{ id: 7, name: 'Action', checked: false },
]);
const onCancel = () => setShow(false);
const onClose = () => console.log('close');
const onSelect = evt => {
const { id } = evt.detail;
const newActions = actions.map(item => {
if (item.id === id) return { ...item, checked: true };
return { ...item, checked: false };
});
setActions(newActions);
};
return (
<View>
<ActionSheet
show={show}
title="Title"
cancelText="取消"
actions={actions}
onClose={onClose}
onSelect={onSelect}
onCancel={onCancel}
/>
<Button onClick={() => setShow(true)}>点击展示</Button>
</View>
);
}
```
### 无选中列表
设置`actions[idx].checked`属性为`false`后,可以展示无选中状态的列表。
```jsx
import React from 'react';
import { ActionSheet, Button } from '@ray-js/smart-ui';
import { View } from '@ray-js/ray';
export default function Demo() {
const actions = [{ name: 'Action' }, { name: 'Action' }, { name: 'Action', subname: '描述信息' }];
const [show, setShow] = React.useState(false);
return (
<View>
<ActionSheet
show={show}
actions={actions}
title="Title"
cancelText="取消"
onCancel={() => setShow(false)}
/>
<Button onClick={() => setShow(true)}>点击展示</Button>
</View>
);
}
```
### 选项状态
选项可以设置为加载状态或禁用状态。
```jsx
import React from 'react';
import { ActionSheet, Button } from '@ray-js/smart-ui';
import { View } from '@ray-js/ray';
export default function Demo() {
const actions = [
{ name: '着色选项', color: '#ee0a24' },
{ loading: true },
{ name: '禁用选项', disabled: true },
];
const [show, setShow] = React.useState(false);
return (
<View>
<ActionSheet
show={show}
actions={actions}
cancelText="取消"
confirmText="确认"
onCancel={() => setShow(false)}
onClose={() => setShow(false)}
onConfirm={() => setShow(false)}
/>
<Button onClick={() => setShow(true)}>点击展示</Button>
</View>
);
}
```
### 展示确认按钮
设置`cancelText`、`confirmText`属性后,会在底部展示取消或确认按钮,点击后关闭当前菜单。
```jsx
import React from 'react';
import { ActionSheet, Button } from '@ray-js/smart-ui';
import { View } from '@ray-js/ray';
export default function Demo() {
const [show, setShow] = React.useState(false);
const actions = [{ name: 'Action' }, { name: 'Action' }, { name: 'Action' }];
return (
<View>
<ActionSheet
show={show}
actions={actions}
cancelText="取消"
confirmText="确认"
onCancel={() => setShow(false)}
onClose={() => setShow(false)}
onConfirm={() => setShow(false)}
/>
<Button onClick={() => setShow(true)}>点击展示</Button>
</View>
);
}
```
### 展示描述信息
设置`description`属性后,会在选项上方显示描述信息。
```jsx
import React from 'react';
import { ActionSheet, Button } from '@ray-js/smart-ui';
import { View } from '@ray-js/ray';
export default function Demo() {
const [show, setShow] = React.useState(false);
const actions = [{ name: 'Action' }, { name: 'Action' }, { name: 'Action' }];
return (
<View>
<ActionSheet
show={show}
actions={actions}
description="这是一段描述信息"
onCancel={() => setShow(false)}
onClose={() => setShow(false)}
onConfirm={() => setShow(false)}
/>
<Button onClick={() => setShow(true)}>点击展示</Button>
</View>
);
}
```
### 自定义
通过设置`title`属性展示标题栏,同时可以使用插槽自定义菜单内容。
```jsx
import React from 'react';
import { ActionSheet, Button } from '@ray-js/smart-ui';
import { View } from '@ray-js/ray';
export default function Demo() {
const [show, setShow] = React.useState(false);
return (
<View>
<ActionSheet
show={show}
title="标题"
onCancel={() => setShow(false)}
onClose={() => setShow(false)}
onConfirm={() => setShow(false)}
>
<View>内容</View>
</ActionSheet>
<Button onClick={() => setShow(true)}>点击展示</Button>
</View>
);
}
```
### 自定义数值
内部嵌套 Slider 组件使用,注意 Slider 组件的渲染时机要在弹框完全进入后,否则会影响其定位。
```jsx
import React from 'react';
import { ActionSheet, Button, Slider } from '@ray-js/smart-ui';
import { View, Text } from '@ray-js/ray';
import { useDebounce } from 'ahooks';
import styles from './index.module.less';
export default function Demo() {
const [show, setShow] = React.useState(false);
const [ready, setReady] = React.useState(false);
const [currentNumber, setCurrentNumber] = React.useState(100);
const currentNumberForSlider = useDebounce(currentNumber, { wait: 500 });
const onChange = React.useCallback(value => {
setCurrentNumber(value);
}, []);
return (
<View>
<ActionSheet
show={show}
title="标题"
onCancel={() => setShow(false)}
onClose={() => setShow(false)}
onConfirm={() => setShow(false)}
onAfterEnter={() => setReady(true)}
onAfterLeave={() => setReady(false)}
>
<View className={styles['content-number']}>
<View className={styles['demo-header']}>
<Text className={styles['demo-text']}>{`${currentNumber}%`}</Text>
</View>
<View className={styles['demo-slider']}>
{ready && (
<Slider
minTrackRadius="8px"
minTrackHeight="45px"
maxTrackRadius="8px"
maxTrackHeight="45px"
value={currentNumberForSlider}
onChange={onChange}
thumbWidth={15}
thumbHeight={50}
thumbRadius={2}
thumbStyle={{
background: '#BBC5D4',
border: '2px solid #FFFFFF',
boxShadow: '0px 0px 2px 0px rgba(0, 0, 0, 0.5)',
}}
/>
)}
</View>
</View>
</ActionSheet>
<Button onClick={() => setShow(true)}>点击展示</Button>
</View>
);
}
```
index.module.less
```css
.content-number {
padding: 10px 39px;
background: var(--app-B1, #f6f7fb);
text-align: center;
color: var(--app-B4-N1, #000);
}
.demo-header {
padding: 10px 39px;
}
.demo-text {
font-size: 40px;
font-weight: 600;
line-height: 46px;
}
.demo-slider {
margin: 23px 0;
min-height: 45px;
}
```
### 自定义滚动
```jsx
import React from 'react';
import { ActionSheet, Button, DateTimePicker } from '@ray-js/smart-ui';
import { View } from '@ray-js/ray';
export default function Demo() {
const [show, setShow] = React.useState(false);
const [currentDate, setCurrentDate] = React.useState(new Date(2018, 0, 1));
const onInput = React.useCallback(event => {
const { detail } = event;
const date = new Date(detail);
setCurrentDate(date);
}, []);
return (
<View>
<ActionSheet
show={show}
title="标题"
onCancel={() => setShow(false)}
onClose={() => setShow(false)}
onConfirm={() => setShow(false)}
>
<DateTimePicker
showToolbar={false}
type="date"
minDate={new Date(2018, 0, 1).getTime()}
value={currentDate}
onInput={onInput}
/>
</ActionSheet>
<Button onClick={() => setShow(true)}>点击展示</Button>
</View>
);
}
```
### 自定义双列选择器 `v2.6.0`
当 `useTitleSlot` 为 `true` 时,可以使用插槽自定义标题内容,支持复杂的双选择器场景。
```jsx
import React from 'react';
import { ActionSheet, Button, DateTimePicker, Picker, SmartEventHandler, SmartPickerBaseEventDetail } from '@ray-js/smart-ui';
import { View } from '@ray-js/ray';
import styles from './index.module.less';
export default function Demo() {
const [show, setShow] = React.useState(false);
const [current12Date, setCurrent12Date] = useState('12:00');
const [tempColumnIdx, setTempColumnIdx] = useState(3);
const onCurrent12DateInput: SmartEventHandler<string> = event => {
setCurrent12Date(event.detail);
};
const onTempColumnChange: SmartEventHandler<SmartPickerBaseEventDetail> = event => {
const { index } = event.detail;
setTempColumnIdx(index as number);
};
return (
<View>
<ActionSheet
show={show}
cancelText="Cancel"
confirmText="Confirm"
slot={{
title: (
<View className={styles['demo-custom-double-select-header']}>
<View>Time</View>
<View>Temp</View>
</View>
),
}}
useTitleSlot
onCancel={() => setShow(false)}
onClose={() => setShow(false)}
onConfirm={() => setShow(false)}
>
<View className={styles['demo-custom-double-select-content']}>
<DateTimePicker
className={styles.flex1}
type="time"
is12HourClock
showToolbar={false}
value={current12Date}
onInput={onCurrent12DateInput}
/>
<Picker
className={styles.flex1}
unit="℃"
activeIndex={tempColumnIdx}
columns={tempColumns}
onChange={onTempColumnChange}
/>
</View>
</ActionSheet>
<Button onClick={() => setShow(true)}>点击展示</Button>
</View>
);
}
```
index.module.less
```css
.demo-custom-double-select-header {
display: flex;
align-items: center;
justify-content: space-around;
}
.demo-custom-double-select-content {
display: flex;
align-items: center;
justify-content: space-between;
}
.flex1 {
flex: 1;
}
```
## API
### Props
| 参数 | 说明 | 类型 | 默认值 |
| ----------------------- | -------------------------------------------- | --------- | ------------------- |
| actions | 菜单选项 | _Array_ | `[]` |
| activeColor | 列表选项中 icon 的选中态颜色 | _string_ | `--app-M1` |
| cancelText | 取消按钮文字 | _string_ | - |
| closeOnClickAction | 是否在点击选项后关闭 | _boolean_ | `true` |
| closeOnClickOverlay | 点击遮罩是否关闭菜单 | _boolean_ | `true` |
| confirmText | 确认按钮文字 | _string_ | - |
| description | 选项上方的描述信息 | _string_ | - |
| overlay | 是否显示遮罩层 | _boolean_ | `true` |
| round | 是否显示圆角 | _boolean_ | `true` |
| safeAreaInsetBottom | 是否为 iPhoneX 留出底部安全距离 | _boolean_ | `true` |
| safeAreaInsetBottomMin `v1.1.0` | 是否需要预留出一个最小的底部安全距离,用于在 safeArea 底部为 0 时进行追加,需要在 safeAreaInsetBottom 为 true 时生效 | _number_ | `16` |
| show | 是否显示动作面板 | _boolean_ | - |
| title | 标题 | _string_ | - |
| useTitleSlot `v2.6.0` | 是否启用标题 Slot | _boolean_ | `false` |
| zIndex | z-index 层级 | _number_ | `100` |
| nativeDisabled `v2.5.0` | 开启弹框期间是否禁用本地手势; 会在弹框开始进入动画时调用 `ty.nativeDisabled(true)`, 在弹框关闭动画结束时调用 `ty.nativeDisabled(false)` 恢复异层组件的点击能力;由于`ty.nativeDisabled` 是全局生效的,所以多个弹框组件同时打开时注意是否传 `native-disabled`属性和关闭的时机,防止 `native-disabled` 属性失效 | _boolean_ | `false` |
| fullCoverView `v2.11.1` | 是否使用 cover-view 包裹弹层,用于覆盖原生组件(如 map、video)时使用 | _boolean_ | `false` |
### Events
| 事件名 | 说明 | 参数 |
| ------------------ | ---------------------------------------- | ---------------------------- |
| onAfterEnter | 遮罩进入后触发 | - |
| onAfterLeave | 遮罩离开后触发 | - |
| onBeforeEnter | 遮罩进入前触发 | - |
| onBeforeLeave | 遮罩离开前触发 | - |
| onCancel | 取消按钮点击时触发 | - |
| onClickOverlay | 点击遮罩层时触发 | - |
| onClose | 关闭时触发 | - |
| onConfirm | 确认按钮点击时触发 | - |
| onEnter | 遮罩进入中触发 | - |
| onLeave | 遮罩离开中触发 | - |
| onSelect | 选中选项时触发,禁用或加载状态下不会触发 | event.detail: 选项对应的对象 |
### Slot
| 名称 | 说明 |
| ------- | ---- |
| default | 自定义面板内容,通常用于插入自定义菜单内容 |
| title | 自定义标题内容,需要 `use-title-slot` 为 `true`,且未设置 `title` 属性时生效 |
### actions
`API`中的`actions`为一个对象数组,数组中的每一个对象配置每一列,每一列有以下`key`:
| 键名 | 说明 | 类型 | 默认值 |
| --------- | ----------------------------- | --------- | ------ |
| className | 为对应列添加额外的 class 类名 | _string_ | - |
| color | 选项文字颜色 | _string_ | - |
| checked | 是否为选中状态,显示选中图标 | _boolean_ | - |
| disabled | 是否为禁用状态 | _boolean_ | - |
| loading | 是否为加载状态 | _boolean_ | - |
| name | 标题 | _string_ | - |
| subname | 二级标题 | _string_ | - |
### 外部样式类
| 类名 | 说明 |
| ------------ | ------------------- |
| customClass | 根节点样式类 |
| listClass | `actions`容器样式类 |
### 样式变量
组件提供了下列 CSS 变量,可用于自定义样式,使用方法请参考 [ConfigProvider 组件](/material/smartui?comId=config-provider)。
| 名称 | 默认值 | 描述 |
| ----------------------------- | -------------------------------------- | ---- |
| --action-sheet-width | _calc(100% - 32px)_ | 弹窗的宽度 |
| --action-sheet-left | _16px_ | 弹窗绝对定位左侧的位置 |
| --action-sheet-max-height | _90%_ | 弹窗的最大高度 |
| --action-sheet-margin | _0 0 16px_ | 弹窗的边距 |
| --action-sheet-active-color | _var(--app-B1, #f6f7fb)_ | 选中图标的颜色,以及按下时列表的背景色 |
| --action-sheet-item-disabled-opacity | _0.3_ | 禁用列表的透明度 |
| --action-sheet-header-border-color | _var(--app-B4-N7, rgba(0, 0, 0, 0.1))_ | 头部的边框色 |
| --action-sheet-header-height | _56px_ | 头部的高度 |
| --action-sheet-header-color | _var(--app-B4-N3, rgba(0, 0, 0, 0.5))_ | 头部的字体颜色 |
| --action-sheet-header-font-size | _16px_ | 头部的字体大小 |
| --action-sheet-header-font-weight | _normal_ | 头部的字重 |
| --action-sheet-description-color | _var(--app-B4-N3, rgba(0, 0, 0, 0.5))_ | 说明文字的颜色 |
| --action-sheet-description-font-size | _14px_ | 说明文字的字体大小 |
| --action-sheet-description-line-height | _20px_ | 说明文字的行高 |
| --action-sheet-item-background | _var(--app-B4, #ffffff)_ | 列表的背景色 |
| --action-sheet-item-border-radius | _0_ | 列表的边框圆角 |
| --action-sheet-item-icon-margin | _0px 16px 0 0_ | 列表的图标大小边距 |
| --action-sheet-item-icon-color | _var(--app-M1, #3678e3)_ | 列表的图标颜色 |
| --action-sheet-item-icon-size | _28px_ | 列表的图标大小 |
| --action-sheet-item-font-size | _16px_ | 列表的文字字体大小 |
| --action-sheet-item-font-weight | _normal_ | 列表的文字字重 |
| --action-sheet-item-line-height | _24px_ | 列表的文字的行高 |
| --action-sheet-item-text-color | _var(--app-B4-N1, rgba(0, 0, 0, 1))_ | 列表的文字的颜色 |
| --action-sheet-subname-color | _var(--app-B4-N3, rgba(0, 0, 0, 0.5))_ | 列表二级名称的字体颜色 |
| --action-sheet-subname-font-size | _12px_ | 列表二级名称的字体大小 |
| --action-sheet-subname-line-height | _20px_ | - |
| --action-sheet-confirm-text-color | _var(--app-B4-N1, rgba(0, 0, 0, 1))_ | 确认按钮的字体颜色 |
| --action-sheet-confirm-font-weight | _500_ | 确认按钮的字体字重 |
| --action-sheet-cancel-text-color | _var(--app-B4-N3, rgba(0, 0, 0, 0.5))_ | 取消按钮的字体颜色 |
| --action-sheet-footer-padding-top | _8px_ | 底部内容的顶部内边距 |
| --action-sheet-footer-padding-color | _var(--app-B4-N9, rgba(0, 0, 0, 0.05))_ | 底部内容的距离列表的间隔色 |
| --action-sheet-active-icon-color `v2.2.0` | _var(--app-M1, #3678e3)_ | 列表选中图标的颜色 |
## 常见问题
### ActionSheet 子组件使用 Slider 渲染定位异常,是什么情况?
由于 `Slider` 组件在 `ActionSheet` 打开时可能尚未完全渲染,因此我们无法获取其 DOM,从而导致定位出现问题。解决方案是在 `ActionSheet` 的 `onAfterEnter` 事件回调之后再开始渲染 `Slider` 组件。这样,我们可以确保 `Slider` 能够在获取 DOM 时被正常渲染。请参考以下示例:
```tsx
import React from 'react';
import { View, Text } from '@ray-js/ray';
import { useDebounce } from 'ahooks';
import { ActionSheet, Slider } from '@ray-js/smart-ui';
import styles from './index.module.less';
function Demo() {
const [ready, setReady] = React.useState(false);
const [currentNumber, setCurrentNumber] = React.useState(100);
const currentNumberForSlider = useDebounce(currentNumber, { wait: 500 });
const onActionSheetReady = React.useCallback(() => setReady(true), []);
const [showNumber, setShowNumber] = React.useState(false);
const onChange = React.useCallback(value => {
setCurrentNumber(value);
}, []);
const toggleActionSheetNumber = React.useCallback(() => setShowNumber(!showNumber), [showNumber]);
return (
<ActionSheet
show={showNumber}
title="Title"
cancelText="Action"
confirmText="Action"
onClose={toggleActionSheetNumber}
onCancel={toggleActionSheetNumber}
onConfirm={toggleActionSheetNumber}
onAfterEnter={onActionSheetReady}
>
<View className={styles['content-number']}>
<View className={styles['demo-header']}>
<Text className={styles['demo-text']}>{`${currentNumber}%`}</Text>
</View>
<View className={styles['demo-slider']}>
{ready && (
<Slider
minTrackRadius="8px"
minTrackHeight="45px"
maxTrackRadius="8px"
maxTrackHeight="45px"
value={currentNumberForSlider}
onChange={onChange}
thumbWidth={15}
thumbHeight={50}
thumbRadius={2}
thumbStyle={{
background: '#BBC5D4',
border: '2px solid #FFFFFF',
boxShadow: '0px 0px 2px 0px rgba(0, 0, 0, 0.5)',
}}
/>
)}
</View>
</View>
</ActionSheet>
);
}
```