将焦点从父母传递给孩子(以及兄弟姐妹)

时间:2019-03-19 16:25:11

标签: javascript reactjs

我有一个搜索栏(父级),其中有3个子项-位置下拉列表,日历(日期选择器)和持续时间下拉列表。默认情况下,位置会选择为用户所在的位置。我希望将焦点更改为日期选择器,其中日历下拉列表在与第一个下拉列表(位置下拉列表)进行交互之后自动打开,并且从第二个输入到第三个输入也是如此。我该怎么做呢?

enter image description here

父母:

import React, { Component } from 'react';

import { Icon, Btn } from '@appearhere/bloom';

import Title from '../Title';
import LocationDropdown from '../LocationDropdown';
import AppearDateCalendar from '../AppearDateCalendar';
import DurationDropdown from '../DurationDropdown';

import css from './SegmentationBar.css';

import i18n from 'utils/i18n/i18n';

const t = i18n.withPrefix('client.apps.static.screens.home.header.segmentation');

type Props = {
  onLocationDropdownChange: Function,
  onDateChange: Function,
  onDurationChange: Function,
  onSubmit: Function,
  onMobileSearchClick: Function,
  fullSupport: boolean,
};

export default class SegmentationBar extends Component<Props> {
  render() {
    const {
      onLocationDropdownChange,
      onDateChange,
      onDurationChange,
      onSubmit,
      fullSupport,
    } = this.props;

    return (
      <div className={css.container}>
        <Title />
        {fullSupport && (
          <div className={css.barWrapper}>
            <div className={css.segmentationBar}>
              <LocationDropdown onDropdownChange={onLocationDropdownChange} />
              <AppearDateCalendar onDateChange={onDateChange} />
              <DurationDropdown onDropdownChange={onDurationChange} />
            </div>
            <div className={css.submitButton} onClick={onSubmit}>
              <Icon name="search" />
            </div>
          </div>
        )}
      </div>
    );
  }
}

孩子:

第一个下拉列表:

import React, { Component } from 'react';
import i18n, { getCurrentLocale } from 'utils/i18n/i18n';

import { Icon } from '@appearhere/bloom';

import locationOrder from './locationOrder.json';
import locations from './locations.json';

import css from './LocationDropdown.css';

const t = i18n.withPrefix('client.apps.static.screens.home.header.segmentation.location');

type Props = {
  onDropdownChange: Function,
};

type Location = {
  key: string,
  name: string,
  country: string,
  placeId: string,
  searchString: string,
  priority: number,
};

class LocationDropdown extends Component<Props> {
  componentDidMount() {
    const selectedCity = this.findCitiesForCountry(locationOrder[getCurrentLocale()][0])[0];
    this.props.onDropdownChange(selectedCity.searchString, selectedCity.placeId);
  }

  citySorting = (a: Location, b: Location): number => {
    if (a.priority > b.priority) return 1;
    if (a.priority < b.priority) return -1;
    if (a.name >= b.name) return 1;
    return -1;
  };

  findCitiesForCountry = (countryKey: string): Array<Location> =>
    locations
      .filter((location: Location): boolean => location.country === countryKey)
      .sort(this.citySorting);

  handleDropdownChange = (event: SyntheticInputEvent<EventTarget>) => {
    const city = locations.find(
      (location: Location): boolean => location.key === event.target.value,
    );
    this.props.onDropdownChange(city.searchString, city.placeId);
  };

  renderSelectOptions = (countryKey: string): React.Node => {
    const cities = this.findCitiesForCountry(countryKey);
    return cities.map((city: Location): React.Node => (
      <option key={city.key} value={city.key}>
        {city.name}
      </option>
    ));
  };

  renderSelectOptionGroups = (): React.Node =>
    locationOrder[getCurrentLocale()].map((countryKey: string): React.Node => (
      <optgroup key={countryKey} label={t(countryKey)}>
        {this.renderSelectOptions(countryKey)}
      </optgroup>
    ));

  render() {
    return (
      <div className={css.LocationDropdown}>
        <div className={css.searchIcon}>
          <Icon name="search" />
        </div>
        <select role="listbox" className={css.locationSelect} onChange={this.handleDropdownChange}>
          {this.renderSelectOptionGroups()}
        </select>
      </div>
    );
  }
}

第二个输入: 日历:

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import i18n from 'utils/i18n/i18n';

import { DayPicker } from '@appearhere/bloom';
import moment from 'utils/moment/moment';
import cx from 'classnames';

import css from './AppearDateCalendar.css';

const t = i18n.withPrefix('client.apps.static.screens.home.header.segmentation.calendar');

type Props = {
  onDateChange: Function,
};

type State = {
  calendarOpen: boolean,
  month: moment,
  day: ?moment,
};

export default class AppearDateCalendar extends Component<Props, State> {
  state = {
    calendarOpen: false,
    month: moment(),
    day: undefined,
  };

  componentDidMount() {
    document.addEventListener('mousedown', this.handleClickOutside);
  }

  componentWillUnmount() {
    document.removeEventListener('mousedown', this.handleClickOutside);
  }

  handleClickOutside = (event: SyntheticMouseEvent<EventTarget>) => {
    const currentNode = ReactDOM.findDOMNode(this);
    if (currentNode && !currentNode.contains(event.target)) {
      this.setState({ calendarOpen: false });
    }
  };

  handleCalendarClick = () => {
    this.setState({ calendarOpen: !this.state.calendarOpen });
  };

  handleMonthChange = (_event: any, newMonth: moment) => {
    this.setState({ month: newMonth });
  };

  handleDaySelect = (_event, day: moment) => {
    this.props.onDateChange(day);
    this.setState({ day, calendarOpen: false });
  };

  dateDisplayText = (): string => {
    if (this.state.day) return this.state.day.format('Do MMM, YY');
    return t('choose_date');
  };

  render() {
    return (
      <div className={cx(css.appearDateCalendar, this.state.calendarOpen ? css.focused : '')}>
        <div onClick={this.handleCalendarClick}>
          <h5 className={css.heading}>{t('heading')}</h5>
          <p className={css.dateText}>{this.dateDisplayText()}</p>
        </div>
        {this.state.calendarOpen && (
          <div className={css.calendarDropdown}>
            <DayPicker
              month={this.state.month}
              onInteraction={this.handleDaySelect}
              onMonthChange={this.handleMonthChange}
            />
          </div>
        )}
      </div>
    );
  }
}

第三个下拉列表: 持续时间:

import React, { Component } from 'react';
import i18n from 'utils/i18n/i18n';

import css from './DurationDropdown.css';

import durations from './durations.json';

const t = i18n.withPrefix('client.apps.static.screens.home.header.segmentation.duration');

type Props = {
  onDropdownChange: Function,
};

type Duration = {
  name: string,
  maxDuration: number,
  highValue: boolean,
};

export default class DurationDropdown extends Component<Props> {
  handleDropdownChange = (event: SyntheticInputEvent<EventTarget>) => {
    const durationIndex = event.target.value;
    const duration = durations[durationIndex];
    this.props.onDropdownChange(duration.maxDuration, duration);
  };

  renderDurationOptions = (): React.Node =>
    durations.map((duration: Duration, index: number): React.Node => (
      <option key={duration.name} value={index}>
        {t(duration.name)}
      </option>
    ));

  render() {
    return (
      <div className={css.durationDropdown}>
        <h5 className={css.heading}>{t('heading')}</h5>
        <select role="listbox" className={css.durationSelect} onChange={this.handleDropdownChange}>
          <optgroup label={t('booking_duration')}>{this.renderDurationOptions()}</optgroup>
        </select>
      </div>
    );
  }
}

1 个答案:

答案 0 :(得分:0)

您应该阅读有关React引用的信息:http://parseplatform.org/Parse-SDK-JS/api/2.2.1/Parse.Query.html#select

您可以为每个输入创建一个ref,并将其从您的父级传递给3个孩子,并在下拉菜单处理程序中使用ref.current.focus()