Прототип интерактивного текстового поля с помощью Framer. Часть 2

Pavel Chelyuskin
Монографик
4 min readJun 29, 2018

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

Классы позволяют создавать новые типы объектов определять для них свойства и методы, которые будут работать для всех экземпляров класса. Layer, TextLayer, PageComponent — это все встроенные во Framer классы. Если вы работаете в Figma, то ближайший аналог класса — компонент.

Создаем класс

class InputComponent extends Layer
¬ constructor: (@options={}) ->
¬ ¬ @isFocus = false
¬ ¬ super _.defaults @options,
¬ ¬ ¬ width: 360
¬ ¬ ¬ height: 76
¬ ¬ ¬ backgroundColor: "#fff"
¬ ¬ ¬ inputLabel: "Label"

Разберем, что это значит:

class InputComponent extends Layer — создаем новый класс под названием InputComponent на основе встроенного во Framer класса Layer. Наш новый класс будет наследовать все свойства и методы от класса Layer и расширять его.

constructor: (@options={}) -> — специальный метод, который используется для создания классов.

@isFocus — будем использовать для проверки, является ли наше поле в фокусе.

super _.defaults @options, — конструкция, с помощью которой мы получаем свойства и родительского класса (т.е. Layer), переопределяем те, которые нам интересны и добавляем новые. _.defaults — это функция из встроенной в Framer библиотеки lodash.

Элементы текстового поля

1. Название

Добавим название текстового поля, для этого внутри нашего класса добавим TextLayer. И добавим два состояния: базовое (лейбл по центру поля) и активное (лейбл смещается вверх и уменьшается):

@label = new TextLayer
¬ parent: @
¬ text: @options.inputLabel
¬ fontSize: 16
¬ lineHeight: 1.25
¬ y: 18
@label.states =
¬ basic:
¬ ¬ fontSize: 16
¬ ¬ y: 18
¬ active:
¬ ¬ fontSize: 12
¬ ¬ y: 0

2. Линия подчеркивания

Добавляем линию и ее состояния:

@line = new Layer
¬ parent: @
¬ width: @.width
¬ height: 2
¬ y: 54
¬ backgroundColor: "#808080"
¬ opacity: 0.5
@line.states =
¬ basic:
¬ ¬ backgroundColor: "#808080"
¬ ¬ opacity: 0.5
¬ hover:
¬ ¬ backgroundColor: "#808080"
¬ ¬ opacity: 1
¬ active:
¬ ¬ backgroundColor: "#000000"
¬ ¬ opacity: 1

3. Поле ввода

@inputField = document.createElement("input")
@inputField.style["width"] = @.width + 'px'
@inputField.style["height"] = "56px"
@inputField.style["color"] = "#000000"
@inputField.style["font-size"] = "16px"
@inputField.style["background-color"] = "rgba(0,0,0,0)"
@inputField.style["outline"] = "none"
@inputField.value = ""
@._element.appendChild(@inputField)

События

Нам осталось сделать наше поле интерактивным. Нам нужно создать две пары событий для нашего текстового поля:

  1. При наведении и убирании курсора мыши;
  2. При фокусе и анфокусе поля.

Для наведения будем использовать знакомые события onMouseOver и onMouseOut :

@.onMouseOver () ->
¬ @line.animate("hover")
@.onMouseOut () ->
¬ if !@isFocus # Если курсор стоит в поле, то обратную анимацию не делаем
¬ ¬ @line.animate("basic")

Для фокуса и, так называемого, блюра (то есть убирании фокуса с поля) будем использовать onfocus и onblur. Я сейчас не буду вдаваться в подробности, почему мы импользуем разный синтаксис, можете отдельно почитать про fat arrows.

@inputField.onfocus = =>
¬ @isFocus = true
¬ @line.animate("active")
¬ @label.animate("active")
@inputField.onblur = =>
¬ @isFocus = false
¬ @line.animate("basic")
¬ if @inputField.value == "" # Если пользователь оставил поле пустым, то возвращаем лейбл на место
¬ ¬ @label.animate("basic")

Ура, наш класс готов! Осталось превратить его в модуль.

Класс → Модуль

Модуль — это отдельный файл содержащий один или несколько классов, который лежит в папке modules. Так проще организовывать и подключать только те классы, которые вам нужны.

Для появления модуля нужно:

  • При создании класса перед названием напиать exports.. Таким образом первая строка нашего модуля будет выглядеть так:
class exports.InputComponent extends Layer
  • Сохранить наш класс в отдельный файл с названием InputComponent.coffee в папке /modules нашего прототипа. Обратите внимание: если в вашем модуле только один класс, то модуль должен называться точно также, как класс. Если в модуле несколько классов, то название модуля не должно повторять название какого-либо класса в модуле.
  • Подключить модуль к прототипу с помощью команды {InputComponent} = require "InputComponent"

Теперь посмотрим, как мы можем им пользоваться.

Прототип формы

Сделаем функцию, в которую мы будем передавать список нужных полей, и она будет строить форму:

createForm = (fieldsList) ->
¬ formWidth = 412 # Ширина создаваемой формы
¬ gap = 25 # Отступ между полями
¬ firstInputX = 50 # Положение по X первого поля
¬ firstInputY = 5 # Положение по Y первого поля
¬ inputs = [] # Создаем пустой массив в который запишем все создаваемые поля
¬ for field in fieldsList # Проходим циклом по всем названиям полей, которые получили в переменной fieldsList и создаем соответствующие поля
¬ ¬ inputs[field] = new InputComponent
¬ ¬ width: formWidth
¬ ¬ x: firstInputX
¬ ¬ y: firstInputY + fieldsList.indexOf(field)*(76+gap)
¬ ¬ inputLabel: field

Нам остается вызвать написанную функцию…

createForm(["First name", "Last name", "E-mail", "Phone number"])

… и мы видим готовую форму!

Готовый прототип с модулем InputComponent можно взять на гитхабе. Этот же модуль вы можете использовать в любом своем прототипе скопировав его в папку modules.

--

--