Overlay 弹层

如果项目中使用的是 1.x 版本的基础组件(@alifd/next),请在左侧导航顶部切换组件版本。

安装方法

  1. 在命令行中执行以下命令npm install @icedesign/base@latest -S

用于弹层类的工具类集合.

开发指南

Overlay提供了一系列的组件的集合用于创建弹层组件。其中包含:

Gateway

Gateway的作用是将节点渲染到指定的容器中。正常情况下React使用当前节点所在的父节点作为容器,但是Gateway可以将其包含的节点渲染到另外的节点中。

Gateway只有一个配置项就是container, 它可以接受字符串和函数。

  1. // 将span渲染到id为container的节点中
  2. <Gateway container="container">
  3. <span>123</span>
  4. </Gateway>

实际上也可以传入container为函数,返回节点的ref.

  1. <div ref="container"></div>
  2. <Gateway container={() => this.refs.container}>
  3. <span>123</span>
  4. </Gateway>

Overlay

Overlay利用了Gateway提供的能力,可以在页面中弹出一个浮层,封装了动画和定位及一些可用性的功能。

Overlay被设计为无状态的组件,其本身并不控制自己的显示和隐藏的状态。

注意: 类似的canCloseby*的配置也需要配合onRequestClose才能关闭Overlay

安全节点

弹层同时提供点击文档中的节点隐藏该弹层的功能,但是由于React内部维护了一个事件队列,且并未提供针对document的事件绑定方式,所以在点击任何一个节点都会触发document的click,即便手动阻止冒泡也不行, Overlay采用了一个安全节点的设置来避免这个问题.

定位

  • align由空格隔开的字符串表示,例如 tl bl. 其中tl代表目标元素的左上方,bl代表基准元素的左下方,所以tl bl的意思是目标元素的左上方对齐基准元素左下方。其中定位的可选值有 tl, tc, tr, cl, cc, cr, bl, bc, br.

  • align支持的Boolean值仅为false,在设置为false的时候,不使用JS定位,这样你可以根据你的需要传入style或者className进行CSS定位。

说明 ttop的缩写,bbottom的缩写,ccenter的缩写,lleft的缩写,rright的缩写.

下面的例子演示了如何将弹层定位到页面的右上角

<Overlay visible align="tr tr"><span>123</span></Overlay>

Popup

接收某个节点,弹出一个浮层, 这个浮层默认情况下使用这个节点作为定位的参照对象

API

弹层

参数说明类型默认值
prefix样式类名的品牌前缀String'next-'
className自定义类名String-
style自定义样式对象Object-
children浮层内容any-
visible是否显示浮层, 如果此属性为false,浮层不会被渲染Booleanfalse
canCloseByEsc是否支持esc按键关闭浮层Booleantrue
canCloseByOutSideClick点击浮层外的区域是否关闭浮层Booleantrue
canCloseByMask点击遮罩区域是否关闭浮层Booleantrue
animation配置动画的播放方式Object/Boolean{ in: 'expandInDown', out: 'expandOutUp' }
target配置浮层定位的参照元素anyPosition.VIEWPORT
align浮层相对于target的定位, 详见开发指南的定位部分String/Boolean'tl bl'
offset浮层相对于target定位的微调Array0, 0
beforeClose浮层关闭前触发的事件签名:Function() => voidFunction() => {}
onClose浮层关闭后触发的事件签名:Function() => voidFunction() => {}
afterClose浮层关闭后触发的事件, 如果有动画,则在动画结束后触发签名:Function() => voidFunction() => {}
beforeOpen浮层打开前触发的事件签名:Function() => voidFunction() => {}
onOpen浮层打开后触发的事件签名:Function() => voidFunction() => {}
afterOpen浮层打开后触发的事件, 如果有动画,则在动画结束后触发签名:Function() => voidFunction() => {}
onRequestClose浮层请求关闭触发的事件签名:Function(reason: String, e: Event) => void参数:reason: {String} 浮层关闭的来源e: {Event} DOM事件Function() => {}
beforePosition浮层定位完成前触发的事件签名:Function() => voidFunction-
onPosition浮层定位完成后触发的事件签名:Function(config: Object, node: Object) => void参数:config: {Object} 定位的参数node: {Object} 定位的元素Function() => {}
autoFocus浮层打开的时候是否让里面的元素自动获取焦点Booleanfalse
hasMask是否显示遮罩Booleanfalse
cache隐藏时是否保留子节点Booleanfalse
safeNode安全节点,当点击document的时候, 如果包含该节点则不会关闭浮层, 如果是函数需要返回ref, 如果是字符串则是该DOM的id, 也可以直接传入DOM节点any-
wrapperClassName浮层的根节点的样式类String-
container指定渲染组件的容器any-
shouldUpdatePosition强制更新定位信息Boolean-
needAdjust是否自动调整定位的位置Boolean-
disableScroll是否禁用页面滚动Booleanfalse

Overlay.Gateway

参数说明类型默认值
container指定渲染children的容器any() => document.body

Overlay.Popup

参数说明类型默认值
align弹层相对于target的定位, 详见开发指南的定位部分String'tl bl'
offset弹层相对于target定位的微调Array0, 0
trigger触发弹层显示或者隐藏的元素any<div></div>
triggerType触发弹层显示的类型String'hover'
visible弹层当前显示的状态Boolean-
defaultVisible弹层默认显示的状态Boolean-
disabled设置此属性,弹层无法打开Booleanfalse
delay弹层在触发以后的延时显示Number200
canCloseByOutSideClick点击浮层外的区域是否关闭浮层Booleantrue
onVisibleChange弹层在显示和隐藏触发的事件签名:Function(visible: Boolean, type: String, e: Event) => void参数:visible: {Boolean} 弹层是否隐藏和显示type: {String} 触发弹层显示和隐藏的来源e: {Event} DOM事件Function() => {}
autoFocus浮层打开的时候是否让里面的元素自动获取焦点Boolean-
animation配置动画的播放方式Object/Boolean{ in: 'expandInDown', out: 'expandOutUp' }
target配置弹层定位的参照元素any-

Overlay.Position

参数说明类型默认值
className自定义类名String-
target定位参照的元素any-
contentNode定位的目标元素any-
align定位的方式, 详见开发指南的定位部分String/Boolean'tl bl'
offset相对于target定位的微调Array0, 0
beforePosition定位完成前触发的事件签名:Function() => voidFunction() => {}
onPosition定位完成后触发的事件签名:Function(config: Object, node: Object) => void参数:config: {Object} 定位的参数node: {Object} 定位的元素Function() => {}
needAdjust是否自动调整定位的位置Booleantrue
needListenResize是否监听Resize事件Booleantrue
shouldUpdatePosition强制更新定位信息Booleanfalse
isRtl对齐方式Booleanfalse

代码示例

遮罩

带有遮罩的弹出层

Overlay 弹层 - 图1

查看源码在线预览

import { Overlay } from "@icedesign/base";

class App extends React.Component {
  constructor(props, context) {
    super(props, context);
    this.state = {
      visible: false
    };
  }
  render() {
    return (
      <span>
        <button onClick={this.onClick.bind(this)} ref="target">
          Open
        </button>
        <Overlay
          visible={this.state.visible}
          hasMask
          disableScroll
          align="cc cc"
          safeNode={() => this.refs.target}
          onRequestClose={this.onClose.bind(this)}
        >
          <span className="overlay-demo">Hello World From Overlay!</span>
        </Overlay>
      </span>
    );
  }
  onClick() {
    this.setState({ visible: true });
  }
  onClose = reason => {
    console.log("onRequestClose emit!, reason: ", reason);
    this.setState({
      visible: false
    });
  };
}

ReactDOM.render(<App />, mountNode);

.overlay-demo {
    border: 1px solid #999;
    padding: 10px;
    width: 300px;
    height: 100px;
    background: #fff;
    box-shadow: 2px 2px 20px rgba(0,0,0,0.15);
}

受控

演示了Popup受控的示例,可以在内部控制Popup的显示和隐藏

Overlay 弹层 - 图2

查看源码在线预览

import { Overlay } from "@icedesign/base";

const Popup = Overlay.Popup;

class App extends React.Component {
  state = {
    visible: false
  };
  render() {
    return (
      <Popup
        trigger={<button>Open</button>}
        visible={this.state.visible}
        triggerType="click"
        onVisibleChange={this.onVisibleChange}
      >
        <div className="overlay-demo">
          <button onClick={this.onClose}>Close</button>
          <p>Hello World From Popup!</p>
        </div>
      </Popup>
    );
  }
  onClose = () => {
    this.setState({
      visible: false
    });
  };
  onVisibleChange = visible => {
    this.setState({
      visible
    });
  };
}

ReactDOM.render(<App />, mountNode);

.overlay-demo {
    border: 1px solid #999;
    padding: 10px;
    width: 300px;
    height: 100px;
    background: #fff;
    box-shadow: 2px 2px 20px rgba(0,0,0,0.15);
}

Gateway

Gateway 的基本用法

Overlay 弹层 - 图3

查看源码在线预览

import { Overlay } from "@icedesign/base";

const { Gateway } = Overlay;

class App extends React.Component {
  render() {
    return (
      <div>
        <span ref="container" />
        <Gateway container={() => this.refs.container}>
          <span>Hello World from gateway.</span>
        </Gateway>
      </div>
    );
  }
}

ReactDOM.render(<App />, mountNode);

弹层嵌套

弹层嵌套的时候,使用container属性将容器渲染到第一个弹层的节点内部。

Overlay 弹层 - 图4

查看源码在线预览

import { Overlay } from "@icedesign/base";

const Popup = Overlay.Popup;

class App extends React.Component {
  state = {
    visible: false,
    overlayVisible: false
  };
  render() {
    return (
      <Popup
        trigger={<button>Open</button>}
        triggerType="click"
        visible={this.state.visible}
        onVisibleChange={this.onVisibleChange}
      >
        <div className="overlay-demo">
          <Popup
            triggerType="click"
            trigger={<button>Open overlay</button>}
            container={trigger => trigger && trigger.parentNode}
            visible={this.state.overlayVisible}
            onVisibleChange={this.onOverlayVisibleChange}
          >
            <div className="overlay-demo" onClick={this.hideOverlay}>
              Click me will close this overlay, but popup will not close.
            </div>
          </Popup>
          <p>Hello World From Popup!</p>
        </div>
      </Popup>
    );
  }
  hideOverlay = () => {
    this.setState({
      overlayVisible: false
    });
  };
  showOverlay = () => {
    this.setState({
      overlayVisible: true
    });
  };
  onVisibleChange = visible => {
    this.setState({
      visible
    });
  };
  onOverlayVisibleChange = overlayVisible => {
    this.setState({
      overlayVisible
    });
  };
}

ReactDOM.render(<App />, mountNode);

.overlay-demo {
    border: 1px solid #999;
    padding: 10px;
    width: 300px;
    height: 100px;
    background: #fff;
    box-shadow: 2px 2px 20px rgba(0,0,0,0.15);
}

弹出层

弹出一个浮层

Overlay 弹层 - 图5

查看源码在线预览

import { Overlay } from "@icedesign/base";

class App extends React.Component {
  constructor(props, context) {
    super(props, context);
    this.state = {
      visible: false
    };
  }
  render() {
    return (
      <span>
        <button onClick={this.onClick.bind(this)} ref="target">
          Toggle visible
        </button>
        <Overlay
          visible={this.state.visible}
          target={() => this.refs.target}
          safeNode={() => this.refs.target}
          onRequestClose={this.onClose.bind(this)}
        >
          <span className="overlay-demo">Hello World From Overlay!</span>
        </Overlay>
      </span>
    );
  }
  onClick() {
    this.setState({ visible: !this.state.visible });
  }
  onClose = () => {
    this.setState({
      visible: false
    });
  };
}

ReactDOM.render(<App />, mountNode);

.overlay-demo {
    border: 1px solid #999;
    padding: 10px;
    width: 300px;
    height: 100px;
    background: #fff;
    box-shadow: 2px 2px 20px rgba(0,0,0,0.15);
}

触发的弹层

使用Popup弹出一个浮层

Overlay 弹层 - 图6

查看源码在线预览

import { Overlay } from "@icedesign/base";

const Popup = Overlay.Popup;
const afterClose = () => {
  console.log("close");
};
const trigger = <button>Open</button>;
ReactDOM.render(
  <Popup trigger={trigger} triggerType="click" afterClose={afterClose}>
    <div className="overlay-demo">Hello World From Popup!</div>
  </Popup>,
  mountNode
);

.overlay-demo {
    border: 1px solid #999;
    padding: 10px;
    width: 300px;
    height: 100px;
    background: #fff;
    box-shadow: 2px 2px 20px rgba(0,0,0,0.15);
}

跟随滚动

演示弹层如何跟随滚动

Overlay 弹层 - 图7

查看源码在线预览

import { Overlay } from "@icedesign/base";

const Popup = Overlay.Popup;

class App extends React.Component {
  render() {
    return (
      <div className="scroll-container" ref="scroll">
        <Popup
          trigger={<button>Open</button>}
          container={() => this.refs.scroll}
          triggerType="click"
        >
          <div className="overlay-demo">
            <p>Hello World From Popup!</p>
          </div>
        </Popup>
        <div style={{ height: "300px" }} />
      </div>
    );
  }
}

ReactDOM.render(<App />, mountNode);

.overlay-demo {
    border: 1px solid #999;
    padding: 10px;
    width: 300px;
    height: 100px;
    background: #fff;
    box-shadow: 2px 2px 20px rgba(0,0,0,0.15);
}
.scroll-container {
    position: relative;
    height: 150px;
    border: 1px solid #999;
    padding: 10px;
    overflow: auto;
}

相关区块

Overlay 弹层 - 图8

暂无相关区块