Проект: Жуткий сезон

Знаете ли вы, что по данным W3Techs JavaScript используется на 97,6% всех веб-сайтов? Теперь вы знаете, по оценкам, существует 1,7 миллиарда веб-сайтов, что означает, что 1,66 миллиарда веб-сайтов используют JavaScript. И теперь, когда вы знаете, вы знаете, почему это такой хороший и почти необходимый язык для изучения, если вы хотите разместить свои приложения в Интернете. Этот блог собирается продемонстрировать некоторые из наиболее интересных частей веб-приложения, которое я разработал, изучая этот широко используемый интерактивный язык создания веб-сайтов.

Для начала поговорим о бэкенде. Для серверной части мыиспользуем Rails в качестве API только для отправки и получения информации из базы данных, для этого мы открываем наш терминал и генерируем новый Rails API, используя

rails new <my_app_name> --database=postgresql --api

Затем мы создаем наши миграции, модели, контроллеры, маршруты и ассоциации Rails так же, как если бы мы создавали приложение rails.

class Card < ApplicationRecord
has_many :card_backgrounds
has_many :backgrounds, through: :card_backgrounds
end

def create
card = Card.new(name: card_params[:name])
end

Rails.application.routes.draw do
resources :cards, only: [:index, :create, :show]
end

Для отправки данных во внешний интерфейс Rails требует, чтобы мы использовали render json (обозначение объекта JavaScript) в действии контроллера. Здесь мы отправляем объект карты, созданный как_json, чтобы включить только определенные атрибуты объекта, действие индекса карт — это простая схема рендеринга.

render json: cards.as_json( only: [:id, :name])

В то время как действие показа для отдельных карточек сравнительно сложное, здесь мы запрашиваем определенные атрибуты ассоциаций карточек.

render json: card.as_json( only: [:id, :name],
  include: {
    element_positions: {
      only: [:element_id, :image_url, :xPosition, :yPosition,    :xOffset, :yOffset, :imageSize, :name]
    },
    elements: {
      only: [:id, :image_url]
    },
    backgrounds: {
      only: [:id, :name]
    }
}

Далее мы собираемся перейти к внешнему интерфейсу, где и происходит все действие. Прежде всего, мы собираемся добавить прослушиватель событий для DOM, он будет запускать все, что мы поместили в метод после загрузки DOM. Это гарантирует, что если мы запрашиваем элемент, он будет найден путем поиска после его загрузки, а не до этого.

document.addEventListener('DOMContentLoaded', () => {
console.log('dom is loaded');
}

За пределами этого обработчика событий будет написана целая куча функций и классов с функциями и логикой, внутри обработчика событий будут вызываться функции. Первой из этих функций будет вызов выборки в базу данных для получения элементов, которыми пользователь может манипулировать в приложении. fetch обращается к базе данных и получает ответ, мы берем ответ, а затем преобразуем его в json, а затем перебираем результаты, вызывая другую функцию для работы с данными. От добавления элементов в дом, прослушивателей событий и функций для управления и создания.

function getCardItems(database,func) {
  fetch(database)
  .then(response => response.json())
  .then(items => {
    for (const item of items) {
      func(item)
    }
  })

В приложении «Spooky Season» выполняется вызов базы данных для получения элементов карты и фона для создания поздравительных открыток на Хэллоуин, вызов получает набор элементов (response =› response.json()) каждый представляет другой img ( for (const item of items)), который затем добавляется в модель DOM, на которую пользователь может щелкнуть и добавить на карточку. Существует также вызов для фонов и уже созданных карт.

Когда пользователь выбирает фон, фоновое изображение затем добавляется в DOM и отображается как фон для «карты». Затем пользователь может выбрать «элементы» и добавить их в DOM и на карту, после рендеринга на «карту» пользователь может затем перемещать и изменять размер элементов по своему художественному вкусу.

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

Для начала мне нужно было выбрать элемент и сделать так, чтобы положение этого элемента было таким же, как положение мыши, я играл с несколькими различными подходами, включая element.style.left/top и положение элементов x/y, используя

Метод .getBoundingClientRect возвращает объект DOMRect, предоставляющий информацию о размере элемента и его положении относительно окна просмотра.

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

После некоторого изучения я наткнулся и решил остановиться на свойстве преобразования css. Это свойство позволило мне перемещать элемент по экрану в зависимости от исходного положения элементов после загрузки в DOM, сохранять новое положение элементов и расстояние от исходного положения до JS-объекта элементов. Когда элемент снова нажимается, функция загружает эту информацию в свойство перевода и позволяет нам продолжить перемещение объекта. Допустим, исходное положение было 0px и 0px, верхний левый угол, первая переменная по оси x и вторая по вертикальной оси y. С помощью перевода мы хотим переместить элемент на 50 пикселей по оси x и на 50 пикселей по оси y.

transform: translate(50px,50px);

Теперь позиция элемента будет 50px внутрь и 50px вниз.

Если бы я хотел, чтобы элемент был на 100 пикселей внутрь и на 100 пикселей вниз, мне пришлось бы поместить то, что я хочу, чтобы преобразование было из исходной позиции, я подчеркиваю это только потому, что изначально думал, что переведенная позиция стала новой. положение элемента, но это не так. Позиция элемента всегда будет исходной позицией при загрузке в DOM.

transform: translate(100px,100px);

Итак, теперь я могу перемещать элемент из его исходного положения с помощью преобразования. Все, что мне нужно отслеживать, — это значение перемещений x/y от исходной позиции и сохранять его в объектах, которые я создал при добавлении элемента на «карту» и DOM. Когда элемент выбран снова, я могу продолжить преобразование исходного положения элемента и сохранить количество преобразований при отмене выбора. бум.

Другой дилеммой была привязка элемента к положению мыши при выборе. Чтобы противостоять этому, нам нужно смещение позиции мыши и позиции элемента, я знаю, что даже когда я пишу это, это звучит запутанно, но потерпите меня, в конце концов, все это имеет смысл.

Предположим, что позиция элемента вернулась к отметке 50px по оси x и 50px по оси y, а положение мыши, когда мы щелкаем, составляет 59px по оси x и 57px по оси y. Поскольку положение элементов преобразуется в зависимости от положения мыши, мы получим некрасивую привязку положения элемента к положению мыши. В шагах смещение, элемент преобразуется, позиция мыши является основой преобразования, поэтому, чтобы получить точную позицию для преобразования, нам нужно вычесть позицию элемента x из позиции мыши x, то же самое с позициями y и преобразовать элемент на основе положения мыши за вычетом смещения.

currentX = e.clientX - (e.clientX - element.x)
or
mousePosition - (mousePosition - lastKnownTranslatePosition)

Так что независимо от того, где я нажимаю на элемент, позиция преобразования основывается на смещении позиции мыши. Это почти кажется ненужным, если учесть последнюю известную позицию преобразования, но, тем не менее, учитывая меня, текущая позиция преобразования основана на текущей позиции мыши относительно того места, где был активирован щелчок по элементу. Это все для того, чтобы буквально показать более плавное движение при щелчке и перемещении элемента, без защелки, плавно.

Вот код для изучения.

Последнее, о чем стоит упомянуть в этом блоге, — это отправка вызовов fetch для создания новых объектов и их сохранения в базе данных. Здесь мы отправляем выборку с использованием HTTP-глагола RESTful, чтобы API-интерфейс rails мог перехватить и интерпретировать это как действие создания для контроллера карт, API-интерфейс Rails создаст на основе отправленных параметров, а затем отправит обратно вновь созданный объект, который мы отформатируем. в json и добавить в DOM.

fetch("http://127.0.0.1:3000/cards", {
  method: "POST",
  headers: {"Content-Type": "application/json"},
  body: JSON.stringify(bodyData)
})
.then(response => response.json())
.then(json => {
  getCardLoadout(json)
})
}

Подводя итог, можно сказать, что существует Rails API, который обрабатывает базу данных, отправляет объекты, получает информацию и создает объекты. Существует интерфейс JS, который обрабатывает DOM и взаимодействия с пользователем и динамически изменяет веб-страницу, позволяя пользователю в этом примере делать странные, глупые открытки на Хэллоуин. Здесь, в конце, я могу сказать, что мне очень понравилось создавать это приложение во время изучения Javascript, а также, как я думаю, я говорю во всех своих проектных блогах, что это было чрезвычайно сложно, но очень полезно.

Спасибо за прочтение.