React Bootstrap OverlayTrigger与触发器=“焦点”错误工作

时间:2016-08-05 16:05:00

标签: ios css twitter-bootstrap react-bootstrap

在iOS safari中,当触发外部时,触发=“焦点”的OverlayTrigger无法解除。这是我的代码:

<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>

我知道这是Bootstrap cuz的一个已知错误,这甚至不适用于iOS中的their own website,但有没有人知道任何解决方法?如果它不需要jQuery,那将是最好的,但jQuery解决方案是受欢迎的。感谢。

1 个答案:

答案 0 :(得分:1)

好的,既然没有其他人给我解决方法,我和同事一起解决了这个问题3天,我们想出了这个重要的解决方案:

问题:

使用触发器=&#34;焦点&#34;,在弹出窗口/工具提示外单击但不触及时,可以取消Bootstrap Popover / Tooltip。 Android浏览器显然会自动更改点击次数,因此在Android上运行良好。但是基于iOS Safari(iOS chrome,iOS firefox等)的iOS Safari和浏览器不能做到这一点。

THE FIX:

我们发现在React Bootstrap中,Overlay组件实际上允许您自定义何时显示Popover / Tooltip,因此我们基于Overlay构建了此组件InfoOverlay。要处理组件外部的点击,我们需要为Popover / Tooltip和窗口添加事件监听器,以处理“mousedown”和“mousedown”。并且&#39; touchstart&#39;。此外,此方法将使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解决这个问题......