react引入外部js

by Rajesh Pillai

由Rajesh Pillai

(React.js: implement the drag and drop feature without using external libraries)

(Get into the details of implementing drag and drop features in React from scratch.)

Let’s first see the result of what we will be building. I am trying out .gif — hopefully it works everywhere as expected. I’ve used Camtasia with a personal license.

首先让我们看看我们将要构建的结果。 我正在尝试.gif-希望它可以按预期在任何地方使用。 我已经将Camtasia与个人许可证一起使用。

The key learning points are to:

关键学习点是:

  1. make an element draggable by adding the “draggable” attribute
  2. make an area droppable by implementing the “dragover” event
  3. capture the drag data by implementing the “dragstart” event
  4. capture the drop by implementing the “drop” event
  5. implement the “drag” event that is fired as the element is being dragged
  6. store the intermediate data in the dataTransfer object

For visual learners, head over to the video below.

对于视觉学习者,请转到下面的视频。

(Step 1 — create the root app for the demo)

All the code for drag and drop will go into AppDragDropDemo.js component.

所有拖放代码将进入AppDragDropDemo.js组件。

import React from 'react';import ReactDOM from 'react-dom';import '.index.css';import AppDragDropDemo from './AppDragDropDemo';
ReactDOM.render(<AppDragDropDemo />,     document.getElementById("root"));

The entry point for the AppDragDropDemo looks like the code below.

AppDragDropDemo的入口点看起来像下面的代码。

import React, { Component } from 'react';
export default class AppDragDropDemo extends Component {  render () {    return (      <div className="container-drag">        DRAG & DROP DEMO      </div>    );  }}

If you now run the application, you will be presented with this awesome screen (pun intended)

如果您现在运行该应用程序,将会看到一个很棒的屏幕(双关语意)

(Step 2 — create the state object to store some tasks)

Let’s create some tasks to simulate a simple application. What we intend to do is to drag and drop these tasks into different categories like wip, complete , and so on.

让我们创建一些任务来模拟一个简单的应用程序。 我们打算做的就是将这些任务拖放到不同的类别中,例如wipcomplete等。

export default class AppDragDropDemo extends Component {      state = {            tasks: [{name:"Learn Angular",             category:"wip",              bgcolor: "yellow"},                        {name:"React",              category:"wip",              bgcolor:"pink"},                        {name:"Vue",              category:"complete",              bgcolor:"skyblue"}                ]}
render () {    return (      <div className="container-drag">        DRAG & DROP DEMO      </div>    );  }}

(Step 3 — organize our data into categories)

Let’s implement the below code in the render method, to group tasks into their respective categories, wip and complete. Feel free to add more categories and play with the code.

让我们在render方法中实现以下代码,将任务分为wipcomplete各自的类别。 随意添加更多类别并使用代码。

You can copy-paste the code above from the below snippet.

您可以从下面的代码段复制粘贴上面的代码。

render() {          var tasks = { wip: [],                 complete: []          }           this.state.tasks.forEach ((t) => {                   tasks[t.category].push(<div       key={t.name}                           onDragStart={(e)=>this.onDragStart(e, t.name)}                          draggable                          className="draggable"                          style={{backgroundColor: t.bgcolor}}>                                {t.name}                    </div>);          });

In the above code, we are looping through all tasks and creating a div for every task item and storing it in the respective categories.

在上面的代码中,我们遍历所有任务,并为每个任务项创建一个div并将其存储在相应的类别中。

So, the wip[] contains all tasks in the wip category and complete[] contains all the completed tasks.

因此, wip[]包含wip类别中的所有任务,而complete[]包含所有已完成的任务。

(Step 4 — make the task item draggable)

Add the draggable attribute to the <div> or any element to make an element draggable. Refer to the code block above for the text format of the code.

将draggable属性添加到<div>或任何元素以使元素可拖动。 有关代码的文本格式,请参见上面的代码块。

(Step 5 — create a droppable container)

To create a droppable container, implement the dragover event. Now, since we want to disable the default dragover event, we simple call the event.preventDefault() from the dragover event.

要创建可放置容器,请实现dragover event 。 现在,由于我们要禁用默认的拖动事件,因此我们只需从拖动事件中调用event.preventDefault()

We will also render {tasks.wip} and {tasks.complete} in their corresponding div elements.

我们还将在其相应的div元素中渲染{tasks.wip}{tasks.complete}

return (<div className="container-drag">     <h2 className="header">DRAG & DROP DEMO</h2>                       <div className="wip"        onDragOver={(e)=>this.onDragOver(e)}                           onDrop={(e)=>{this.onDrop(e, "wip")}}>                          <span className="task-header">WIP</span>                          {tasks.wip}                     </div>                     <div className="droppable"      onDragOver={(e)=>this.onDragOver(e)}                          onDrop={(e)=>this.onDrop(e, "complete")}>                           <span className="task-header">COMPLETED</span>                           {tasks.complete}                     </div>               </div>);
Let us now implement the onDragOver() event handler.

The output so far will look like the below figure.

到目前为止的输出将如下图所示。

(Step 6 — capture the state of the element being dragged)

Let’s modify the code where we are creating the category for each task. Add an eventhandler ondragstart and pass the id/name or any information you need to persist while the drag/drop is happening.

让我们修改为每个任务创建类别的代码。 在ondragstart添加事件处理ondragstart并传递ID /名称或在拖放过程中需要保留的任何信息。

I am using name as a unique value to identify the task. Feel free to use ID or whatever unique key you have.

我使用name作为唯一值来标识任务。 随意使用ID或您拥有的任何唯一密钥。

Let’s now implement the onDragStart event handler.

现在,让我们实现onDragStart事件处理程序。

In the onDragStart handler, we grab the parameter and store that within the dataTransfer object. (Don’t get confused by the parameter naming, as I guess I was in a different naming world while coding this :) .)

在onDragStart处理程序中,我们获取参数并将其存储在dataTransfer对象中。 (不要对参数命名感到困惑,因为我猜我在编写此代码时处于另一个命名世界:)。

IE note: this may not work with IE. For IE, the better practice is to give the format as the key as shown below.

IE注意 :这可能不适用于IE。 对于IE,更好的做法是将格式指定为密钥,如下所示。

Instead of
ev.dataTransfer.setData("id", id)
USE
ev.dataTransfer.setData(“text/plain”,id)

The above handler will ensure that the element being dragged is stored in the event object and is available for use when required. It may be required while dropping on a target.

上面的处理程序将确保被拖动的元素存储在事件对象中,并可在需要时使用。 放在目标上时可能需要它。

Now if you run the application and drag the elements, the following logs will be output.

现在,如果您运行应用程序并拖动元素,将输出以下日志。

(Step 7 — handle the drop event.)

Let’s open up the render method and add the onDrop event to the div with a className of droppable.

让我们打开render方法,将onDrop事件添加到div,其className为droppable

In the above code, we add the drop event handler, and pass the required category complete as an argument. This indicates we are dropping the element from the wip state to the complete state (category). Please feel free to change the names, as required.

在上面的代码中,我们添加了drop事件处理程序,并将所需的complete类别作为参数传递。 这表示我们正在将元素从wip状态放到complete状态(类别)。 请根据需要随时更改名称。

Let’s now implement the onDrop() event handler.

现在让我们实现onDrop()事件处理程序。

Here’s the code you can copy/paste:

这是您可以复制/粘贴的代码:

onDrop = (ev, cat) => {         let id = ev.dataTransfer.getData("id");  let tasks = this.state.tasks.filter((task) => {      if (task.name == id) {               task.category = cat;                 }                     return task;          });           this.setState({                 ...this.state,                 tasks          });    }

In the onDrop event handler, we grab the task being dragged by using getData method on the event’s dataTransfer object.

onDrop事件处理程序中,我们使用事件的dataTransfer对象上的getData方法来捕获要拖动的任务。

We then create a new tasks array by using the filter method, and change the category of the task being dragged.

然后,我们使用filter方法创建一个新的任务数组,并更改要拖动的任务的类别。

setState() will trigger render, and the tasks will be rendered in the right areas.

setState()将触发渲染,并且任务将在正确的区域中渲染。

IE note: To make it work in IE, use the below getData method.

IE注意 :要使其在IE中工作,请使用以下getData方法。

Instead of

代替

var id = ev.dataTransfer.getData(“id”)

var id = ev.dataTransfer.getData(“ id”)

use

var id = ev.dataTransfer.getData(“text”)

var id = ev.dataTransfer.getData(“ text”)

(Step 8 — to implement drop from “complete” to “wip,” add the onDrop handler)

The onDrop() handler remains the same as earlier.

onDrop()处理函数与之前的相同。

Finally, run the code and marvel at your creation :) and have fun while coding.

最后,运行代码并惊叹于您的创作:),并在编码时玩得开心。

You can grab the source code from here.

您可以从此处获取源代码。

Note: for this to work cross browser, change the setData type to string.for example, to set data, use ev.dataTransfer.setData(“text/plain”,id). To read data, use var id = ev.dataTransfer.getData(“text”)

注意: ev.dataTransfer.setData(“text/plain”,id)此功能可跨浏览器使用,请将setData类型更改为string。例如,要设置数据,请使用ev.dataTransfer.setData(“text/plain”,id) 要读取数据,请使用var id = ev.dataTransfer.getData(“text”)

Since my aim was to demonstrate the core drag and drop features, the code has not been optimized for factors such as design and naming conventions.

由于我的目的是演示核心拖放功能,因此尚未针对诸如设计和命名约定之类的因素对代码进行优化。

Learn with me @Learner + Fullstack Coach (@rajeshpillai): https://twitter.com/rajeshpillai

与我一起学习@Learner + Fullstack Coach(@rajeshpillai): https ://twitter.com/rajeshpillai

Promotion: Special 10$ coupon for Medium readers for my upcoming live ReactJS-Beyond the basics course on Udemy in case you wish to support our open source curriculum Mastering frontend engineering in 12 to 20 weeks.

促销:如果您希望在12到20周内支持我们的开源课程“ 掌握前端工程”,那么我即将推出的实时ReactJS-Beyond Udemy基础课程将为中级读者提供10美元特别优惠券。

Just published my early access course Javascript Deep Dive — Code your own React

刚刚发布了我的抢先体验课程Javascript Deep Dive-编写自己的React