如何在 React 中正确捕获 Materialize-CSS datepicker 值?

Posted

技术标签:

【中文标题】如何在 React 中正确捕获 Materialize-CSS datepicker 值?【英文标题】:How do I correctly capture Materialize-CSS datepicker value in React? 【发布时间】:2019-05-19 10:26:52 【问题描述】:

我希望在我的 React 组件中使用 materialize-css 创建一个带有 datepicker 的表单。这个表单捕获的字段不多,结构相当简单。返回的表单如下所示:

<form onSubmit=this.handleSubmit.bind(this)>
     <div className="container">
          <div className="card grey lighten-3">
               <div className="card-content black-text">
                    <span className="card-title">
                            <input placeholder="Event Name"
                                    name="name" value=this.state.name
                                    onChange=this.handleStateChange.bind(this)/>
                    </span>
                    <input name="description" placeholder="Description"
                                      value=this.state.description
                                      onChange=this.handleStateChange.bind(this)/>
                    <input name="image" placeholder="Image URL"
                                      value=this.state.image
                                      onChange=this.handleStateChange.bind(this)/>
                    <input placeholder="Start Date"
                                className="datepicker" name="startDate" value=this.state.startDate
                                onSelect=this.handleStateChange.bind(this)/>
                </div>
                <div class="card-action">
                    <div className="row">
                        <span>
                           <div className="col s3">
                               <input className="btn light-blue accent-1" type="submit" value="Submit"/>
                           </div>
                           <div className="col s3">
                               <a className="btn grey" onClick=this.handleExpand.bind(this)>Cancel</a>
                           </div>
                       </span>
                   </div>
               </div>
           </div>
       </div>
   </form>

状态变化用

处理
handleStateChange(item) 
    this.setState([item.target.name]: item.target.value);

我已经调用了AutoInit 来初始化我的日期选择器

M.AutoInit();

我尝试使用onChange 而不是onSelect 来管理日期选择器状态更改,但它似乎没有捕获该事件。使用onSelect,如果我选择一个日期然后重新打开日期选择器,有时会捕获日期。

我也尝试过使用一些alternate initialization methods for the datepicker 无济于事。

如何使用给定的设置正确捕获输入更改?

【问题讨论】:

不相信有onSelect - 你的意思是onChange 吗? 我已经尝试了几个星期,但一切都是徒劳的,即使我想知道它的答案。 @SakoBu 我在问题中提到了这一点。似乎都没有提供所需的行为 哦,我也有同样的问题...这真的很难...对于时间选择器,我可以使用 onBlur 来完成...但不能使用 datepicker Check this repository in this 我尝试制作 Materialize CSS 提供的所有 javascript 组件 - github.com/GermaVinsmoke/Reactize 【参考方案1】:

您好,希望这会对某人有所帮助 -

组件的情况是默认的 onChange 方法返回日期 (2019-08-01) 而不是元素的事件处理程序对象。为了解决这个问题,我们需要在 onChange 方法中创建一个对象,该对象模仿事件处理程序的 target.id 和 target.value

等其他组件正常工作。看看吧:

这是组件的外观:

            <DatePicker
                label="myDate"
                value=state.myDate
                id="myDate"
                onChange=(newDate) => 
                    handleChange(
                        target: 
                            id: "myDate",
                            value: newDate
                        
                    )
                 />

这里是完整的代码:

import React,  useState, useEffect  from "react";
import "materialize-css/dist/css/materialize.min.css";
import "materialize-css/dist/js/materialize.min.js";
import  DatePicker  from "react-materialize";

const PickDate = (props) => 

    const [state, setState] = useState(myName: "Mags", myDate: "2019-08-01");

    const handleChange = (e) => 
        const key = e.target.id;
        const val = e.target.value;

        const newState = ...state;
        newState[key] = val;
        setState(newState);
    

    return (
        <React.Fragment>
            <input type="text" value=state.myName id="myName" onChange=handleChange />
            <DatePicker
                label="myDate"
                value=state.myDate
                id="myDate"
                onChange=(newDate) => 
                    handleChange(
                        target: 
                            id: "myDate",
                            value: newDate
                        
                    )
                 />
        </React.Fragment>
    );


export default PickDate;

附言。这使用 React Hooks - 但它也适用于普通类。

【讨论】:

【参考方案2】:

在研究了所有关于 React 生命周期的星期六之后。我得到了这个解决方案:

组件的使用:

    <DatePicker label="Fecha" value=this.state.formSchedule.start 
onChange=(date) => 
    this.state.formSchedule.start = date;
    this.setState( formSchedule: this.state.formSchedule );
/>

类 DatePicker.tsx:

    import * as React from 'react';
import Materialize from 'materialize-css';
import moment from 'moment'
import 'moment/locale/es'
import  any  from 'prop-types';


interface IState 
  value: any;


interface IProps 
  label: any;
  format: any;
  onChange: any;
  formatMoment: any;


export default class DatePicker extends React.Component<IProps, IState> 

  static defaultProps = 
    label: "Fecha",
    value: new Date(),
    format: 'ddd d, mmm',
    formatMoment: 'ddd D, MMM'
  

  constructor(props: any) 
    super(props);
    this.componentWillReceiveProps(props);
  

  componentWillReceiveProps(props) 
    this.state = 
      value: props.value
    ;
  

  render() 
    return <div className="input-field col s6">
      <i className="material-icons prefix">date_range</i>
      <input id="date" type="text" className="datepicker queso"
        value=moment(this.state.value).locale('es').format(this.props.formatMoment)
      />
      <label className="active" htmlFor="date">this.props.label</label>
    </div>;
  


  componentDidMount() 
    var context = this;

    var elems = document.querySelectorAll('.queso');
    Materialize.Datepicker.init(elems, 
      defaultDate: new Date(),
      format: this.props.format,
      container: 'body',
      onSelect: function (date) 
        context.setState( value: context.state.value );
        context.props.onChange(date);
      ,
      autoClose: true
     as Partial<any>);

  

【讨论】:

伙计,这在 react 和 redux 的情况下也很有效。谢谢【参考方案3】:

谢谢卢卡斯,你的回答也帮助了我。

这是我的解决方案 - 没有 redux 或 props,只有具有自己状态的类组件

import React,  Component  from "react";
import "./calendar.css";
import Materialize from "materialize-css";
import moment from "moment";

class Calendar extends Component 
  componentDidMount() 
    var context = this;

    var elems = document.querySelectorAll(".dateset");
    Materialize.Datepicker.init(elems, 
      defaultDate: new Date(),
      format: this.state.format,
      container: "body",
      onSelect: function(date) 
        context.setState( value: context.state.value );
        console.log(date); // Selected date is logged
      ,
      autoClose: true
    );
  

  state = 
    value: new Date(),
    format: "ddd d, mmm",
    formatMoment: "ddd D, MMM"
  ;

  render() 
    return (
      <div className="input-field col s6">
        <i className="material-icons prefix">date_range</i>
        <input
          id="date"
          type="text"
          className="datepicker dateset"
          defaultValue=moment(this.state.value).format(
            this.state.formatMoment
          )
        />
      </div>
    );
  


export default Calendar;

【讨论】:

【参考方案4】:

已经添加的答案都没有帮助我,所以我决定以我的方式去做。 我没有将 Materialize 和 jQuery 安装到我的模块中,只是将它们添加到 index.html

当您单击输入字段时,日期选择器模式窗口将打开,并且有两个按钮 CANCEL 和 OK。我通过 jQuery 找到了 OK 按钮并添加了单击功能,该功能从输入字段中获取值并更新状态;

componentDidMount()
window.$(".datepicker-done").click(() => 
      var datepickerValue = window.$("#date-input").val();  // date-input it's 'id' on datepicker input

      this.setState( approxLastDay: datepickerValue );
    );

注意: datepickerValue 将采用字符串格式(例如“Aug 6, 2019”)

【讨论】:

【参考方案5】:

我有同样的问题,这是我的解决方案。

import React,  Component  from 'react'
import M from 'materialize-css';

class CreateReport extends Component 
    constructor(props) 
        super(props);
        this.state = 
            startDate: '',
            endDate: ''
        ;
        // refs for startDate, endDate
        this.startDate = React.createRef();
        this.endDate = React.createRef();
    
    componentDidMount() 
        var context = this;
        document.addEventListener('DOMContentLoaded', function () 
            var start = document.querySelectorAll('.datepicker');
            M.Datepicker.init(start, 
                format: "mm/dd/yyyy",
                autoClose: true,
                onClose: context.handleDate
            );
        );
    
    handleDate = () => 
        this.setState(
            startDate: this.startDate.current.value,
            endDate: this.endDate.current.value,
        )
        // console.log(this.state.startDate)
        // console.log(this.state.endDate)
    
    handleChange = (e) => 
        this.setState(
            [e.target.id]: e.target.value
        )
    
    handleSumbit = (e) => 
        e.preventDefault();
        console.log(this.state)
    
    render() 
        return (
            <div>
                <div className="container">
                    <form onSubmit=this.handleSumbit className="white col s12 m6">

                        <div className="row">
                            <div className="input-field col s3 offset-s2">
                                <label htmlFor="date">Start Date</label>
                                <input
                                    type="text"
                                    className="datepicker"
                                    id="startDate"
                                    onChange=this.handleChange
                                    value=this.state.startDate
                                    ref=this.startDate
                                />
                            </div>
                            <div className="input-field col s3 offset-s2">
                                <label htmlFor="date">End Date</label>
                                <input
                                    type="text"
                                    className="datepicker"
                                    id="endDate"
                                    onChange=this.handleChange
                                    value=this.state.endDate
                                    ref=this.endDate />
                            </div>
                        </div>
                        <div className="col s8 offset-s2 center-align">
                            <button className="btn pink lighten-1 z-depth-0 ">Sign Up</button>
                        </div>

                    </form>
                </div>
            </div >
        )
    

export default CreateReport

【讨论】:

【参考方案6】:

我做了一个不太优雅的解决方案,但它也有不少代码行。它似乎正在工作(经过数小时的调试!)。

我创建了一个名为 trouble 的 css 类,并将其应用于处理 DatePickerTimePicker 的所有字段。在初始化中,我创建了事件监听器来检查更改。当检测到更改时,它会调用 _valueTracker,并使其发送 redux 注意到的更新事件。

一件非常奇怪的事情是,如果我传入与 e.target.value 完全相同的值,它什么也不做。它必须是一串随机的东西,例如“UPDATE!”在这种情况下。我将此代码与物化初始化的其余部分一起使用。

const troubles = document.querySelectorAll(".trouble");
troubles.forEach((item) => 
  item.addEventListener("change", (e) => 
    e.target._valueTracker.setValue("UPDATE!");
  );
);

【讨论】:

顺便说一句:这有点像 hack,但它节省了我重写所有不同的日期和时间组件,这很简单。

以上是关于如何在 React 中正确捕获 Materialize-CSS datepicker 值?的主要内容,如果未能解决你的问题,请参考以下文章

React Native:如何安全地捕获用户的电话号码

如何正确使用带有 axios + react 的拦截器

如何在 React 应用程序中捕获 Firebase 通知?

React - 如何在 html5 中捕获全屏视频请求?

如何在 react-konva 中捕获视频的第一帧

如何使用 CKEditor 和 React JS 捕获 OnChange 事件