2016-08-05 59 views
1

在iOS Safari中,触发=“焦点”的OverlayTrigger在外部点击时无法关闭。这里是我的代码:React Bootstrap OverlayTrigger with trigger =“focus”bug工作在

<OverlayTrigger 
    trigger="focus" 
    placement="right" 
    overlay={ <Popover id="popoverID" title="Popover Title"> 
       What a popover... 
      </Popover> } > 
    <a bsStyle="default" className="btn btn-default btn-circle" role="Button" tabIndex={18}> 
     <div className="btn-circle-text">?</div> 
    </a> 
</OverlayTrigger> 

我知道,这是自举的Cuz这并不甚至their own website在iOS的工作一个已知的bug,但没有人知道任何方法去解决呢?如果它不需要jQuery,那将是最好的,但是jQuery解决方案是受欢迎的。谢谢。

回答

1

OK,因为没有其他人围绕给我的工作,我曾在这个问题上与我的同事一起为3天,我们来到了这个沉重的解决方案:

问题:

当trigger =“focus”时,当在Popover/Tooltip外部单击而不是触摸时,Bootstrap Popover/Tooltip可以被解除。 Android浏览器显然会自动更改点击次数,所以Android上的事情很好。但是基于iOS safari(iOS chrome,iOS firefox等)的iOS Safari和浏览器不这么做。

THE FIX:

我们发现,在阵营引导,覆盖组件实际上允许您自定义的时候,显示酥料饼/工具提示,所以我们建立了基于覆盖该组件InfoOverlay。为了处理组件外部的点击,我们需要为Popover/Tooltip和窗口添加事件监听器来处理'mousedown'和'touchstart'。另外,这种方法会使Popover始终有最小的宽度,因为组件的填充权最初为0px,而且我们基于某个父组件的宽度进行制作,以便根据父组件进行响应。并且代码看起来是这样的:

import React, { Component, PropTypes as PT } from 'react'; 
import {Popover, Overlay} from 'react-bootstrap'; 

export default class InfoOverlay extends Component { 

    static propTypes = { 
     PopoverId: PT.string, 
     PopoverTitle: PT.string, 
     PopoverContent: PT.node, 
     // You need to add this prop and pass it some numbers 
     // if you need to customize the arrowOffsetTop, it's sketchy... 
     arrowOffsetTop: PT.number, 
     // This is to be able to select the parent component 
     componentId: PT.string 
    } 

    constructor(props) { 
     super(props); 
     this.state = { 
      showPopover: false, 
      popoverClicked: false 
     }; 
    } 

    componentDidMount() { 
     // Here are the event listeners and an algorithm 
     // so that clicking popover would not dismiss itself 
     const popover = document.getElementById('popoverTrigger'); 
     if (popover) { 
      popover.addEventListener('mousedown',() => { 
       this.setState({ 
        popoverClicked: true 
       }); 
      }); 
      popover.addEventListener('touchstart',() => { 
       this.setState({ 
        popoverClicked: true 
       }); 
      }); 
     } 
     window.addEventListener('mousedown',() => { 
      if (!this.state.popoverClicked) { 
       this.setState({ 
        showPopover: false 
       }); 
      } else { 
       this.setState({ 
        popoverClicked: false 
       }); 
      } 
     }); 
     window.addEventListener('touchstart',() => { 
      if (!this.state.popoverClicked) { 
       this.setState({ 
        showPopover: false 
       }); 
      } else { 
       this.setState({ 
        popoverClicked: false 
       }); 
      } 
     }); 

     // this is to resize padding-right when window resizes 
     window.onresize =()=>{ 
      this.setState({}); 
     }; 
    } 

    // This function sets the style and more importantly, padding-right 
    getStyle() { 
     if (document.getElementById(this.props.componentId) && document.getElementById('popoverTrigger')) { 
      const offsetRight = document.getElementById(this.props.componentId).offsetWidth - document.getElementById('popoverTrigger').offsetLeft - 15; 
      return (
       {display: 'inline-block', position: 'absolute', 'paddingRight': offsetRight + 'px'} 
      ); 
     } 
     return (
      {display: 'inline-block', position: 'absolute'} 
     ); 
    } 

    overlayOnClick() { 
     this.setState({ 
      showPopover: !(this.state.showPopover) 
     }); 
    } 

    render() { 
     const customPopover = (props) => { 
      return (
       {/* The reason why Popover is wrapped by another 
        invisible Popover is so that we can customize 
        the arrowOffsetTop, it's sketchy... */} 
       <div id="customPopover"> 
        <Popover style={{'visibility': 'hidden', 'width': '100%'}}> 
         <Popover {...props} arrowOffsetTop={props.arrowOffsetTop + 30} id={this.props.PopoverId} title={this.props.PopoverTitle} style={{'marginLeft': '25px', 'marginTop': '-25px', 'visibility': 'visible'}}> 
          {this.props.PopoverContent} 
         </Popover> 
        </Popover> 
       </div> 
      ); 
     }; 

     return (
      <div id="popoverTrigger" style={this.getStyle()}> 
       <a bsStyle="default" className="btn btn-default btn-circle" onClick={this.overlayOnClick.bind(this)} role="Button" tabIndex={13}> 
        <div id="info-button" className="btn-circle-text">?</div> 
       </a> 
       <Overlay 
        show={this.state.showPopover} 
        placement="right" 
        onHide={()=>{this.setState({showPopover: false});}} 
        container={this}> 
        {customPopover(this.props)} 
       </Overlay> 
      </div> 
     ); 
    } 
} 

最后,这是围绕着繁重的工作,因为它的代码修复一个很大的量,你也许能感觉到你的网站是由一点点放缓因为有4个事件监听器。最好的解决方案是告诉Bootstrap来解决这个问题...