Перше знайомство з Moon.js

Alex Alex 05 жовтня
Перше знайомство з Moon.js

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

Бібліотека Moon.js

Moon.js - це мінімалістична JavaScript-бібліотека, призначена для розробки швидких і функціональних інтерфейсів. Вона має порівняно невеликі розміри, що дозволяє створювати на її основі досить компактні програми. Бібліотека відрізняється дуже високою продуктивністю. В Moon.js використовується підхід до проєктування інтерфейсів, заснований на компонентах. Для створення компонентів застосовуються шаблони. Ця бібліотека вельми схожа на Vue.js.

Сильні сторони Moon.js

  • Moon.js відрізняється компактними розмірами (в мініфіцірованном і стислому вигляді це - близько 2 Кб). Це менше, ніж розміри інших бібліотек і фреймворків на кшталт React і Angular.
  • Ця бібліотека відрізняється високою швидкістю рендеринга інтерфейсів.
  • Moon.js - це бібліотека, заснована на функціональних методах розробки. При роботі з нею використовується підхід до проєктування інтерфейсів, заснований на так званих «драйверах».

Початок роботи

Бібліотеку Moon.js можна включити в проект двома способами. Перший полягає в установці її з NPM. Другий - в її підключенні безпосередньо на сторінку, на якій її планується використовувати. Якщо вирішено скористатися NPM-варіантом бібліотеки, то спочатку потрібно буде встановити пакет moon-cli, інструмент командного рядка:

$ npm i moon-cli -g

В даному прикладі цей інструмент встановлюється глобально, викликати його можна з будь-якої директорії. Для створення проєкту, заснованому на Moon.js, можна виконати наступну команду:

$ moon create moon-prj

Ця команда створює новий проєкт в каталозі moon-prj. Після того, як буде завершено створення проєкту, в вашому розпорядженні буде основа майбутнього програми. Другий варіант використання Moon.js передбачає її підключення до сторінки, на якій її планується використовувати. У бібліотеки є модуль moon-browser, який дозволяє користуватися її можливостями безпосередньо на сторінці, до якої вона підключена. Отже, для підключення бібліотеки до сторінці нам потрібно включити до складу сторінки два наступних тега:

<script src="https://unpkg.com/moon"></script>
<script src="https://unpkg.com/moon-browser"></script>

Як бачите, відповідні скрипти завантажуються з CDN unpkg. У першому тезі імпортується основна бібліотека. У другому - бібліотека moon-browser. Вона відповідає за компіляцію шаблонів Moon.js, за приведення їх до вигляду, придатного для виведення браузером. Тепер, для того щоб скористатися синтаксичними конструкціями Moon.js на сторінці, потрібно буде включити їх в тег <script>, не забувши поставити його атрибут typeяк text/moon.

<!-- Підключення до сторінки зовнішнього скрипта -->
<script src="./main-script.js" type="text/moon"></script>
<!-- Або код на самій сторінці -->
<script type="text/moon">
    ...
</script>

Підключення Moon.js

Moon.js, як і інші бібліотеки та фреймворки, які використовуються для створення односторінкових застосунків, підключається до певного елемента сторінки. Зазвичай роль контейнера для Moon.js-застосунку відіграє елемент <div>:

<div id="root"></div>

Подібний елемент, який є кореневим елементом Moon.js-застосунку, розміщують в коді файлу index.html, що представляє собою точку входу в проєкт. Для підключення Moon.js до цього елементу використовується драйвер view (нижче ми поговоримо про драйвери докладніше):

Moon.use({
    view: Moon.view.driver("#root")
})

Дана конструкція повідомляє бібліотеці про те, що вона повинна підключити застосунок до елементу з ідентифікатором root. При необхідності вказати бібліотеці подібний елемент можна, скориставшись API браузера, призначеним для роботи з DOM:

Moon.use({
    view: Moon.view.driver(document.getElementById("root"))
})

Тепер поговоримо про те, як в Moon.js організована робота з даними, і про те, як за допомогою цієї бібліотеки створювати елементи інтерфейсів.

Синтаксис опису елементів інтерфейсу

Для опису Moon.js-інтерфейсів використовується мова програмування Moon View Language (MVL), яка була розроблена спеціально для вирішення даного завдання. Вона нагадує JSX. Ця мова застосовується для опису елементів і для налаштування їх взаємовідносин. Ось приклад:

<script type="text/moon">
    function aView(data) {
        return (
            <div>Hi from Moon</div>
        )
    }
</script>

Нескладно помітити те, що в цьому фрагменті Moon.js-коду, відповідального за формування елемента <div>, використовуються синтаксичні структури, що нагадують HTML. Але ці структури використовуються в JavaScript-коді. Такий JavaScript-код браузер виконати не зможе, але це від нього і не потрібно, тому що Moon.js компілює подібні конструкції в звичайний JavaScript.

Робота з даними

У Moon.js для управління візуальними зображеннями елементів і для роботи з даними використовується концепція драйверів. Тут ми поглянемо на драйвер, що дозволяє працювати з даними, а в наступному розділі поговоримо про драйвер, призначений для роботи з елементами інтерфейсу. Драйвер, призначений для роботи з даними, відповідає за зберігання даних програми і дозволяє користуватися даними там, де вони потрібні. Іншими словами, цей драйвер зберігає глобальне стан застосунку. Задати початкові дані Moon.js-застосунку можна за допомогою API Moon.use:

Moon.use({
    data: Moon.data.driver
})

Записувати нові дані в стану можна, повертаючи їх з відповідних функцій:

Moon.run(({ data }) => {
    console.log(data) // undefined
    return {
        data: "Nnamdi"
    }
})

API Moon.run відповідає за запуск програми. Коллбек, переданий цьому API, отримує посилання на глобальні дані в аргументі data. Так як на момент виклику цієї функції в data поки нічого немає, команда console.log із цього прикладу виведе undefined. Ми повертаємо з коллбека об'єкт, у якого є властивість data зі значенням Nnamdi. Цей об'єкт буде являти собою новий стан застосунку, даними якого зможуть скористатися будь-які інші функції, які звертаються до data. Механізм роботи з даними в Moon.js ми розглянули. Тепер докладніше поговоримо про роботу з елементами інтерфейсу.

Робота з елементами інтерфейсу

У Moon.js є драйвер view, який призначений для створення елементів і для монтування їх в DOM. Ми вже розглядали фрагмент коду, повторений нижче, в якому до елементу <div> підключається базовий елемент Moon.js:

Moon.use({
    view: Moon.view.driver("#root")
})

Саме тут виконується монтування елемента. Тепер функції можуть повертати елементи, які здатні замінювати старі елементи. Їх можна представляти у вигляді об'єктів, що містять властивість view, в яке записані відповідні дані. Бібліотека бере значення властивості view які повертається функцією об'єкта і записує його в елемент, підключений до елементу з ідентифікатором root.

У Moon.js використовується концепція віртуального DOM і потужний алгоритм порівняння старої і нової версій інтерфейсу. Це дозволяє бібліотеці приймати рішення про те, коли потрібно оновлювати DOM, і про те, які саме частини DOM потребують оновлення.

function handleClick() {
    return {};
}
Moon.run(() => ({
    view: <button @click=handleClick>Click Me!</button>
}));

Тут коллбек, що передається Moon.run, виводить в DOM кнопку. Відбувається це через те, що функція повертає об'єкт з властивістю view. Значення, призначене цій властивості, потрапляє в DOM. У кнопки є обробник події click, представлений функцією handleClick. Ця функція повертає порожній об'єкт, її виклик не призводить до внесення змін в DOM.

Створення елементів

Moon.js представляє розробнику великий набір допоміжних функцій, призначених для створення елементів інтерфейсів. В результаті виявляється, що елементи можна створювати, використовуючи не мову опису інтерфейсів Moon.js, а відповідні функції:

const { div, text, node, p } = Moon.view.m

Moon.js експортує функції, імена яких відповідають іменам створюваних з їх допомогою елементів. Так, функція div дозволяє створювати елементи <div>. Функція text створює текстові вузли. Функція node дозволяє створювати призначені для користувача елементи. Функція p створює елементи <p>. Як бачите, імена цих функцій ясно вказують на їх призначення.Створимо елемент <div>:

const Div = div({});

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

const Div = div({
    class: "DivClass"
});

Тут ми описали елемент <div>, в атрибут class якого має бути записано значення DivClass. Ось як створити текстовий елемент:

const Text = text({ data: "A text node" });

У властивості data об'єкта, переданого функції text, є текст для елемента. Створимо кастомний елемент:

const CustomEl = node("custom-el");

Для того щоб задати цьому елементу який-небудь атрибут, можна зробити так:

CustomEl({ "attr": "attr-value"})

Події

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

function handleClick() {
    return {};
}
Moon.run(() => ({
    view: <button @click=handleClick>Click Me!</button>
}));

В результаті на сторінку буде виведена кнопка з текстом Click Me, після натискання на яку буде викликана функція handleClick.

Компоненти

У Moon.js функції - це компоненти. Це означає, що функції можна згадувати в описі елементів інтерфейсу. Те, що повертає функція, буде включено до складу елемента. Припустимо, у нас є така функція:

function aView({ data }) {
    return <div>A View</div>
}

Ця функція, aView, повертає елемент, який може бути візуалізувати:

Moon.run(() => {
    view: <div><aView /></div>
})

Ім'я функції в цьому прикладі використовується в ролі імені елемента. В результаті виконання цього коду виявиться, що те, що повертає функція, буде поміщено в тег <div>. Коли все це потрапить в DOM, там виявиться така розмітка:

<div>
    <div>A View</div>
</div>

Розробка застосунків, заснованих на Moon.js

Для того щоб зібрати воєдино все те, про що ми щойно говорили, давайте створимо на Moon.js простий TODO-застосунок. Тут ми скористаємося відповідним прикладом , який підготовлений розробниками Moon.js. Хочу нагадати про те, що рекомендується, освоюючи нові бібліотеки і фреймворки, створювати з їх допомогою невеликі застосунки. Це дозволяє прискорити навчання і допомагає зрозуміти особливості роботи досліджуваних інструментів. Спочатку мова йде про їх засади, але з часом приходить і розуміння складніших механізмів. Ось як виглядає сторінка цього застосунку.

Перше знайомство з Moon.js

На сторінці є заголовок, поле, кнопка, і список справ, який можна поповнювати, вводячи їх опис в поле і натискаючи на кнопку. Почнемо роботу зі створення файлу index.html. Тут ми підключимо Moon.js безпосередньо на сторінку:

<html>
<body>
    <div id="root"></div>
</body>
<script src="https://unpkg.com/moon"></script>
<script src="https://unpkg.com/moon-browser"></script>
<!-- Воспользуемся скриптом, встроенным в страницу -->
<script type="text/moon">
    function viewTodos({data, view}) {
        return (
            <div>
                <input type="text" value=data.todo @input=updateTodo/>
                <button @click=createTodo>Create</button>
                <ul children=(data.todos.map(todo =>
                    <li>{todo}</li>
                ))/>
            </div>
        )
    }
    function updateTodo({ data, view }) {
        const dataNew = { ...data, todo: view.target.value };
        return {
            data: dataNew,
            view: <viewTodos data=dataNew/>
        }
    }
    function createTodo({ data }) {
        const dataNew = {
            todo: "",
            todos: [...data.todos, data.todo]
        };
        return {
            data: dataNew,
            view: <viewTodos data=dataNew/>
        }
    }
    <!-- Настройка драйверов data и view -->
    Moon.use({
        data: Moon.data.driver,
        view: Moon.view.driver("#root")
    })
    <!-- Запуск приложения -->
    Moon.run(() => {
        data: [],
        view: <viewTodos data=[]>
    })
</script>
</html>

Функція viewTodos виводить елементи, необхідні для введення відомостей про нові справи і для виведення їх у вигляді списку. Її аргументами є data та view.

Функція createTodo створює нову справу і повертає її у властивості data.

Функція updateTodo записує нову справу в стан застосунку. Зверніть увагу на обробники подій @click та @input, які є в функції viewTodos. Подія @input викликається при введенні тексту, що описує справу, в відповідне поле. При обробці цієї події викликається функція updateTodo. Аргумент view у цій функції представляє подію, що відбулася. Користуючись гею, ми звертаємося до DOM і отримуємо дані, введені в поле. Потім ці дані потрапляють в стан у вигляді властивості todo.

Подія @click викликається після натискання на кнопку. Вона виконує запис нової справи в список справ. Для вирішення цього завдання використовується функція createTodo. Ця функція звертається до властивості стану todo і записує нові дані у властивість todos, у глобальні дані та повертає його із властивістю view, встановленою для  <viewTodos>, представлений відповідною функцією, в атрибут data якого записано значення dataNew.

Це призведе до виконання повторного рендеринга viewTodos і до оновлення DOM. У список справ, виведений на сторінці, буде додано нову справу. Запустіть цю програму в браузері і поекспериментуйте з нею.

Підсумки

Ми розібрали основи Moon.js. А саме, поговорили про те, що користуватися бібліотекою можна, встановлюючи її з NPM і підключаючи до сторінок безпосередньо. Далі, ми обговорили внутрішні механізми бібліотеки: роботу з даними, обробку подій, розробку компонентів.Мені здається, що Moon.js - це приємна бібліотека. І, якщо навіть не говорити про інші переваги, вона мені симпатична через компактний розмір. 

Джерело: Introduction to Moon.js

Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Війти / Зареєструватися