Додаток A: Інтерактивна розробка за допомогою Figwheel

Вступ

У цьому проекті ми не будемо у сотий раз писати “Hello World”—. Натомість створимо веб-сторінку, що запитує вік користувача та перераховує роки у дні, виходячи зі спрощення про 365 днів у році.

Ми скористаємося плагіном figwheel для leiningen. Це плагін створює повністю інтерактивне середовище на базі REPL з функцією автоматичного перезавантаження.

Перші кроки

Найперший крок - створення нового проекту за допомогою шаблона figwheel lein. Для створення проекту під назвою age введемо наступні команди:

$ lein new figwheel age
Retrieving figwheel/lein-template/0.3.5/lein-template-0.3.5.pom from clojars
Retrieving figwheel/lein-template/0.3.5/lein-template-0.3.5.jar from clojars
Generating fresh 'lein new' figwheel project.
$ cd age # move into newly created project directory

Проект має таку структуру:

> tree age      # the linux "tree" utility displays dir structure
age
├── .gitignore
├── project.clj
├── README.md
├── resources
│   └── public
│       ├── css
│       │   └── style.css
│       └── index.html
└── src
    └── age
        └── core.cljs

Файл project.clj містить інформацію, що її потребує Leiningen для завантаження залежностей та зборки проекту. Домовимося поки що вважати, що в ньому є все необхідне для правильної роботи та не розглядати його зміст детально.

Відкрийте index.html та додайте наступний код:

<!DOCTYPE html>
<html>
  <head>
    <link href="css/style.css" rel="stylesheet" type="text/css">
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
  </head>
  <body>
    <div id="app">
      <h1>Age in Days</h1>
      <p>
        Enter your age in years:
        <input type="text" size="5" id="years">
        <button id="calculate">Calculate</button>
      </p>
      <p id="feedback"></p>
    </div>
    <script src="js/compiled/age.js" type="text/javascript"></script>
  </body>
</html>

Найцікавіше відбувається у файлі core.cljs. Поки що не міняйте в ньому нічого та запустіть оточення figwheel, яке завантажить велику кількість залежностей, та запустіть сервер.

$ lein figwheel
Retrieving lein-figwheel/lein-figwheel/0.5.2/lein-figwheel-0.5.2.pom from clojars
Retrieving figwheel-sidecar/figwheel-sidecar/0.5.2/figwheel-sidecar-0.5.2.pom from clojars
Retrieving org/clojure/clojurescript/1.7.228/clojurescript-1.7.228.pom from central
... # much more output
Prompt will show when Figwheel connects to your application

Якщо ви користуєтеся операційною системою Linux або Mac OS X, введіть команду rlwrap lein figwheel. У браузері перейдіть за посиланням http://localhost:3449. Відкривши консоль, ви маєте побачити щось подібне до наступного скріншоту:

image::localhost1.png[Screenshot of web page and console]

У терміналі зʼявиться наступне повідомлення:

$ rlwrap lein figwheel
To quit, type: :cljs/quit
cljs.user=>

Виконайте цю рекомендацію, а саме у файлі core.cljs замініть (println...) та збережіть файл. Зміни будуть одразу відображені у браузері.

Зробіть навмисну помилку: додайте зайву закриваючу дужку до println. Після збереження файлу браузер має показати помилку компіляції.

Взаємодія з JavaScript

У вікні REPL введіть наступну команду для виклику функції window.alert():

(.alert js/window "It works!")
;; => nil

У загальному випадку виклик функцій JavaScript з контексту ClojureScript передбачає введення імені функції (перед яким вводиться крапка), обʼєкту, який містить цю функцію, та будь-яких необхідних параметрів. Після введення команди ви маєте побачити вікно повідомлення у браузері. Натисніть "відміна", і побачите у терміналі nil та запит наступної команди. Інший спосіб:

(js/alert "It works!")
;; => nil

Перший варіант працює у будь-якому випадку, тому для консистентності ми будемо користуватися ним у цьому уроці.

Обʼєкти JavaScript можна створювати з контексту ClojureScript за допомогою того ж самого синтаксису - вводити імʼя класу та крапку. Методи JavaScript також можна викликати:

> (def d (js/Date.))
;; => #'cljs.user/d
> d
;; => #inst "2016-04-03T21:04:29.908-00:00"
> (.getFullYear d)
;; => 2016

> (.toUpperCase "doh!")
;; => "DOH!"

> (.getElementById js/document "years")
;; => #object[HTMLInputElement [object HTMLInputElement]]

Наступний приклад має зробити наші кроки більш зрозумілими. Для читання властивості обʼєкту слід використовувати синтаксис з крапкою та дефісом: вводити .- перед назвою властивості. У вікні браузера введіть число у поле для вводу (24 у нашому прикладі), потім поверніться до терміналу.

(def year-field (.getElementById js/document "years"))
;; => #'cljs.user/year-field

(.-value year-field)
;; => "24"

(set! (.-value year-field) "25")
;; => "25"

Все працює, але поки що ми побачили лише трохи більше, ніж прямий переклад з JavaScript на ClojureScript. Наступним кроком додамо обробник подій на кнопку. Обробка подій ускладнюється особливостями крос-платформної взаємодії, тому виконувати її на на простому ClojureScript не бажано.

Рішенням є використання бібліотеки Google Closure library. Для підключення цієї бібліотеки внесіть зміни до :require на початку файла core.cljs:

(ns ^:figwheel-always age.core
  (:require [goog.dom :as dom]
            [goog.events :as events]))

Тепер отримати доступ до елемента та задати його значення стало простіше. Виконайте наступні кроки у терміналі REPL та спостерігайте за змінами у вікні браузера:

(in-ns 'age.core)
(def y (dom/getElement "years"))
;; => #'age.core/y

(set! (.-value y) "26")
;; => "26"

(dom/setTextContent (dom/getElement "feedback") "This works!")
;; => nil

Щоб додати подію, слід визначити функцію від одного аргументу (а саме подію, яку треба обробити), та наказати відповідному елементу HTML очікувати на потрібну подію. Функція events/listen приймає три аргументи: елемент, подію та функцію-обробник.

(defn testing [evt] (js/alert "Responding to click"))
;; => #'age.core/testing

(events/listen (dom/getElement "calculate") "click" testing)
;; => #<[object Object]>

Після цього браузер має реагувати на натискання на кнопку. Для видалення обробника подій слід викликати функцію unlisten.

(events/unlisten (dom/getElement "calculate") "click" testing)
;; => true

Зберемо усе разом у файлі core.cljs:

(ns ^:figwheel-always age.core
  (:require [goog.dom :as dom]
            [goog.events :as events]))

(enable-console-print!)

(defn calculate
  [event]
  (let [years (.parseInt js/window (.-value (dom/getElement "years")))
        days (* 365 years)]
    (dom/setTextContent (dom/getElement "feedback")
                        (str "That is " days " days old."))))

(defn on-js-reload [])

(events/listen (dom/getElement "calculate") "click" calculate)

Додаток B: Налаштування оточення для розробки на ClojureScript

Cursive

Розділ не завершено.

Emacs

Розділ не завершено.

Vim

Розділ не завершено.

results matching ""

    No results matching ""