GithubHelp home page GithubHelp logo

qalamar / react-dnd Goto Github PK

View Code? Open in Web Editor NEW
5.0 1.0 0.0 23.05 MB

A guide on how-to add drag'n drop functionality to React components using the DOM Event Model.

Home Page: https://qalamar.github.io/react-dnd/docs/

License: MIT License

JavaScript 78.69% CSS 21.31%

react-dnd's Introduction

img

عن المشروع

هذا المشروع يهدف بالاساس لشرح كيفية جعل عناصر React قابلة للسحب و التحريك (Drag & Drop) عن طريق ما يسمى بـ DOM Event Model ما يعني أن هذا يتم مباشرة عن طريق HTML Drag'n Drop API دون اللجوء الى مكتبات خارجية.



الهدف

يسرني أنك قد سئلت, هناك العديد من عناصر واجهة المستخدم (UI) التي يمكن ان تتحسن عندما نضيف لها خاصية التحريك, خصوصا بالنسبة للاجهزة التي تعمل باللمس. عموما نجد هذه العناصر في البرامج التعليمية على سبيل المثال او أي حلول تعتمد بشكل كبير على تجاوب المستخدم مع الواجهة. بعض الامثلة: Trello Boards, Google Calendar Scheduler, DrawMuzz



النتيجة النهائية

المشروع الذي سنقوم بصنعه:

img

مثال عن كيف يمكن استخدامه في مشروع حقيقي:

img




كيف يعمل المشروع

img img img img




متطلبات

للقيام بتشغيل وصنع المثال, نحتاج أولا الى تنفيذ بعض الاوامر:
npx create-react-app react-dnd
cd react-dnd
npm start
اذا كنت تستعمل Yarn
yarn create react-app react-dnd
cd react-dnd
yarn start



تعليمات

توجه الى ملف App.js
تخزين المعلومات:
لنقم بانشاء جدول يضم معلومات حول العناصر, هذه المعلومات تتظمن: معرف id , محتوى العنصر item والخانة الخاصة به type.
const [state, setState] = useState({
  items: [
    {
      id: "1",
      item: "العنصر الاول",
      type: "Slot1",
    },
    {
      id: "2",
      item: "العنصر الثاني",
      type: "Slot1",
    },
    {
      id: "3",
      item: "العنصر الثالث",
      type: "Slot2",
    },
    {
      id: "4",
      item: "العنصر الرابع",
      type: "Slot2",
    },
  ],
});
معالجة التحريك (Event handlers):
حينما نضغط على العنصر عند بداية التحريك (onDragStart), نقوم بتهيئة معلومات العنصر للنقل عن طريق dataTransfer.setData
const onDragStart = (event, item) => {
  event.dataTransfer.setData("item", item);
};
نمنع المعالجة الافتراضية لأننا نريد تطبيق معالجة خاصة (مقارنة الخانات) عند نهاية التحريك (onDragOver)
const onDragOver = (event) => {
  event.preventDefault();
};
عند وضع العنصر داخل الاطار, نقوم بتحويل المعلومات المعدة سابقا في dataTransfer.getData ونقوم بالتأكد بأن العنصر في الاطار المناسب. بعدها نقوم بتحديث الـstate بالحالة الجديدة
ونقوم بالتأكد بأن العنصر في الاطار المناسب. بعدها نقوم بتحديث الـstate بالحالة الجديدة
const onDrop = (event, slot) => {
  let item = event.dataTransfer.getData("item");
  let items = state.items.filter((task) => {
    if (task.item === item) {
      task.type = slot;
    }
    return task;
  });
  setState({
    ...state,
    items,
  });
};
عند حدوث تحريك, نقوم بتحديث جداول الخانات في حالة اضافة عنصر جديد
لا تنسى ان تضيف "dir="rtl الى عناصرك اذا كنت تستخدم اللغة العربية
state.items.forEach((task) => {
  items[task.type].push(
    <div
      key={task.id}
      onDragStart={(event) => onDragStart(event, task.item)}
      draggable
      dir="rtl"
    >
      {task.item}
    </div>
  );
});
في واجهة المستخدم, نقوم بصنع خانتين. كل منهما تعرض العناصر المطابقة لنوعها من جدول العناصر
<div>
  <h1 dir="rtl">يمكنك سحب العناصر من خانة الى اخرى (Drag & Drop)</h1>
  <div>
    <div
      onDragOver={(event) => onDragOver(event)}
      onDrop={(event) => onDrop(event, "Slot1")}
    >
      <h2>الخانة 1</h2>
      {items.Slot1}
    </div>
    <div
      onDragOver={(event) => onDragOver(event)}
      onDrop={(event) => onDrop(event, "Slot2")}
    >
      <h2>الخانة 2</h2>
      {items.Slot2}
    </div>
  </div>
</div>

الملف النهائي
حينما تنتهي من اتباع ما سبق, يصبح لديك الملف التالي:
const App = () => {
  const [state, setState] = useState({
    items: [
      {
        id: "1",
        item: "العنصر الاول",
        type: "Slot1",
      },
      {
        id: "2",
        item: "العنصر الثاني",
        type: "Slot1",
      },
      {
        id: "3",
        item: "العنصر الثالث",
        type: "Slot2",
      },
      {
        id: "4",
        item: "العنصر الرابع",
        type: "Slot2",
      },
    ],
  });
  const onDragStart = (event, item) => {
    event.dataTransfer.setData("item", item);
  };
  const onDragOver = (event) => {
    event.preventDefault();
  };

  const onDrop = (event, slot) => {
    let item = event.dataTransfer.getData("item");
    let items = state.items.filter((task) => {
      if (task.item === item) {
        task.type = slot;
      }
      return task;
    });
    setState({
      ...state,
      items,
    });
  };

  let items = {
    Slot1: [],
    Slot2: [],
  };

  state.items.forEach((task) => {
    items[task.type].push(
      <div
        key={task.id}
        onDragStart={(event) => onDragStart(event, task.item)}
        draggable
        dir="rtl"
      >
        {task.item}
      </div>
    );
  });

  return (
    <div>
      <h1 dir="rtl">يمكنك سحب العناصر من خانة الى اخرى (Drag & Drop)</h1>
      <div>
        <div
          onDragOver={(event) => onDragOver(event)}
          onDrop={(event) => onDrop(event, "Slot1")}
        >
          <h2>الخانة 1</h2>
          {items.Slot1}
        </div>
        <div
          onDragOver={(event) => onDragOver(event)}
          onDrop={(event) => onDrop(event, "Slot2")}
        >
          <h2>الخانة 2</h2>
          {items.Slot2}
        </div>
      </div>
    </div>
  );
};

تنسيق
لجعل المشروع في صيغة قابلة للعرض, سنقوم باضافة TailwindCSS مما يمكننا من تعديل الواجهة بسهولة
هذه الخطوة اختيارية ويمكنك استعمال CSS فقط أو اي مكتبة تفضل كـBootstrap, Material UI
التعليمات
yarn add tailwindcss -D
npx tailwind init
اصنع ملف src/tailwind.css وضع بداخله المعلومات التالية:
@tailwind base;
@tailwind components;
@tailwind utilities;
الان توجه الى ملف package.json وعدل الـscripts كما يلي:
"scripts": {
  "start": "npm run tailwind:css && react-scripts start",
  "tailwind:css": "tailwind build src/tailwind.css -c tailwind.config.js -o src/index.css",
  "build": "npm run tailwind:css && react-scripts build",
  ...
}
عد الى الملف الرئيسي وطبق التنسيق التالي:
const App = () => {
  const [state, setState] = useState({
    items: [
      {
        id: "1",
        item: "العنصر الاول",
        type: "Slot1",
      },
      {
        id: "2",
        item: "العنصر الثاني",
        type: "Slot1",
      },
      {
        id: "3",
        item: "العنصر الثالث",
        type: "Slot2",
      },
      {
        id: "4",
        item: "العنصر الرابع",
        type: "Slot2",
      },
    ],
  });
  const onDragStart = (event, item) => {
    event.dataTransfer.setData("item", item);
  };
  const onDragOver = (event) => {
    event.preventDefault();
  };

  const onDrop = (event, slot) => {
    let item = event.dataTransfer.getData("item");
    let items = state.items.filter((task) => {
      if (task.item === item) {
        task.type = slot;
      }
      return task;
    });
    setState({
      ...state,
      items,
    });
  };

  let items = {
    Slot1: [],
    Slot2: [],
  };

  state.items.forEach((task) => {
    items[task.type].push(
      <div
        key={task.id}
        onDragStart={(event) => onDragStart(event, task.item)}
        draggable
        dir="rtl"
        className="p-4 m-4 bg-white border-r-8 border-blue-700 shadow-xl"
      >
        {task.item}
      </div>
    );
  });

  return (
    <div className="flex flex-wrap pt-32 main">
      <div class="md:w-3/12 w-1/12 p-4"></div>
      <div class="md:w-6/12 w-10/12 p-4">
        <h1 className="pb-16 text-xl font-bold text-center" dir="rtl">
          يمكنك سحب العناصر من خانة الى اخرى (Drag & Drop)
        </h1>
        <div className="flex flex-wrap">
          <div
            className="w-1/2 p-6 shadow-md"
            onDragOver={(event) => onDragOver(event)}
            onDrop={(event) => {
              onDrop(event, "Slot1");
            }}
          >
            <h2 className="font-bold text-center">الخانة 1</h2>
            {items.Slot1}
          </div>
          <div
            className="w-1/2 p-6 shadow-md"
            onDragOver={(event) => onDragOver(event)}
            onDrop={(event) => onDrop(event, "Slot2")}
          >
            <h2 className="font-bold text-center">الخانة 2</h2>
            {items.Slot2}
          </div>
        </div>
      </div>
      <div class="md:w-3/12 w-1/12 p-4"></div>
    </div>
  );
};
هذا التنسيق يسمح لنا بالحصول على الواجهة التالية

img

الان بامكانك تشغيل المشروع
  yarn run start



ماذا بعد؟

اذا كنت تريد أن تطور حلول اكثر تعقيدا او أن تظيف Animations دون أن تصنع كل شيء يديويا, انصحك بالاضافات مفتوحة المصدر التالية:
سبب اختياري لهذه الاضافات هو لكونها مشهورة نسبيا وتحظى بدعم مستمر من المطورين. أود أيضا أن اذكر بعض المكتبات مثل Framer Motion التي تحتوي على خصائص مشابهة

كلمة أخيرة

شكرا على القراءة حتى هذه النقطة, أتمنى ان يكون الشرح مفيدا وحظا سعيدا في مشاريعكم المقبلة.

react-dnd's People

Contributors

qalamar avatar imgbotapp avatar

Stargazers

 avatar  avatar Latreche Cherif avatar Salah Eddine Ait Balkacm avatar  avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.