---
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>
  );
}
```