将DHTMLX Scheduler组件与React JS库一起使用教程

dhtmlxScheduler是一个类似于Google日历的JavaScript日程安排控件,日历事件通过Ajax动态加载,支持通过拖放功能调整事件日期和时间。事件可以按天,周,月三个种视图显示。

本文介绍了dhtmlxScheduler v5.3各小版本更新内容集合,请查看文章内容了解详细信息。

我们继续进行一系列教程,致力于将我们的Web应用程序组件与不同的客户端框架进行集成。查阅我们有关将DHTMLX Scheduler与流行的基于React JS组件的库一起使用的新分步指南。

在这里,您将学习如何:

 

  • 创建一个基本的React Scheduling应用程序
  • 通过自定义功能扩展事件日历功能
  • 使其能够实时聆听并响应用户的操作

在深入探讨该主题之前,我们邀请您在我们的React Scheduler GitHub存储库上查看完整的演示。

 

如何开始

我们的第一步是初始化应用程序结构。为此,我们将使用创建React应用程序工具。您可以在本文中找到有关它的其他信息。

要创建一个应用程序,请运行以下命令:

npx create-react-app scheduler-react

然后,我们进入app文件夹并使用以下命令运行该应用程序:

cd scheduler-react
yarn start (if you use yarn)
npm start (if you use npm)

现在我们的应用程序应该从http:// localhost:3000 /开始

React app

将DHTMLX Scheduler添加到React App
让我们从我们的Scheduler组件开始。
您需要做的第一件事是将DHTMLX Scheduler程序包添加到您的项目中。
可以通过npm或yarn添加它的免费版本:

yarn add dhtmlx-scheduler (for yarn)
or
npm install dhtmlx-scheduler (for npm)

然后,创建src / components / Scheduler文件夹。在这里,我们将为DHTMLX Scheduler添加一个React Component包装器。
创建Scheduler.js文件并打开它:

{{ src/components/Scheduler/Scheduler.js }}
import React, { Component } from 'react';
import 'dhtmlx-scheduler';
import 'dhtmlx-scheduler/codebase/dhtmlxscheduler_material.css';
 
const scheduler = window.scheduler;
 
export default class Scheduler extends Component {
    componentDidMount() {
        scheduler.skin = 'material';
        scheduler.config.header = [
            'day',
            'week',
            'month',
            'date',
            'prev',
            'today',
            'next'
        ];
 
        const { events } = this.props;
        scheduler.init(this.schedulerContainer, new Date(2020, 5, 10));
        scheduler.clearAll();
        scheduler.parse(events);
    }
 
    render() {
        return (
            <div
                ref={ (input) => { this.schedulerContainer = input } }
                style={ { width: '100%', height: '100%' } }
            ></div>
       );
    }
}

现在创建Scheduler.css文件并为scheduler-container添加样式:

{{ src/components/Scheduler/Scheduler.css }}
.scheduler-container {
    height: 100vh;
    width: 100vw;
}

最后,创建具有以下内容的index.js文件:

{{ src/components/Scheduler/index.js }}
import Scheduler from './Scheduler';
import './Scheduler.css';
export default Scheduler;

由于DHTMLX Scheduler是位于ReactJS世界之外的常规JS库,因此我们创建了包装器组件。装入组件后,我们将初始化DHTMLX Scheduler并将其附加到DOM。我们还可以使用通过props传递的数据来填充它。

 

请注意,由于DHTMLX Scheduler的免费版本没有析构函数,因此我们没有定义componentWillUnmount。这也意味着,如果我们在某个时候从React中删除了一个组件,则DHTMLX Scheduler的实例将保留在内存中,并在下次再次安装该组件时再次使用。

现在,将Scheduler添加到我们的App组件中。请注意,我们对此示例使用硬编码数据:

{{ src/App.js }}
import React, { Component } from 'react';
import Scheduler from './components/Scheduler';
import './App.css';
 
const data = [
    { start_date:'2020-06-10 6:00', end_date:'2020-06-10 8:00', text:'Event 1', id: 1 },
    { start_date:'2020-06-13 10:00', end_date:'2020-06-13 18:00', text:'Event 2', id: 2 }
];
 
class App extends Component {
    render() {
        return (
            <div>
                <div className='scheduler-container'>
                    <Scheduler events={data}/>
                </div>
            </div>
        );
    }
 }
 export default App;

如果我们现在运行该应用程序,我们应该在页面上看到一个带有初始事件的简单事件日历:

yarn start
or
npm start
基本React Scheduler

配置React Scheduler组件

让我们在React js事件日历中添加一些自定义功能。假设我们需要添加一个带有复选框的工具栏,该复选框将负责在小时刻度上切换时间格式。

我们可以使用hour_date配置和hour_scale模板更改时间格式。之后,我们需要使用渲染器以新格式重新绘制视图。让我们尝试在React中实现它。首先,让我们转到Scheduler组件,并为视图配置实现几个预设。

打开Scheduler.js,向其添加以下代码:

{{ src/components/Scheduler/Scheduler.js }}
   componentDidMount() {
        scheduler.skin = 'material';
        scheduler.config.header = [
            'day',
            'week',
            'month',
            'date',
            'prev',
            'today',
            'next'
        ];
        scheduler.config.hour_date = '%g:%i %A';
        scheduler.xy.scale_width = 70;
 
        const { events } = this.props;
        scheduler.init(this.schedulerContainer, new Date(2020, 5, 10));
        scheduler.clearAll();
        scheduler.parse(events);
    }
    shouldComponentUpdate(nextProps) {
        return this.props.timeFormatState !== nextProps.timeFormatState;
    }
 
    componentDidUpdate() {
        scheduler.render();
    }
 
    setTimeFormat(state) {
        scheduler.config.hour_date = state ? '%H:%i' : '%g:%i %A';
        scheduler.templates.hour_scale = scheduler.date.date_to_str(scheduler.config.hour_date);
    }

在这里,我们添加了componentDidUpdate处理程序(将在更新时重新绘制视图)和shouldComponentUpdate处理程序,在其中将确定是否需要更新视图。
并在render方法的开头添加对setTimeFormat函数的调用:

{{ src/components/Scheduler/Scheduler.js }}
      render() {
        const { timeFormatState } = this.props;
        this.setTimeFormat(timeFormatState);
        return (
            <div
                ref={ (input) => { this.schedulerContainer = input } }
                style={ { width: '100%', height: '100%' } }
            ></div>
        );
    }

现在,调度程序将以24小时格式显示时间。当hour_date属性和hour_scale模板更改时,我们需要调用视图的更新。

让我们添加用于更改时间格式的UI。我们将使用一个简单的工具栏和切换器。
创建工具栏组件:

{{ src/components/Toolbar/index.js }}
import Toolbar from './Toolbar';
import './Toolbar.css';
export default Toolbar;
{{ src/components/Toolbar/Toolbar.js }}
import React, { Component } from 'react';
export default class Toolbar extends Component {
    handleTimeFormatStateChange = (e) => {
        if (this.props.onTimeFormatStateChange) {
            this.props.onTimeFormatStateChange(e.target.checked)
        }
    }
    render() {
        return (
            <div className='time-format-section'>
                <label className='time-format-chkbx'>
                    Time format: 
                    <input type='checkbox'
                        checked={ this.props.timeFormatState }
                        onChange={ this.handleTimeFormatStateChange }
                    />
                    <div className='chkbx-text'></div>
                </label>
            </div>
        );
    }
}
{{ src/components/Toolbar/Toolbar.css }}
.tool-bar {
    background: #ededed;
    height: 40px;
    line-height: 14px;
    padding: 5px 10px;
    text-align: center;
    padding-left: 60px;
}
 
.time-format-chkbx {
    display: inline-flex;
    padding-top: 10px;
    font-family: Roboto,Arial;
    user-select: none;
    font-weight: 500;
    font-size: 20px;
    color: rgba(0,0,0,.75);
}
 
.time-format-chkbx input {
    position: absolute;
    z-index: -1;
    opacity: 0;
    margin: 10px 0 0 20px;
}
.chkbx-text {
    position: relative;
    cursor: pointer;
    user-select: none;
    font-weight: 800;
    font-size: 20px;
    line-height: 30px;
    font-family: Roboto,Arial;
    margin-left: 10px;
}
.chkbx-text:before {
    content: '12h';
    text-align: right;
    padding: 0 10px;
    position: absolute;
    top: -8px;
    left: 0;
    width: 60px;
    height: 30px;
    border-radius: 15px;
    background: #CDD1DA;
    box-shadow: inset 0 2px 3px rgba(0,0,0,.2);
    transition: .2s;
}
.chkbx-text:after {
    content: '';
    position: absolute;
    top: -6px;
    left: 2px;
    width: 25px;
    height: 25px;
    border-radius: 15px;
    background: #FFF;
    box-shadow: 0 2px 5px rgba(0,0,0,.3);
    transition: .2s;
}
.time-format-chkbx input:checked + .chkbx-text:before {
    content: '24h';
    color: white;
    text-align: left;
    background: #0288d1;
}
.time-format-chkbx input:checked + .chkbx-text:after {
    left: 53px;
}
.time-format-chkbx input:focus + .chkbx-text:before {
    box-shadow: inset 0 2px 3px rgba(0,0,0,.2), 0 0 0 3px rgba(2,136,209,.7);
}

并更新调度程序容器的高度:

{{ src/components/Scheduler/Scheduler.css }}
.scheduler-container {
    height: calc(100vh - 50px);
    width: 100vw;
}

在这里,我们添加了用于更改时间格式的复选框,并为父组件提供了onTimeFormatStateChange处理程序。现在,您需要将工具栏添加到App组件中:

{{ src/App.js }}
import Toolbar from './components/Toolbar';

以及用于更改事件的处理程序:

{{ src/App.js }}
  state = {
        currentTimeFormatState: true
    };
 
    handleTimeFormatStateChange = (state) => {
        this.setState({
            currentTimeFormatState: state
        });
    }

JSX:

{{ src/App.js }}
  render() {
        const { currentTimeFormatState } = this.state;
        return (
            <div>
                <div className="tool-bar">
                    <Toolbar
                        timeFormatState={currentTimeFormatState}
                        onTimeFormatStateChange={this.handleTimeFormatStateChange}
                    />
                </div>
                <div className='scheduler-container'>
                    <Scheduler
                        events={data}
                        timeFormatState={currentTimeFormatState}
                    />
                </div>
            </div>
        );
    }

因此,每次用户更改时间格式时,我们就有机会将更新后的状态传递给我们的React Scheduler:

带工具栏的React Scheduler

处理DHTMLX React Scheduler中所做的更改

 

现在,我们将展示如何捕获日历视图更改,然后将其传递到应用程序中的某处。
我们将使用dhtmlxScheduler事件捕获Scheduler的更改。
让我们看看如何在实践中做到这一点。打开src / components / Scheduler / Scheduler.js并添加以下方法:

{{ src/components/Scheduler/Scheduler.js }}
 initSchedulerEvents() {
        if (scheduler._$initialized) {
            return;
        }
 
        const onDataUpdated = this.props.onDataUpdated;
 
        scheduler.attachEvent('onEventAdded', (id, ev) => {
            if (onDataUpdated) {
                onDataUpdated('create', ev, id);
            }
        });
 
        scheduler.attachEvent('onEventChanged', (id, ev) => {
            if (onDataUpdated) {
                onDataUpdated('update', ev, id);
            }
        });
 
        scheduler.attachEvent('onEventDeleted', (id, ev) => {
            if (onDataUpdated) {
                onDataUpdated('delete', ev, id);
            }
        });
        scheduler._$initialized = true;
  }
     componentDidMount() {
        scheduler.skin = 'material';
        scheduler.config.header = [
            'day',
            'week',
            'month',
            'date',
            'prev',
            'today',
            'next'
        ];
        scheduler.config.hour_date = '%g:%i %A';
        scheduler.xy.scale_width = 70;
 
        this.initSchedulerEvents();
 
        const { events } = this.props;
        scheduler.init(this.schedulerContainer, new Date(2020, 5, 10));
        scheduler.clearAll();
        scheduler.parse(events);
    }

我们使用调度程序的全局实例,并且由于可以多次挂载它,因此需要确保仅添加一次事件侦听器。

 

为此,我们使用一个自定义的“ scheduler ._ $ initialized”标志。首次初始化调度程序时,未定义此标志,因此我们添加了事件侦听器并将此标志设置为`true`。这样,我们确保不再将事件侦听器附加到同一Scheduler实例。

这样,我们就可以捕获在Scheduler中所做的所有更改并将其发送到父组件。

我们需要捕获事件,为事件创建消息,并将这些消息置于本地状态。为此,请更新App组件:

{{ src/App.js }}
    state = {
        currentTimeFormatState: true,
        messages: []
    };
    addMessage(message) {
        const maxLogLength = 5;
        const newMessage = { message };
        const messages = [
            newMessage,
            ...this.state.messages
        ];
 
        if (messages.length > maxLogLength) {
            messages.length = maxLogLength;
        }
        this.setState({ messages });
    }
 
   logDataUpdate = (action, ev, id) => {
        const text = ev && ev.text ? ` (${ev.text})` : '';
        const message = `event ${action}: ${id} ${text}`;
        this.addMessage(message);
    }  

之后,创建一个组件,将在页面上显示以下消息:

{{ src/components/MessageArea/MessageArea.js }}
import React, { Component } from 'react';
 
export default class MessageArea extends Component {
    render() {
        const messages = this.props.messages.map(({ message }) => {
            return <li key={ Math.random() }>{message}</li>
        });
 
        return (
            <div className="message-area">
                <h3>Messages:</h3>
                <ul>
                    { messages }
                </ul>
            </div>
        );
    }
}
 
MessageArea.defaultProps = {
    messages: []
};
{{ src/components/MessageArea/index.js }}
import MessageArea from './MessageArea';
import './MessageArea.css';
export default MessageArea;

添加样式:

{{ src/components/MessageArea/MessageArea.css }}
.message-area {
    background: #ebebeb;
    height: 200px;
    overflow: auto;
    padding: 10px;
    box-sizing:border-box;
}
 
.message-area ul{
    margin: 0;
    padding: 0;
    list-style: none;
}
 
.message-area li:before {
    content: "\003e";
    padding-right: 10px;
}

并更新调度程序容器的高度:

{{ src/components/Scheduler/Scheduler.css }}
.scheduler-container {
    height: calc(100vh - 50px - 200px);
    width: 100vw;
}

最后,将此组件连接到App:
导入:

{{ src/App.js }}
import MessageArea from './components/MessageArea';

JSX:

render() {
        const { currentTimeFormatState, messages } = this.state;
        return (
            <div>
                <div className="tool-bar">
                    <Toolbar
                        timeFormatState={currentTimeFormatState}
                        onTimeFormatStateChange={this.handleTimeFormatStateChange}
                    />
                </div>
                <div className='scheduler-container'>
                    <Scheduler
                        events={data}
                        timeFormatState={currentTimeFormatState}
                        onDataUpdated={this.logDataUpdate}
                    />
                </div>
                <MessageArea
                    messages={messages}
                />
            </div>
        );
    }

因此,现在每次用户更改日历事件时,处理程序都会调用App组件并更新MessageArea,后者在页面上打印有关用户操作的信息。

 

如果运行该应用程序,我们将看到以下结果:

用消息来响应调度程序

我们希望我们的教程对您的项目有用。如果您遇到任何困难,请随时在下面的评论中向我们发送您的问题。

 

posted @ 2020-10-22 14:08  roffey  阅读(464)  评论(0编辑  收藏  举报