1. 程式人生 > 實用技巧 >將DHTMLX Scheduler元件與React JS庫一起使用教程

將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 /開始

將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 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:

處理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,後者在頁面上列印有關使用者操作的資訊。

如果執行該應用程式,我們將看到以下結果:

我們希望我們的教程對您的專案有用。如果您遇到任何困難,請隨時在下面的評論中向我們傳送您的問題。