React-Modal:单击React-DatePicker时如何将模态到自动扩展? (附加代码)

发布于 2025-02-13 18:38:35 字数 1893 浏览 3 评论 0原文

单击React-DatePicker时,如何将模式转换为自动扩展?模态最初适合,但是当您单击日期字段和React-datepicker显示日历时,“ React-Mododal”对话框不会自动扩展?

前:

单击日期:

代码:

import React, { useState } from 'react';
import Modal from 'react-modal';
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";

const customStyles = {
  content: {
    top: '50%',
    left: '50%',
    right: 'auto',
    bottom: 'auto',
    marginRight: '-50%',
    transform: 'translate(-50%, -50%)',
  },
};

export default function TestPage2() {
  const [modalIsOpen, setIsOpen] = React.useState(false);
  const [startDate, setStartDate] = useState(new Date());

  function openModal() {
    setIsOpen(true);
  }

  function closeModal() {
    setIsOpen(false);
  }

  return (
    <div>
      <button onClick={openModal}>Open Modal</button>
      <Modal
        isOpen={modalIsOpen}
        onRequestClose={closeModal}
        contentLabel="Example Modal"
        style={customStyles}
      >
        <h3>Prior to Date Picker</h3>
        <label htmlFor="Checkin Date">Checkin Date</label>
        <DatePicker
          selected={startDate}
          // wrapperClassName="datePicker"
          // className="form-control"
          dateFormat="d MMMM yyyy"
          name="checkinDate"
          onChange={(date, event) => {
            if (date) {
              setStartDate(date)
            }
          }}
          />
          <h3>After Date Picker</h3>
      </Modal>
    </div>
  );
}

How to get modal to auto-expand when react-datepicker is clicked? Modal fits initially, but then when you click on the date field and the react-datepicker shows the calendar, the react-modal dialog does not auto-expand?

Before:
enter image description here

Ater clicking date:
enter image description here

Code:

import React, { useState } from 'react';
import Modal from 'react-modal';
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";

const customStyles = {
  content: {
    top: '50%',
    left: '50%',
    right: 'auto',
    bottom: 'auto',
    marginRight: '-50%',
    transform: 'translate(-50%, -50%)',
  },
};

export default function TestPage2() {
  const [modalIsOpen, setIsOpen] = React.useState(false);
  const [startDate, setStartDate] = useState(new Date());

  function openModal() {
    setIsOpen(true);
  }

  function closeModal() {
    setIsOpen(false);
  }

  return (
    <div>
      <button onClick={openModal}>Open Modal</button>
      <Modal
        isOpen={modalIsOpen}
        onRequestClose={closeModal}
        contentLabel="Example Modal"
        style={customStyles}
      >
        <h3>Prior to Date Picker</h3>
        <label htmlFor="Checkin Date">Checkin Date</label>
        <DatePicker
          selected={startDate}
          // wrapperClassName="datePicker"
          // className="form-control"
          dateFormat="d MMMM yyyy"
          name="checkinDate"
          onChange={(date, event) => {
            if (date) {
              setStartDate(date)
            }
          }}
          />
          <h3>After Date Picker</h3>
      </Modal>
    </div>
  );
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

深海夜未眠 2025-02-20 18:38:36

将以下属性添加到CustomStyles中的内容对象中:

 overflow: 'hidden'

并更改React-DatePicker-Popper类的属性值:

.react-datepicker-popper {
  position: static!important;
  transform: none!important;
}

codesandbox: https://codesandbox.io/s/awesome-feather-mj81tz

add the following property to your content object inside customStyles:

 overflow: 'hidden'

and change the property values of react-datepicker-popper class :

.react-datepicker-popper {
  position: static!important;
  transform: none!important;
}

codesandbox: https://codesandbox.io/s/awesome-feather-mj81tz

与风相奔跑 2025-02-20 18:38:36

几周前,我完全遇到了同一问题。我正在寻找一个简单的修复程序,但我没有找到一个。我所做的是将datepicker分为2个组件(+ redux)。

  1. 是您的输入&lt; datePicker/&gt;

  1. 是您的浮动日期选择器&lt; datePickerFloatingItem/&gt;

datePicker

datePicker只是输入字段,这就是您可以在整个React WebApp中使用的组件。这里最大的变化是,您需要与调度员一起执行动作以显示浮动物品。此外,您需要确定datepicker的X和Y坐标,以将浮动物品放置在正确的位置。

这是datePicker组件的外观(我已经删除了逻辑代码以不使所有人感到困惑):

class DatetimePicker extends React.Component<IDatetimePickerProps, IDatetimePickerState> {

    public componentDidMount() {
        this.updateDate(this.props.date);
        window.addEventListener("resize", this.updateDimensions);
    }

    public componentWillUnmount() {
        // display the floating datepicker even when resizing the window
        window.removeEventListener("resize", this.updateDimensions);
    }

    ///
    /// LOGIC CODE (deleted)
    ///

    private showCalendar = (): void => {
        const { date, key } = this.state;
        const { dispatch } = this.props;
        const { showFloating } = this.props.datePickerState

        if (!showFloating) {
            this.createOutsideClickEvent();
            if (date) {
                this.updateDate(date);
            }
        } else {
            this.removeOutsideClickEvent();
        }

        var boundingRect = document.getElementById(key)?.getBoundingClientRect();
        if (boundingRect) {
            dispatch(updateDatepickerData({ updateDate: this.updateDate, showFloating: true, date, positionX: boundingRect.left, positionY: boundingRect.top + boundingRect.height, key }))
        }
    }

    private updateDimensions = (): void => {
        const { dispatch } = this.props;
        const { date, showFloating } = this.props.datePickerState;
        const { key } = this.state;

        var boundingRect = document.getElementById(key)?.getBoundingClientRect();
        if (boundingRect && this.props.datePickerState.key === key) {
            dispatch(updateDatepickerData({ positionX: boundingRect.left, positionY: boundingRect.top + boundingRect.height, date, showFloating }))
        }
    }


    public render(): React.ReactNode {
        const { input, wrapperRef, key } = this.state;
        const { style, disabled, className, onClick, styleWrapper, icon } = this.props;

        return <span className="datetimepicker" ref={wrapperRef} onClick={onClick} style={styleWrapper}>
            <Input
                className={`datetimepicker__input ${className}`}
                value={input}
                onChange={this.updateInput}
                getFocus={this.disableErrorView}
                getBlur={this.textInputLostFocus}
                rightButtonClicked={this.showCalendar}
                style={style}
                id={key}
                icon={icon}
                disabled={disabled}
            />
        </span>
    }
}

datePickerFloingItem,

您只需要在应用程序中将datePickerFloingItem放置在您的应用程序中即可。
最好将其定位在app.js(root组件)上。

具有位置也很重要:父元素的相对定义位置:datePickerFloingItem的固定。现在,您可以使用top:左:带有datePicker的坐标

,这就是datePickerFloingItem的样子(我还删除了不必要的代码)为了保持更容易理解)

interface IDatepickerFloatingItemStateProps {
    date: Date
    showFloating: boolean
    positionX?: number
    positionY?: number
}

class DatepickerFloatingItem extends React.Component<IDatepickerFloatingItemProps, IDatepickerFloatingItemState> {

    private clickedFloatingDatepicker = (event: React.MouseEvent<HTMLSpanElement>): void => event.preventDefault()
    private updateDate = (date?: Date, closeFloating?: boolean): void => {
        const { dispatch } = this.props;

        dispatch(updateDatepickerDate(date ? date : new Date()))
        if (closeFloating) dispatch(updateDatepickerShowFloating(!closeFloating))
    }

    public render(): React.ReactNode {
        const { showFloating, date, positionX, positionY } = this.props;
        const { datepickerView } = this.state;

        return <span className={`datetimepicker__floating ${showFloating ? "show" : ""}`} onClick={this.clickedFloatingDatepicker} style={{ top: `${positionY}px`, left: `${positionX}px` }}>
            <DateCalendar datepickerView={datepickerView} date={date} updateDate={this.updateDate} />
        </span>
    }
}

function mapStateToProps(applicationState: ApplicationState): IDatepickerFloatingItemStateProps {
    return {
        date: applicationState.datepicker.date,
        showFloating: applicationState.datepicker.showFloating,
        positionX: applicationState.datepicker.positionX,
        positionY: applicationState.datepicker.positionY
    }
}

export default connect(mapStateToProps)(DatepickerFloatingItem)

Redux,

我不得不将一些东西移到Redux商店,以确保 floatingdatepicker 以及 datepicker 有机会以某种方式交流

我的redux商店很简单:

import { Action, Reducer } from 'redux';

export interface DatepickerState {
    date: Date
    showFloating: boolean
    positionX?: number
    positionY?: number
    updateDate?: (date?: Date) => void
}

export const UPDATE_DATEPICKER_SHOWFLOATING = "UPDATE_DATEPICKER_SHOWFLOATING";
export const UPDATE_DATEPICKER_DATA = "UPDATE_DATEPICKER_DATA";
export const UPDATE_DATEPICKER_DATE = "UPDATE_DATEPICKER_DATE";

export interface UpdateDatepickerShowFloating {
    type: "UPDATE_DATEPICKER_SHOWFLOATING"
    showFloating: boolean
}

export interface UpdateDatepickerDate {
    type: "UPDATE_DATEPICKER_DATE"
    date: Date
}

export interface UpdateDatepickerData {
    type: "UPDATE_DATEPICKER_DATA"
    state: DatepickerState
}

type KnownAction = UpdateDatepickerShowFloating | UpdateDatepickerData | UpdateDatepickerDate

const unloadedState: DatepickerState = { updateDate: () => { }, date: new Date(), showFloating: false, showTime: false, positionX: 0, positionY: 0 }

export const reducer: Reducer<DatepickerState> = (state: DatepickerState | undefined, incomingAction: Action): DatepickerState => {

    if (state === undefined) {
        return unloadedState;
    }

    const action = incomingAction as KnownAction;

    switch (action.type) {
        case UPDATE_DATEPICKER_SHOWFLOATING:
            return { ...state, showFloating: action.showFloating }
        case UPDATE_DATEPICKER_DATE:
            setTimeout(() => { if (state.updateDate) state.updateDate(action.date) }, 1)
            return { ...state, date: action.date }
        case UPDATE_DATEPICKER_DATA:
            return { ...state, ...action.state }
        default:
            break;
    }

    return state;
}

正如您在图像上所看到的那样,它实际上是在模态内工作:

我知道这种方法很耗时,但我仍然希望它仍然对您有所帮助,我也希望您的眼睛不要看到基于班级的组件。

I exactly faced the same issue a few weeks ago. I was looking for a easy fix but I' didn't found one. What I did is to split up the Datepicker into 2 components (+ redux).

  1. Is your input <Datepicker />

enter image description here

  1. Is your floating date picker <DatepickerFloatingItem/>

enter image description here

Datepicker

The datepicker is simply the input field and that's the component you can use throughout your react webapp. The biggest change here is that you need to run an action with the dispatcher to show the floating item. Additionally you need to determine the X and Y coordinates of your Datepicker to place the Floating Item at the correct spot.

Here is how the Datepicker component could look like (I've deleted the logic code to not confuse everyone):

class DatetimePicker extends React.Component<IDatetimePickerProps, IDatetimePickerState> {

    public componentDidMount() {
        this.updateDate(this.props.date);
        window.addEventListener("resize", this.updateDimensions);
    }

    public componentWillUnmount() {
        // display the floating datepicker even when resizing the window
        window.removeEventListener("resize", this.updateDimensions);
    }

    ///
    /// LOGIC CODE (deleted)
    ///

    private showCalendar = (): void => {
        const { date, key } = this.state;
        const { dispatch } = this.props;
        const { showFloating } = this.props.datePickerState

        if (!showFloating) {
            this.createOutsideClickEvent();
            if (date) {
                this.updateDate(date);
            }
        } else {
            this.removeOutsideClickEvent();
        }

        var boundingRect = document.getElementById(key)?.getBoundingClientRect();
        if (boundingRect) {
            dispatch(updateDatepickerData({ updateDate: this.updateDate, showFloating: true, date, positionX: boundingRect.left, positionY: boundingRect.top + boundingRect.height, key }))
        }
    }

    private updateDimensions = (): void => {
        const { dispatch } = this.props;
        const { date, showFloating } = this.props.datePickerState;
        const { key } = this.state;

        var boundingRect = document.getElementById(key)?.getBoundingClientRect();
        if (boundingRect && this.props.datePickerState.key === key) {
            dispatch(updateDatepickerData({ positionX: boundingRect.left, positionY: boundingRect.top + boundingRect.height, date, showFloating }))
        }
    }


    public render(): React.ReactNode {
        const { input, wrapperRef, key } = this.state;
        const { style, disabled, className, onClick, styleWrapper, icon } = this.props;

        return <span className="datetimepicker" ref={wrapperRef} onClick={onClick} style={styleWrapper}>
            <Input
                className={`datetimepicker__input ${className}`}
                value={input}
                onChange={this.updateInput}
                getFocus={this.disableErrorView}
                getBlur={this.textInputLostFocus}
                rightButtonClicked={this.showCalendar}
                style={style}
                id={key}
                icon={icon}
                disabled={disabled}
            />
        </span>
    }
}

DatepickerFloatingItem

You only need to position the DatepickerFloatingItem once in your application.
It's best to position it at App.js (the root component).

It's also important to have position: relative for the parent element and define position: fixed for the DatepickerFloatingItem. Now you can easily position your floating element using top: and left: with the coordinates of the Datepicker

And this is how the DatepickerFloatingItem could look like (I also removed the unnecessary code to keep it more understandable)

interface IDatepickerFloatingItemStateProps {
    date: Date
    showFloating: boolean
    positionX?: number
    positionY?: number
}

class DatepickerFloatingItem extends React.Component<IDatepickerFloatingItemProps, IDatepickerFloatingItemState> {

    private clickedFloatingDatepicker = (event: React.MouseEvent<HTMLSpanElement>): void => event.preventDefault()
    private updateDate = (date?: Date, closeFloating?: boolean): void => {
        const { dispatch } = this.props;

        dispatch(updateDatepickerDate(date ? date : new Date()))
        if (closeFloating) dispatch(updateDatepickerShowFloating(!closeFloating))
    }

    public render(): React.ReactNode {
        const { showFloating, date, positionX, positionY } = this.props;
        const { datepickerView } = this.state;

        return <span className={`datetimepicker__floating ${showFloating ? "show" : ""}`} onClick={this.clickedFloatingDatepicker} style={{ top: `${positionY}px`, left: `${positionX}px` }}>
            <DateCalendar datepickerView={datepickerView} date={date} updateDate={this.updateDate} />
        </span>
    }
}

function mapStateToProps(applicationState: ApplicationState): IDatepickerFloatingItemStateProps {
    return {
        date: applicationState.datepicker.date,
        showFloating: applicationState.datepicker.showFloating,
        positionX: applicationState.datepicker.positionX,
        positionY: applicationState.datepicker.positionY
    }
}

export default connect(mapStateToProps)(DatepickerFloatingItem)

Redux

I had to move some stuff to the Redux store to ensure that the FloatingDatePicker as well as the Datepicker have chance to communicate somehow

I've kept the redux store pretty straight forward:

import { Action, Reducer } from 'redux';

export interface DatepickerState {
    date: Date
    showFloating: boolean
    positionX?: number
    positionY?: number
    updateDate?: (date?: Date) => void
}

export const UPDATE_DATEPICKER_SHOWFLOATING = "UPDATE_DATEPICKER_SHOWFLOATING";
export const UPDATE_DATEPICKER_DATA = "UPDATE_DATEPICKER_DATA";
export const UPDATE_DATEPICKER_DATE = "UPDATE_DATEPICKER_DATE";

export interface UpdateDatepickerShowFloating {
    type: "UPDATE_DATEPICKER_SHOWFLOATING"
    showFloating: boolean
}

export interface UpdateDatepickerDate {
    type: "UPDATE_DATEPICKER_DATE"
    date: Date
}

export interface UpdateDatepickerData {
    type: "UPDATE_DATEPICKER_DATA"
    state: DatepickerState
}

type KnownAction = UpdateDatepickerShowFloating | UpdateDatepickerData | UpdateDatepickerDate

const unloadedState: DatepickerState = { updateDate: () => { }, date: new Date(), showFloating: false, showTime: false, positionX: 0, positionY: 0 }

export const reducer: Reducer<DatepickerState> = (state: DatepickerState | undefined, incomingAction: Action): DatepickerState => {

    if (state === undefined) {
        return unloadedState;
    }

    const action = incomingAction as KnownAction;

    switch (action.type) {
        case UPDATE_DATEPICKER_SHOWFLOATING:
            return { ...state, showFloating: action.showFloating }
        case UPDATE_DATEPICKER_DATE:
            setTimeout(() => { if (state.updateDate) state.updateDate(action.date) }, 1)
            return { ...state, date: action.date }
        case UPDATE_DATEPICKER_DATA:
            return { ...state, ...action.state }
        default:
            break;
    }

    return state;
}

And as you can see at the image, it's actually working inside a modal:
enter image description here

I know this approach is pretty time consuming, but still I hope it was still helping you somehow and I also hope your eyes don't burn from seeing class based components.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文