# FloatButton 悬浮按钮/快捷菜单

- 来源：[E10 UI 组件库](https://www.e-cology.com.cn/ui/mobile/float-button/freepass)
- 平台：移动端
- 维护者：屈正巍
- Issue：http://gitlab.ecology10.cn/FRONTEND/weapp-ui/-/issues?state=all&search=[FloatButton]

## 代码演示

### 基础用法

直接引入组件进行使用

```jsx
import { Component, ReactText, CSSProperties, } from 'react';
import { FloatButton, Checkbox, Select, SingleType, SelectValueType, SelectOptionData, Input, Icon, Radio } from '@weapp/ui';
const rtl = window.weappUtils?.needRTL?.()
const { InputNumber } = Input

const radioOptionsData = [
  { id: 'window', title: 'window', content: 'window' },
  { id: 'demoNode', title: 'demoNode', content: 'demoNode' }
]

const options1 = [
  { id: 'px', content: 'px', },
  { id: '%', content: '%', },
]

const options2 = [
  { id: 'trigger', content: '四周展开', },
  { id: 'popover', content: '列表卡片', },
  { id: 'dialog', content: '下方滑出', },
]

class QuickMenuDemo extends Component<any> {

  state = {
    radioValue: 'window',
    disableDrag: false,
    sidebarCollapse: false,
    sidebarCollapseDragLimit: false,
    useCustomRender: false,
    closeAnimation: false,
    countsComplete: false,
    size: 50,
    width: void 0,
    height: void 0,
    borderRadiusType: '%',
    borderRadius: 50,
    renderCount: 15,
    counts: 100,
    menuType: 'trigger',
  }

  onClick = () => console.log('onQuickMenuClick-外部api渲染点击事件')
  onMenuVisibleChange = (visible?: boolean) => console.info('onMenuVisibleChange', visible)
  getContainer = () => {
    const { radioValue } = this.state
    const container = radioValue === 'window' ? void 0 : document.getElementById('demoNode') as any
    console.log('getContainer-container', container)
    return container
  }
  onQuickIconClick = () => console.info('onQuickIconClick-外部自定义渲染点击事件')
  renderQuickIcon = () => {
    return (
      <div id={'demo-test-customIcon'}>
        <Icon style={{ width: 30, height: 30, border: ' 1px solid pink' }} name={'Icon-Robot2'} onClick={this.onQuickIconClick} />
      </div>
    )
    // return <Icon style={{ width: 30, height: 30, border: ' 1px solid pink' }} name={'Icon-Robot2'} onClick={this.onQuickIconClick} />
  }

  // 按钮挂载容器
  handleRadioChange = (value: any) => this.setState({ radioValue: value })
  // 是否可拖拽
  handleChangeDisableDrag = (value: any) => this.setState({ disableDrag: value })
  // 是否用自定义渲染
  handleChangeUseCustomRender = (value: any) => this.setState({ useCustomRender: value })
  // 是否侧边收起
  handleChangeSidebarCollapse = (value: any) => this.setState({ sidebarCollapse: value })
  // 是否开启侧边收起拖拽限制
  handleChangeSidebarCollapseDragLimit = (value: any) => this.setState({ sidebarCollapseDragLimit: value })
  // 按钮大小
  handleInputNumber = (value: ReactText) => this.setState({ size: value })
  // 按钮宽高
  handleInputNumber2 = (value: ReactText) => this.setState({ width: value })
  handleInputNumber3 = (value: ReactText) => this.setState({ height: value })
  // 按钮圆角
  handleSelect = (value: SingleType<SelectValueType>, option: SelectOptionData) => this.setState({ borderRadiusType: value })
  handleInputNumber4 = (value: ReactText) => this.setState({ borderRadius: value })
  // 计数数量
  handleInputNumber6 = (value: ReactText) => this.setState({ counts: value })
  // 计数按钮是否完整展示
  handleCountsComplete = (value: any) => this.setState({ countsComplete: value })
  // 子菜单数量
  handleInputNumber5 = (value: ReactText) => this.setState({ renderCount: value, clickOpenMDialog: false })
  // 子菜单类型
  handleSelect1 = (value: SingleType<SelectValueType>, option: SelectOptionData) => this.setState({ menuType: value })
  // 禁止子菜单动画
  handleChangeCloseAnimation = (value: any) => this.setState({ closeAnimation: value })

  // buttons
  click1 = () => alert('点击了第一个')
  click2 = () => alert('点击了第二个')
  click3 = () => alert('点击了第三个')
  click4 = () => alert('点击了第四个')
  click5 = () => alert('点击了第五个')
  getButtons = () => {
    const buttonsStyle: CSSProperties = rtl ? { transform: 'scaleX(-1)' } : {}
    const buttons = [
      [(<span style={buttonsStyle} onClick={this.click1}><Icon name={'Icon-Right-fold-up'} /></span>), '新建流程', '#FF666A'],
      [(<span style={buttonsStyle} onClick={this.click2} ><Icon name={'Icon-Speechless'} /></span>), '图标按钮', '#ffcd52'],
      [(<span style={buttonsStyle} onClick={this.click3}><Icon name={'Icon-@My-new-feedback'} /></span>), '一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接', '#40D8AD'],
      [(<span style={buttonsStyle} onClick={this.click4}><Icon name={'Icon-gateway'} /></span>), '一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮', '#24CEF6'],
      [(<span style={buttonsStyle} onClick={this.click5}><Icon name={'Icon-gateway'} /></span>), '第五个按钮', '#666666'],
      [(<span style={buttonsStyle} onClick={this.click1}><Icon name={'Icon-Right-fold-up'} /></span>), '新建流程', '#FF666A'],
      [(<span style={buttonsStyle} onClick={this.click2} ><Icon name={'Icon-Speechless'} /></span>), '图标按钮', '#ffcd52'],
      [(<span style={buttonsStyle} onClick={this.click3}><Icon name={'Icon-@My-new-feedback'} /></span>), '一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接', '#40D8AD'],
      [(<span style={buttonsStyle} onClick={this.click4}><Icon name={'Icon-gateway'} /></span>), '一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮', '#24CEF6'],
      [(<span style={buttonsStyle} onClick={this.click5}><Icon name={'Icon-gateway'} /></span>), '第五个按钮', '#666666'],
      [(<span style={buttonsStyle} onClick={this.click1}><Icon name={'Icon-Right-fold-up'} /></span>), '新建流程', '#FF666A'],
      [(<span style={buttonsStyle} onClick={this.click2} ><Icon name={'Icon-Speechless'} /></span>), '图标按钮', '#ffcd52'],
      [(<span style={buttonsStyle} onClick={this.click3}><Icon name={'Icon-@My-new-feedback'} /></span>), '一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接', '#40D8AD'],
      [(<span style={buttonsStyle} onClick={this.click4}><Icon name={'Icon-gateway'} /></span>), '一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮', '#24CEF6'],
      [(<span style={buttonsStyle} onClick={this.click5}><Icon name={'Icon-gateway'} /></span>), '第五个按钮', '#666666'],
      [(<span style={buttonsStyle} onClick={this.click1}><Icon name={'Icon-Right-fold-up'} /></span>), '新建流程', '#FF666A'],
      [(<span style={buttonsStyle} onClick={this.click2} ><Icon name={'Icon-Speechless'} /></span>), '图标按钮', '#ffcd52'],
      [(<span style={buttonsStyle} onClick={this.click3}><Icon name={'Icon-@My-new-feedback'} /></span>), '一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接', '#40D8AD'],
      [(<span style={buttonsStyle} onClick={this.click4}><Icon name={'Icon-gateway'} /></span>), '一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮', '#24CEF6'],
      [(<span style={buttonsStyle} onClick={this.click5}><Icon name={'Icon-gateway'} /></span>), '第五个按钮', '#666666'],
      [(<span style={buttonsStyle} onClick={this.click1}><Icon name={'Icon-Right-fold-up'} /></span>), '新建流程', '#FF666A'],
      [(<span style={buttonsStyle} onClick={this.click2} ><Icon name={'Icon-Speechless'} /></span>), '图标按钮', '#ffcd52'],
      [(<span style={buttonsStyle} onClick={this.click3}><Icon name={'Icon-@My-new-feedback'} /></span>), '一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接', '#40D8AD'],
      [(<span style={buttonsStyle} onClick={this.click4}><Icon name={'Icon-gateway'} /></span>), '一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮', '#24CEF6'],
      [(<span style={buttonsStyle} onClick={this.click5}><Icon name={'Icon-gateway'} /></span>), '第五个按钮', '#666666'],
    ]
    return buttons
  }

  // ----------render----------
  render() {
    const { radioValue, disableDrag, sidebarCollapse, sidebarCollapseDragLimit, closeAnimation, countsComplete, size, width, height, borderRadius, renderCount, menuType, borderRadiusType, counts, useCustomRender } = this.state
    const buttons = this.getButtons()
    return (
      <div id={'demoNode'}>
        <div style={{ height: 40, display: 'flex', alignItems: 'center' }}>
          <span>调整定位容器:</span>
          <Radio
            style={{ marginLeft: 10 }}
            data={radioOptionsData}
            value={radioValue}
            onChange={this.handleRadioChange} />
        </div>
        <div style={{ height: 40, display: 'flex', alignItems: 'center' }}>
          <span>禁止拖拽:</span>
          <Checkbox
            style={{ marginLeft: 10 }}
            value={disableDrag}
            onChange={this.handleChangeDisableDrag} />
        </div>
        <div style={{ height: 40, display: 'flex', alignItems: 'center' }}>
          <span>自定义渲染:</span>
          <Checkbox
            style={{ marginLeft: 10 }}
            value={useCustomRender}
            onChange={this.handleChangeUseCustomRender} />
        </div>
        <div style={{ height: 40, display: 'flex', alignItems: 'center' }}>
          <span>侧边收起:</span>
          <Checkbox
            style={{ marginLeft: 10 }}
            value={sidebarCollapse}
            onChange={this.handleChangeSidebarCollapse} />
        </div>
        {/* <div style={{ height: 40, display: 'flex', alignItems: 'center' }}>
          <span>侧边收起拖拽限制:</span>
          <Checkbox
            style={{ marginLeft: 10 }}
            value={sidebarCollapseDragLimit}
            onChange={this.handleChangeSidebarCollapseDragLimit} />
        </div> */}
        <div style={{ height: 40, display: 'flex', alignItems: 'center' }}>
          <span>按钮大小:</span>
          <InputNumber
            style={{ width: 50, marginLeft: 10 }}
            value={size}
            onChange={this.handleInputNumber}
            max={9999}
            min={20}
          />
          <span>（注意当宽/高设置值后会替代按钮大小的值）</span>
        </div>
        <div style={{ height: 40, display: 'flex', alignItems: 'center' }}>
          <span>按钮宽度:</span>
          <InputNumber
            style={{ width: 50, marginLeft: 10 }}
            value={width}
            onChange={this.handleInputNumber2}
            max={9999}
            min={20}
          />
        </div>
        <div style={{ height: 40, display: 'flex', alignItems: 'center' }}>
          <span>按钮高度:</span>
          <InputNumber
            style={{ width: 50, marginLeft: 10 }}
            value={height}
            onChange={this.handleInputNumber3}
            max={9999}
            min={20}
          />
        </div>
        <div style={{ height: 40, display: 'flex', alignItems: 'center' }}>
          <span>按钮圆角:</span>
          <Select
            style={{ width: 50, marginLeft: 10, marginRight: 5 }}
            data={options1}
            value={borderRadiusType}
            onSelect={this.handleSelect}
            placeholder={'类型'}
          />
          <InputNumber
            style={{ width: 50, marginLeft: 10 }}
            value={borderRadius}
            onChange={this.handleInputNumber4}
            max={borderRadiusType === '%' ? 50 : void 0}
            min={0}
          />
        </div>
        <div style={{ height: 40, display: 'flex', alignItems: 'center' }}>
          <span>计数按钮数量:</span>
          <InputNumber
            style={{ width: 50, marginLeft: 10 }}
            value={counts}
            onChange={this.handleInputNumber6}
            min={0}
          />
        </div>
        <div style={{ height: 40, display: 'flex', alignItems: 'center' }}>
          <span>计数按钮是否完整展示:</span>
          <Checkbox
            style={{ marginLeft: 10 }}
            value={countsComplete}
            onChange={this.handleCountsComplete} />
        </div>
        <div style={{ height: 40, display: 'flex', alignItems: 'center' }}>
          <span>子菜单数量</span>
          <InputNumber
            style={{ width: 50, marginLeft: 10 }}
            value={renderCount}
            onChange={this.handleInputNumber5}
            max={50}
            min={0}
          />
          <span>（注意demo最多25个） </span>
        </div>
        <div style={{ height: 40, display: 'flex', alignItems: 'center' }}>
          <span>子菜单类型:</span>
          <Select
            style={{ width: 100, marginLeft: 10 }}
            data={options2}
            value={menuType}
            onSelect={this.handleSelect1}
          />
        </div>
        <div style={{ height: 40, display: 'flex', alignItems: 'center' }}>
          <span>禁止子菜单动画:</span>
          <Checkbox
            style={{ marginLeft: 10 }}
            value={closeAnimation}
            onChange={this.handleChangeCloseAnimation} />
        </div>
        <FloatButton
          key={radioValue} // 使用 radioValue 作为 key，强制重新渲染
          getContainer={this.getContainer}
          disableDrag={disableDrag}
          sidebarCollapse={sidebarCollapse}
          sidebarCollapseDragLimit={sidebarCollapseDragLimit}
          className={"my-float-button-demo"}
          menuClassName={"menu-class-demo"}
          size={Number(size)}
          width={Number(width)}
          height={Number(height)}
          borderRadius={Number(borderRadius)}
          borderRadiusType={borderRadiusType as any}
          closeAnimation={closeAnimation}
          countsComplete={countsComplete}
          counts={Number(counts)}
          right={50}
          bottom={50}
          // 一些菜单配置项
          menuType={menuType as any}
          buttons={buttons.slice(0, this.state.renderCount)}
          popoverId={'my-popover-id-demo'}
          popoverClassName={'my-popover-class-demo'}
          menuTriggerClassName={'my-menu-trigger-class-demo'}
          menuTriggerPlacementButtonClassName='my-menu-trigger-placement-button-class-demo'
          // moreMenuTitle={'自定义更多'}
          // moreMenuElement={(<Icon name={'Icon-Right-fold-up'} />)}
          // quickIcon
          onClick={this.onClick}
          onMenuVisibleChange={this.onMenuVisibleChange}
          quickIcon={useCustomRender ? this.renderQuickIcon() : void 0}
        />
      </div>
    );
  }
}

export default QuickMenuDemo;
```

### 自定义按钮

自定义渲染悬浮按钮中的内容

```jsx
import { Icon, FloatButton } from '@weapp/ui';
import React, { useCallback } from 'react';
// import './style/index.less';

interface QuickMenuDemoProps {
  weId?: string;
}

const Index = (props: QuickMenuDemoProps) => {

  let ref: any = null;

  const click = useCallback(() => {
    alert('点击了第一个');
  }, []);

  const buttons = [
    [(<span onClick={click} > <Icon name={'Icon-Right-fold-up'} /> </span>), '新建流程', '#FF666A'],
    [(<Icon name={'Icon-Speechless'} />), '图标按钮', '#ffcd52'],
    [(<Icon name={'Icon-@My-new-feedback'} />), '一个连接', '#40D8AD'],
    [(<Icon name={'Icon-gateway'} />), '一个按钮', '#24CEF6']
  ];

  const setRef = useCallback((el: any) => {
    ref = el
  }, [])

  const getRef = useCallback(() => {
    return ref;
  }, [ref]);

  return (
    <div>
      <div className="customRef" ref={setRef}>自定义弹窗渲染的位置</div>
      <FloatButton
        className="my-float-button-demo"
        menuClassName="menu-class-demo"
       
        quickIcon={'testesttest'}
        buttons={buttons}
        popupContainer={getRef}
        counts={9}
      />
    </div>
  );
}

export default Index;
```

### 自定义按钮(禁拖拽)

自定义渲染悬浮按钮中的内容

```jsx
import { Icon, FloatButton } from '@weapp/ui';
import React, { useCallback } from 'react';
// import './style/index.less';

interface QuickMenuDemoProps {
  weId?: string;
}

const Index = (props: QuickMenuDemoProps) => {

  let ref: any = null;

  const click = useCallback(() => {
    alert('点击了第一个');
  }, []);

  const buttons = [
    [(<span onClick={click} > <Icon name={'Icon-Right-fold-up'} /> </span>), '新建流程', '#FF666A'],
    [(<Icon name={'Icon-Speechless'} />), '图标按钮', '#ffcd52'],
    [(<Icon name={'Icon-@My-new-feedback'} />), '一个连接', '#40D8AD'],
    [(<Icon name={'Icon-gateway'} />), '一个按钮', '#24CEF6']
  ];

  const setRef = useCallback((el: any) => {
    ref = el;
  }, [])

  const getRef = useCallback(() => {
    return ref;
  }, [ref]);

  return (
    <div>
      <div className="customRef" ref={setRef}>自定义弹窗渲染的位置</div>
      <FloatButton
        className="my-float-button-demo"
        menuClassName="menu-class-demo"
       
        quickIcon={'test'}
        buttons={buttons}
        popupContainer={getRef}
        counts={9}
        disableDrag
      />
    </div>
  );
}

export default Index;
```

### 指定渲染节点

自定义按钮渲染指定节点(默认为body)

```jsx
import React, { Component } from 'react';
import { FloatButton, MDialog, MButton } from '@weapp/ui';

interface QuickMenuDemoProps { }
interface QuickMenuDemoState {
  dialogVisible: boolean;
  size: number;
  node: string,
}

class QuickMenuDemo extends Component<QuickMenuDemoProps, QuickMenuDemoState> {

  state = {
    dialogVisible: false,
    size: 44,
    node: 'demoNode2'
  }

  onClick = () => this.setState({ dialogVisible: true })
  onCloseDialog = () => this.setState({ dialogVisible: false })
  onChange = (value: any) => this.setState({ size: value })
  getContainer = () => {
    const { node } = this.state
    return document.getElementById(node) as any
  }

  setNode1 = () => {
    this.setState({ node: 'demoNode1' })
  }

  setNode2 = () => {
    this.setState({ node: 'demoNode2' })
  }

  render() {
    const { size, node } = this.state
    return (
      <div id='demoNode1'>
        <h4>更多节点配置请移步pc端QuickMenu组件的demo查看</h4>
        <MButton onClick={this.setNode1}>点击渲染到节点1</MButton>
        <div id='demoNode2'>
          <MButton onClick={this.setNode2}>点击渲染到节点2</MButton>
          <MDialog
            visible={this.state.dialogVisible}
            title={'测试测试'}
            onClose={this.onCloseDialog}
            onOk={this.onCloseDialog}
            destroyOnClose
            mask
            maskClosable
            placement="middle"
          />
        </div>
        <FloatButton
          className="my-float-button-demo"
          menuClassName="menu-class-demo"
          getContainer={this.getContainer}
          onClick={this.onClick}
          key={node}
          size={Number(size)}
        />
      </div>
    );
  }
}

export default QuickMenuDemo;
```

### 在MDialog中使用

在MDialog中使用

```jsx
import { Component, CSSProperties } from 'react';
import { FloatButton, Checkbox, Icon, MDialog, MButton } from '@weapp/ui';
const rtl = window.weappUtils?.needRTL?.()

class QuickMenuDemo extends Component<any> {

  state = {
    disableDrag: false,
    closeAnimation: false,
    countsComplete: false,
    size: 50,
    width: void 0,
    height: void 0,
    borderRadiusType: '%',
    borderRadius: 50,
    renderCount: 15,
    menuType: 'trigger',
    // 以下为MDialog交互
    dialogVisible: false,
  }

  handleChangeDisableDrag = (value: any) => this.setState({ disableDrag: value })

  // buttons
  click1 = () => alert('点击了第一个')
  click2 = () => alert('点击了第二个')
  click3 = () => alert('点击了第三个')
  click4 = () => alert('点击了第四个')
  click5 = () => alert('点击了第五个')
  getButtons = () => {
    const buttonsStyle: CSSProperties = rtl ? { transform: 'scaleX(-1)' } : {}
    const buttons = [
      [(<span style={buttonsStyle} onClick={this.click1}><Icon name={'Icon-Right-fold-up'} /></span>), '新建流程', '#FF666A'],
      [(<span style={buttonsStyle} onClick={this.click2} ><Icon name={'Icon-Speechless'} /></span>), '图标按钮', '#ffcd52'],
      [(<span style={buttonsStyle} onClick={this.click3}><Icon name={'Icon-@My-new-feedback'} /></span>), '一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接', '#40D8AD'],
      [(<span style={buttonsStyle} onClick={this.click4}><Icon name={'Icon-gateway'} /></span>), '一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮', '#24CEF6'],
      [(<span style={buttonsStyle} onClick={this.click5}><Icon name={'Icon-gateway'} /></span>), '第五个按钮', '#666666'],
      [(<span style={buttonsStyle} onClick={this.click1}><Icon name={'Icon-Right-fold-up'} /></span>), '新建流程', '#FF666A'],
      [(<span style={buttonsStyle} onClick={this.click2} ><Icon name={'Icon-Speechless'} /></span>), '图标按钮', '#ffcd52'],
      [(<span style={buttonsStyle} onClick={this.click3}><Icon name={'Icon-@My-new-feedback'} /></span>), '一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接', '#40D8AD'],
      [(<span style={buttonsStyle} onClick={this.click4}><Icon name={'Icon-gateway'} /></span>), '一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮', '#24CEF6'],
      [(<span style={buttonsStyle} onClick={this.click5}><Icon name={'Icon-gateway'} /></span>), '第五个按钮', '#666666'],
      [(<span style={buttonsStyle} onClick={this.click1}><Icon name={'Icon-Right-fold-up'} /></span>), '新建流程', '#FF666A'],
      [(<span style={buttonsStyle} onClick={this.click2} ><Icon name={'Icon-Speechless'} /></span>), '图标按钮', '#ffcd52'],
      [(<span style={buttonsStyle} onClick={this.click3}><Icon name={'Icon-@My-new-feedback'} /></span>), '一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接', '#40D8AD'],
      [(<span style={buttonsStyle} onClick={this.click4}><Icon name={'Icon-gateway'} /></span>), '一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮', '#24CEF6'],
      [(<span style={buttonsStyle} onClick={this.click5}><Icon name={'Icon-gateway'} /></span>), '第五个按钮', '#666666'],
      [(<span style={buttonsStyle} onClick={this.click1}><Icon name={'Icon-Right-fold-up'} /></span>), '新建流程', '#FF666A'],
      [(<span style={buttonsStyle} onClick={this.click2} ><Icon name={'Icon-Speechless'} /></span>), '图标按钮', '#ffcd52'],
      [(<span style={buttonsStyle} onClick={this.click3}><Icon name={'Icon-@My-new-feedback'} /></span>), '一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接', '#40D8AD'],
      [(<span style={buttonsStyle} onClick={this.click4}><Icon name={'Icon-gateway'} /></span>), '一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮', '#24CEF6'],
      [(<span style={buttonsStyle} onClick={this.click5}><Icon name={'Icon-gateway'} /></span>), '第五个按钮', '#666666'],
      [(<span style={buttonsStyle} onClick={this.click1}><Icon name={'Icon-Right-fold-up'} /></span>), '新建流程', '#FF666A'],
      [(<span style={buttonsStyle} onClick={this.click2} ><Icon name={'Icon-Speechless'} /></span>), '图标按钮', '#ffcd52'],
      [(<span style={buttonsStyle} onClick={this.click3}><Icon name={'Icon-@My-new-feedback'} /></span>), '一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接一个链接', '#40D8AD'],
      [(<span style={buttonsStyle} onClick={this.click4}><Icon name={'Icon-gateway'} /></span>), '一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮一个按钮', '#24CEF6'],
      [(<span style={buttonsStyle} onClick={this.click5}><Icon name={'Icon-gateway'} /></span>), '第五个按钮', '#666666'],
    ]
    return buttons
  }

  // ----------render----------
  handleOpenMDialog = () => this.setState({ dialogVisible: true })
  onMenuVisibleChange = (visible?: boolean) => console.log('onMenuVisibleChange', visible)
  handleCloseMDialog = () => this.setState({ dialogVisible: false })
  renderMDialog = () => {
    const { dialogVisible } = this.state
    return (
      <MDialog
        visible={dialogVisible}
        onClose={this.handleCloseMDialog}
        placement={'bottom'}
      >
        <div style={{ border: '1px solid pink', height: 300 }}></div>
      </MDialog>
    )
  }

  render() {
    const { disableDrag, closeAnimation, countsComplete, size, width, height, borderRadius, menuType, borderRadiusType, dialogVisible } = this.state
    const buttons = this.getButtons()
    return (
      <div>
        <div style={{ height: 40, display: 'flex', alignItems: 'center' }}>
          <span>悬浮按钮禁止拖拽:</span>
          <Checkbox
            style={{ marginLeft: 10 }}
            value={disableDrag}
            onChange={this.handleChangeDisableDrag} />
        </div>
        <MButton onClick={this.handleOpenMDialog}>点击打开弹窗</MButton>
        <MDialog
          visible={dialogVisible}
          onClose={this.handleCloseMDialog}
          placement={'bottom'}
        >
          <div style={{ border: '1px solid pink', height: 300 }}>
            <FloatButton
              className={"my-float-button-demo"}
              menuClassName={"menu-class-demo"}
              // onClick={this.onClick}
              onMenuVisibleChange={this.onMenuVisibleChange}
              size={Number(size)}
              width={Number(width)}
              height={Number(height)}
              borderRadius={Number(borderRadius)}
              borderRadiusType={borderRadiusType as any}
              disableDrag={disableDrag}
              closeAnimation={closeAnimation}
              countsComplete={countsComplete}
              counts={12345}
              buttons={buttons.slice(0, this.state.renderCount)}
              menuType={menuType as any}
              right={50}
              bottom={50}
            // left={100}
            // top={100}
            />
          </div>
        </MDialog>
      </div>
    );
  }
}

export default QuickMenuDemo;
```

## API

```typescript
// 打开方式分别对应 四周展开 列表卡片 下方滑出 
type QuickMenuMenuType = 'trigger' | 'popover' | 'dialog'
```

### 参数说明如下：

| 参数 | 说明 | 类型 | 是否必填 | 默认值 |
| --- | --- | --- | --- | --- |
| menuClassName | 菜单样式类 | string | 否 | ------ |
| buttons | 按钮属性配置 | (ReactNode, text:string, color:string)[][] | 否 | ------ |
| quickIcon | 自定义渲染图标 | ReactNode | 否 | ------ |
| onClick | 悬浮菜单点击事件 | function | 否 | ------ |
| startClassName(废弃，此后使用buttonClassName) | 点击按钮样式类 | string | 否 |  |
| buttonClassName | 点击按钮样式类 | string | 否 |  |
| staticClassName | 非拖拽按钮样式类 | string | 否 |  |
| dragClassName | 拖拽按钮样式类 | string | 否 |  |
| getContainer | 按钮渲染指定节点(默认为body) | () => HTMLElement | 否 | ------ |
| disableDrag | 禁用按钮拖拽 | boolean | 否 | ------ |
| size | 按钮的宽高 | number | 否 | 44 |
| defaultPosition | 拖拽按钮初始位置(此api废弃，改为right、bottom、left、top来定位) | ControlPosition | 否 | {x:0,y:0} |
| borderRadius | borderRadius的数值 | number | 否 | 50 |
| borderRadiusType | borderRadius的类型 | 'px'\|'%' | 否 | '%' |
| popoverText | 弹层内容(此项有值才会展示) | string | 否 | '%' |
| popoverType | 弹层类型 | PopoverType | 否 | '%' |
| popoverPlacement | 弹层位置 | PopupPlacement | 否 | '%' |
| popoverProps | 弹层props | PopoverProps | 否 | '%' |
| popoverId | 弹层id | string | 否 |  |
| popoverClassName | 弹层className | string | 否 |  |
| menuTriggerProps | 四周展开模式的triggerProps | TriggerProps | 否 |  |
| menuTriggerClassName | 四周展开模式的trigger的类名 | string | 否 |  |
| menuTriggerPlacementButtonClassName | 四周展开模式的占位按钮的类名 | string | 否 |  |
| menuType | 菜单打开方式 | QuickMenuMenuType | 否 | 'trigger' |
| menuPopoverType | 移动端菜单模式的popoverType | PopoverType | 否 | 'popover' |
| menuPopoverProps | 移动端菜单模式的popover的props | PopoverProps | 否 |  |
| menuPopoverId | 移动端菜单模式的popover的id | string | 否 |  |
| menuPopoverClassName | 移动端菜单模式的popover的className | string | 否 |  |
| right | 绝对定位右侧边距 | number | 否 |  |
| bottom | 绝对定位底部边距 | number | 否 |  |
| left | 绝对定位左侧边距 | number | 否 |  |
| top | 绝对定位顶部边距 | number | 否 |  |
| closeAnimation | 是否关闭动画(安卓手机默认开启) | boolean | 否 |  |
| countsComplete | 右上角计数按钮是否完整展示 | boolean | 否 |  |
| countsZeroHide | 右上角计数按钮为0时是否隐藏 | boolean | 否 |  |
| clickStopPropagation | 点击时是否阻止冒泡(当开启自定义渲染quickIcon时默认开启) | boolean | 否 |  |
| useQuickIconClick | 是否触发自定义渲染的icon内部的点击事件 | boolean | 否 |  |
| sidebarCollapse | 是否开启侧边收起 | boolean | 否 |  |
| sidebarCollapseDragLimit | 侧边收起拖拽限制 | boolean | 否 |  |
| relativeToContainer | 是否相对于容器定位(需要在getContainer中传入有效节点) | boolean | 否 |  |
| restrictToContainer | 拖拽是否限制在容器内(需要开启相对容器定位) | boolean | 否 |  |
