Schedulr: Github Frontend, Github Backend | Живая демонстрация

React Draggable - невероятно простой способ добавить на веб-сайт функцию перетаскивания, но это не самый умный инструмент. Каждый перетаскиваемый элемент знает только немного данных о себе и, к сожалению, не обязательно ведет себя так, как вы думаете.

Недавно я собрал планировщик дня на основе React под названием Schedulr (о котором я писал), и у меня было довольно много проблем с тем, чтобы что-то перетащить, отпустить, а затем вспомнить, что они это сделали. После нескольких дней борьбы с React DnD я решил пойти попроще и просто использовать React Draggable. Хотя в readme есть отличная документация о том, как сделать компоненты перетаскиваемыми с различными ограничениями, в нем нет ничего о том, как подключить все это к вашей серверной части.

Я не могу обещать, что это лучший способ заставить Draggable работать на вас, но у меня это сработало.

Основы

После установки Draggable вы можете импортировать его в любой файл React, а затем просто поместить теги ‹Draggable› ‹/Draggable› вокруг всего, что вы хотите переместить. Это действительно просто сделать прямо из коробки, и это здорово. Есть несколько способов изменить поведение перетаскиваемого элемента, но давайте остановимся на некоторых, которые я считаю полезными.

Сетка - это именно то, на что это похоже. Добавьте значение X и значение Y, и все готово. Ваш перетаскиваемый элемент будет двигаться только в зависимости от этих значений. Это может быть полезно для таких приложений, как мое, где я не хочу, чтобы пользователи выстраивали все подряд. Он также обеспечивает невероятно четкое и приятное движение.

Границы тоже отличные, и это может быть очень весело. Вы можете установить границы как «родительский», чтобы разрешить перемещение элемента только внутри его родительского элемента, но это может быть ограничением. В противном случае вы можете установить значения пикселей слева, справа, сверху и снизу. Я закончил тем, что они сгенерировали программно в зависимости от местоположения элемента. Мне нужно, чтобы каждый элемент имел одно из двух значений X, поэтому с помощью этой логики он может перемещаться на 255 в одном или другом направлении, в зависимости от того, где он находится. Я основываю это на состоянии элемента, поэтому он всегда обновляется. Верхние границы были немного сложнее, но с учетом небольшого отступа они представляют собой просто отрицательное значение текущей позиции Y элемента.

Бэкэнд

Бэкэнд здесь не слишком сложный. В моем случае перетаскиваемые элементы являются «встречами», и у каждого есть координата X, координата Y и немного данных, не связанных с перетаскиванием. Изначально я по привычке установил для них целые числа, но почти гарантировано, что вам понадобятся числа с плавающей запятой. Если ваш элемент расположен в наборе координат, в котором используются десятичные дроби, и ваша серверная часть не может их обработать, они переместятся на вас, как только вы перезагрузите. Плохой вид.

У меня также координаты Y по умолчанию равны 14, так что каждый новый перетаскиваемый элемент, созданный пользователем, смещается в div и совпадает с дневным календарем.

Установка исходного местоположения

Вот здесь все начинает усложняться. My AppointmentList захватывает мои встречи, отображает их и возвращает AppointmentContainer. Каждый из этих AppointmentContainers имеет componentDidMount, который устанавливает состояние для X и Y в бэкэнде. Это передается компоненту Appointment, который использует их для установки абсолютной позиции div, которую оборачивает компонент Draggable.

Если вы знакомы с Draggable, вы можете сказать: «Привет, Дик, разве у компонентов Draggable нет собственной позиции?» Вы правы, они верят. Но я обнаружил, что поведение слишком непредсказуемо, чтобы работать с ним. В конце концов, позиционирование каждого div было самым простым способом.

Как справиться с перетаскиванием

Draggable имеет встроенный обработчик событий под названием OnStop, который срабатывает, когда пользователь прекращает перетаскивать элемент, который я использовал для отправки данных из интерфейса в серверную часть. Он принимает два аргумента: первый - это событие, которое вы привыкли видеть, а второй - вся информация, полученная из события перетаскивания.

Событие перетаскивания отправляет несколько фрагментов информации, хотя это не совсем интуитивно понятно. Вы можете получить узел (который является HTML-элементом, который вы перетаскиваете), а также значения X и Y элемента. X и Y - это не позиция элемента, а величина, на которую указатель мыши переместился при перетаскивании.

Эти значения X и Y довольно хороши, если вы просто ищете свободное движение, но если вы используете движение по сетке, вы получите данные, которые вам нужно немного математически обработать.

const x = this.state.x + dragElement.x > -127.5 ? 0 : -255;

Мое значение X довольно простое, поскольку есть только две позиции, в которых я хочу разместить элементы. Они могут быть в начальной области или в календаре, поэтому я расположил его так, чтобы значение X округлялось до 0 или -255.

Значение Y более сложное. Поскольку у меня есть перетаскиваемые элементы в прокручиваемом div, мне нужно немного пофантазировать. Сначала я нахожу текущую позицию Y элемента на странице с помощью getBoundingClientrect. Затем я просматриваю серию родительских элементов, чтобы найти div, который прокручивает пользователь, и получить его значение. Наконец, у меня есть еще одно смещение, чтобы отразить то, что я хотел бы считать нулевой позицией для встреч.

Все это довольно уродливо, и, оглядываясь назад, я уверен, что есть более чистый способ сделать это. Я уверен, что смогу найти способ установить состояние прокручиваемого div при его перемещении, а затем передать это на встречи.

Вывод

Я создал Schedulr как проект продолжительностью в полторы недели в The Flatiron School и мой первый проект с использованием React. У меня были гораздо более высокие цели, но оказалось, что просто заставить перетащить и оставить упорство было более чем достаточно сложной задачей. Там не было слишком много информации, кроме официального Readme и случайного вопроса о StackOverflow, поэтому я надеюсь, что это может быть ресурсом для людей, которые захотят попробовать это в будущем!