当前位置: 首页 > 知识库问答 >
问题:

ReactJS-自定义组件启动所有工具提示

齐栋
2023-03-14

我有一个自定义组件LocationSearch,它只是谷歌位置自动完成的包装。有时地址比输入框长,所以我实现了一个显示完整地址的工具提示。问题是,如果我在同一页面上有两个组件,并且我将鼠标悬停在其中一个输入框上,两个工具提示都会启动,因为页面上还有另一个LocationSearch组件。我怎么能只启动悬停的工具提示,而不启动其他所有工具提示?

我的LocationSearch组件如下所示:

export default class LocationSearch extends Component {
    constructor(props) {
        super(props);
        this.state = {
            addressSearch: this.props.value || '',
            address: {},
            tooltipKey: false
        };

        this.toggleTooltip = this.toggleTooltip.bind(this);
    }

    toggleTooltip() {
        let tooltipOpen = !this.state.tooltipOpen;
        if (!this.state.addressSearch) {
            tooltipOpen = false;
        }

        this.setState({
            tooltipOpen
        });
    }

    handleAddressSearch = (addressSearch) => {
        this.setState({
            addressSearch,
        });
    };

    handleSelect = (addressSearch) => {
        let scope = this;

        geocodeByAddress(addressSearch)
            .then(results => {
                let street_number, route, city, state, zip, country = "";
                if (results.length > 0) {
                    let result = results[0];
                    for (let i = 0; i < result.address_components.length; i++) {
                        let component = result.address_components[i];
                        for (let x = 0; x < component.types.length; x++) {
                            let type = component.types[x];
                            switch (type) {
                                case "street_number":
                                    street_number = component.long_name || '';
                                    break;
                                case "route":
                                    route = component.long_name || '';
                                    break;
                                case "locality":
                                    city = component.long_name;
                                    break;
                                case "administrative_area_level_1":
                                    state = component.short_name;
                                    break;
                                case "postal_code":
                                    zip = component.long_name;
                                    break;
                                case "country":
                                    country = component.long_name;
                                    break;
                            }
                        }
                    }

                    let address = scope.state.address;
                    if (street_number && route) {
                        address.address1 = street_number + ' ' + route;
                    } else {
                        address.address1 = '';
                    }
                    address.city = city;
                    address.state = state;
                    address.zip = zip;
                    address.country = country;
                    address.googlePlacesId = result.place_id;

                    scope.setState({
                        addressSearch: FormatAddress(address) // just formats a string version of the address object to display in the text box
                    });

                    getLatLng(results[0]).then(function (latLon) {
                        let date = new Date();
                        let url = `https://maps.googleapis.com/maps/api/timezone/json?location=${latLon.lat},${latLon.lng}&timestamp=${date.getTime() / 1000}&key=${GOOGLE_API_CONFIG.mapsKey}`;
                        axios.get(url)
                            .then(function (response) {
                                address.timezone = response.data.timeZoneId;
                                scope.props.handleSelect(address);
                            })
                            .catch(function (error) {
                                console.error("Timezone lookup error:", error);
                                address.timezone = 'US/Arizona';
                                scope.props.handleSelect(address);
                            });
                    })
                }
            })
            .catch(error => {
                console.error('Error', error);
            })
    };


    handleCloseClick = () => {
        this.setState({
            addressSearch: '',
            address: {},
            tooltipOpen: false
        });
    };

    handleError = (status, clearSuggestions) => {
        console.error('Error from Google Maps API', status); // eslint-disable-line no-console
        this.setState({errorMessage: status}, () => {
            clearSuggestions();
        });
    };

    render() {
        if (this.props.hidden) {
            return null;
        }

        return (
            <FormGroup>
                {this.props.label !== '' && (
                    <Label for="address">{this.props.label}</Label>
                )}

                <PlacesAutocomplete
                    onChange={this.handleAddressSearch}
                    value={this.state.addressSearch}
                    onSelect={this.handleSelect}
                    onError={this.props.handleError || this.handleError}
                    shouldFetchSuggestions={!!(this.state.addressSearch && this.state.addressSearch.length > 2)}
                >
                    {({getInputProps, suggestions, getSuggestionItemProps}) => {
                        return (
                            <div className="search-bar-container">
                                <div className="search-input-container" href="#" id="addressTooltip">
                                    <input
                                        {...getInputProps({
                                            placeholder: this.props.placeholder,
                                            className: "search-input"
                                        })}
                                        disabled={this.props.disabled}
                                    />
                                    {this.state.addressSearch && this.state.addressSearch.length > 0 && !this.props.disabled && (
                                        <button
                                            className="clear-button"
                                            onClick={this.handleCloseClick}
                                        >
                                            x
                                        </button>
                                    )}
                                </div>
                                <Tooltip placement="top" isOpen={this.state.tooltipOpen} target="addressTooltip" toggle={this.toggleTooltip}>
                                    {this.state.addressSearch ? this.state.addressSearch : ''}
                                </Tooltip>
                                {suggestions.length > 0 && (
                                    <div className="autocomplete-container">
                                        {suggestions.map(suggestion => {
                                            const className = classNames('suggestion-item', {
                                                'suggestion-item--active': suggestion.active,
                                            });

                                            return (
                                                /* eslint-disable react/jsx-key */
                                                <div
                                                    {...getSuggestionItemProps(suggestion, {className})}
                                                >
                                                    <strong>
                                                        {suggestion.formattedSuggestion.mainText}
                                                    </strong>{' '}
                                                    <small>
                                                        {suggestion.formattedSuggestion.secondaryText}
                                                    </small>
                                                </div>
                                            );
                                            /* eslint-enable react/jsx-key */
                                        })}
                                        <div className="dropdown-footer">
                                            <div>
                                                <img
                                                    src={require('../../assets/img/powered_by_google_default.png')}
                                                    className="dropdown-footer-image"
                                                />
                                            </div>
                                        </div>
                                    </div>
                                )}
                            </div>
                        );
                    }}
                </PlacesAutocomplete>
            </FormGroup>
        )
    }
}

实现两个LocationSearch组件的表单如下所示:

import LocationSearch from "../../../../components/locationsearch/LocationSearch";

export default class Addresses extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            address1: {},
            address1Str: '',
            address2: {},
            address2Str: '',
        }
    }

    handleAddress1Select = (address1) => {
        this.setState({
            address1,
            address1Str: FormatAddress(address1)
        })
    };

    handleAddress2Select = (address2) => {
        this.setState({
            address2,
            address2Str: FormatAddress(address2)
        })
    };

    render() {
        return (
            <div>
                <LocationSearch
                    label='Address 1'
                    placeholder='Street address...'
                    handleSelect={this.handleAddress1Select}
                    value={this.state.address1Str}
                />

                <LocationSearch
                    label='Address 2'
                    placeholder='Street address...'
                    handleSelect={this.handleAddress2Select}
                    value={this.state.address2Str}
                />
            </div>
        )
    }
}

这是其中一个地址字段上的工具提示屏幕截图。正如您所看到的,底部的另一个地址输入框显示未定义,当悬停在顶部的一个上时,两个工具提示都会启动。

有没有办法在组件的每个实例的LocationSearch状态中设置自定义工具提示字段?

共有1个答案

弘思聪
2023-03-14

这两个工具提示通过target=“addressTooltip”附加到相同的id——这也意味着有两个div具有相同的id——它们不是唯一的——不是有效的html。

如果需要多个

<div className="search-input-container" href="#" id={this.props.inputID}>

<Tooltip placement="top" isOpen={this.state.tooltipOpen} target={this.props.inputID} toggle={this.toggleTooltip}>

当然,还要通过propinputID

            <LocationSearch
                label='Address 1'
                placeholder='Street address...'
                handleSelect={this.handleAddress1Select}
                value={this.state.address1Str}

                inputID='first_id'
                key='first_key'
            />

            <LocationSearch
                label='Address 2'
                placeholder='Street address...'
                handleSelect={this.handleAddress2Select}
                value={this.state.address2Str}

                inputID='second_id'
                key='second_key'
            />

您应该为它们使用属性(如上所述)-它们都是同一节点的子节点-响应需求。

 类似资料:
  • 问题内容: 我正在尝试使用angular- ui的工具提示功能向用户显示特定字段无效,但是似乎只能在某些预定义的触发器上显示该工具提示。除了那些触发器外,还有什么方法可以触发工具提示? 例如: 问题答案: 这是一个把戏。 Twitter Bootstrap工具提示(Angular- UI依赖于此)具有一个选项,可以指定带有附加属性的触发事件,如中所示。这为您提供了一种以编程方式(使用Angular

  • 问题内容: 我基于Tkinter创建了一个应用程序,该应用程序使用Matplotlib绘制波形。我不知道如何更改Matplotlib工具栏按钮的工具提示(由于我的应用程序是捷克语,因此我需要翻译英文说明)。我还想更改/翻译或仅删除单击缩放或平移按钮时出现在工具栏面板旁边的说明(,)。 我发现了一些有关如何从工具栏添加或删除按钮的有用提示,但是没有找到有关自定义工具提示/描述的任何建议。我认为这与前

  • 问题内容: 我试图在组件的工具提示中显示多个图像,找到并实现了一个自定义,该自定义添加了所需的组件,如下所示: 但是,我所看到的只是一个小点,表明显示了工具提示,但是以某种方式忽略了大小。我会错过实现自定义工具提示的什么? 问题答案: 基本的“问题”是JToolTip 不是 设计为容器,只是偶然地是一个容器,因为JComponent是。对于Swing“非容器”,它的ui委托负责充当LayoutMa

  • 用法 对同时满足以下条件的元素使用工具提示: 具有交互性 主要是图形而非文本 (上图)可取 (上图)不可取 工具提示不同于悬浮卡片,后者用来显示图片和格式化的文本等更为丰富的信息。 工具提示也不同于ALT属性,后者用来提示静态图片的主旨。 (上图)可取 (上图)不可取 光标和键盘的工具提示 文本:Roboto Medium 10 sp 背景填充:90% 不透明度 工具提示动画 触摸屏UI的工具提示

  • 问题内容: 我一直在环顾四周,尝试各种不同的方法,但无法解决。是否可以在特定事件下隐藏angular-ui工具提示? 我想要做的是当有人将鼠标悬停在div上时显示一个工具提示,并在用户单击它时将其关闭,因为我将显示另一个弹出窗口。我使用自定义触发事件进行了尝试,但似乎无法正常工作。我做的: http://jsfiddle.net/3ywMd/ 工具提示必须在第一次单击时关闭,而不是在第二次单击时关

  • 问题内容: 我已经构建了自己的自定义react-bootstrap Popover组件: 该组件的呈现方式如下: 现在,我想向组件中添加自定义道具,例如:我的文字,并使用新道具在弹出框中设置一些内容,例如- 但随后我在浏览器中收到此警告: 警告:标签上的未知道具。从元素中删除这些道具。 现在,我想我可以删除零件并逐个插入所有原始道具,而无需自定义道具,但是这样我就失去了“淡入淡出”效果,这也是处理