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

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

Предлагаем познакомиться с онлайн-сервисами для создания интерактивных игр. С их помощью во время онлайн-урока можно разбудить интерес и повысить внимание учащихся. 

1) LearningApps

Языки. 23 языка, в том числе, русский. 

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

Закрепить полученные знания в игровой форме учащиеся смогут с помощью таких заданий: «Найти пару», «Классификация», «Заполнить пропуски», «Викторина с выбором правильного ответа», «Сортировка картинок» и других. 

Когда вы открываете упражнение в каталоге, внизу есть опции — «Создать подобное упражнение» или «Сохранить в “Моих упражнениях”». При создании упражнения откроется шаблон: заполняете по аналогии и загружаете готовое задание в курс. 

Пример задания. Задание «Составьте пару» 

Пример упражнения на сервисе LearningApps — удобно выбирать из каталога по категориям 

Конструктор, как выглядит редактор при создании подобного упражнения

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

Кабинет платформы CORE, которая интегрирована с сервисом 

2) Wordwall

Языки. 26 языков, в том числе, русский. 

Возможности. Сервис позволяет создавать интерактивные упражнения и мини-игры. Есть 33 интерактивных шаблона и 21 шаблон для печати, но часть из них — платная: все зависит от выбранного тарифного плана. 

Удобно, что после создания задания можно одним кликом переключить его на другой шаблон с сохранением учебного контента. К примеру задание «Найти пару» можно превратить в «Кроссворд» с такими же названиями фигур. 

Бесплатный пакет дает возможность создать 5 активностей в месяц. Но можно пользоваться готовыми заданиями. 

Пример задания. Викторина «Игровое шоу». 

Пример упражнения на сервисе Wordwall — в меню справа можно переключать шаблоны 

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

Как использовать платформу педагогу. Пример: для изучения иностранного языка разбить изучение лексики по узким темам и дать задания на работу с новыми словами. 

3) Quillionz

Языки. Английский язык. 

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

«Множественный выбор», «Вопросы на “да” / “нет”», «Короткий ответ», «Вставить пропущенное слово» — это на базовом тарифе. Платные тарифы дают больше возможностей: экспресс-режим, экспорт вопросов в виде PDF-файлов, .doc, QTI. 

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

Пример задания. Необходимо зарегистрироваться и зайти в личный кабинет. Откроется конструктор для работы с текстом. 

Вставляем нужный текст и нажимаем кнопку «Proceed». Появляются ключевые слова (для бесплатной версии). 


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

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

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

4) Quizlet

Языки. 18 языков, в том числе, русский. 

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

С помощью мобильных приложений материалы удобно повторять в любое время в любой момент. 

Есть бесплатная пробная недельная версия. Стоимость годового тарифа 2 320 рублей и 3 100 рублей — в зависимости от необходимого в работе функционала.

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

Так выглядит редактор при создании упражнения

Пример игры, созданной с помощью данного сервиса, можно посмотреть здесь. 

Как использовать платформу педагогу. Пример: создавать карточки для изучения лексики по актуальной теме. 

5) Wizer

Языки. 17 языков, в том числе, русский. 

Возможности. С помощью сервиса можно создавать различные учебные материалы — добавлять к ним видео, аудио, изображения и различные типы вопросов. 

Через Google Classroom или любую систему управления обучением можно поделиться материалами с учащимися. Проверять лично и оставлять персональные комментарии или настроить автоматическую систему проверки. 

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

Пример задания. Каталог с уже готовыми заданиями расположен на главной странице. Для поиска подходящего выбираем предмет, класс и язык. 

Пример задания из библиотеки 

Как использовать платформу педагогу. Пример: анализ данных по математике или информатике. 

6) Quizizz

Языки. Интерфейс на английском языке, задания можно создать на русском. 

Возможности. Сервис для создания онлайн-викторин. Учащиеся могут проходить их на мобильных устройствах, что особенно удобно при смешанном обучении. Можно создать урок — этот функционал на стадии beta-тестирования.

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

Есть тариф Super с расширенным функционалом, но и базовой версии достаточно, чтобы создавать интересные интерактивные задания. 

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

Как использовать платформу педагогу. Пример: викторины по любой области знаний. 

7) Padlet

Языки. 38 языков, в том числе, русский. 

Возможности. Сервис помогает собирать и хранить цифровые материалы — создавать доски, веб-страницы. 

Позволяет открыть доступ к созданной доске для групп  учащихся. Доски можно встраивать в персональный блог или поделиться в соцсетях и по QR-Code. 

Преподаватель может собирать коллекции дополнительных материалов по темам уроков или проводить коллективные брейн-штормы.

Пример задания. Доступна библиотека, где можно познакомиться с примерами хранения материалов. 

Планеты солнечной системы, доска

Хиты Дэвида Боуи, доска 

Как использовать платформу педагогу. Пример: можно собирать дополнительные материалы для изучения. 

8) Kahoot

Языки. 7 языков, русского языка нет. 

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

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

Режим Practice помогает в финале прохождения всех вопросов проработать ошибки. С помощью данного сервиса можно создать тест на время. Его стоит использовать в самом конце онлайн-курса в качестве итогового теста. 

Есть и другие режимы. Например, для группового прохождения теста или для соревнований. 

Пример задания. Квиз с выбором из нескольких вариантов. 

Вариант интерактивного задания на сервисе Kahoot

В этом задании из премиум-тарифа необходимо расставить слова в правильном порядке. 

Вариант интерактивного задания на сервисе Kahoot

Как использовать платформу педагогу. Создавать тесты, квизы, онлайн-игры для проверки знаний учащихся по разным темам в разных форматах. 

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

С помощью движка Blend4Web можно создавать как простые, так и относительно сложные, насыщенные интерактивные веб-приложения.
Рассмотрим создание простого приложения с использованием API Blend4Web, в котором реализуем взаимодействие с объектами 3D-сцены, например, анимируя объект при выделении его мышью.

Создание нового приложения

Для создания нового приложения следует воспользоваться менеджером проектов, входящим в состав Blend4Web SDK. Для этого требуется сначала запустить Blender (с установленным аддоном), а затем зайти на главную страницу SDK по адресу http://localhost:6687/. Там менеджер проектов будет доступен по соответствующей ссылке:

Далее следует выбрать Create New Project:

Далее нужно будет выбрать имя нового проекта, к примеру, «simple_app». В случае, если вдруг проект с таким именем уже существует, будет предложено ввести другое имя.
Также можно ввести отображаемый в браузере заголовок приложения, например, «Interactive Web Application»:

Остальные настройки оставим по умолчанию. После этого нажмем кнопку Create Project внизу данной страницы для создания приложения. Затем необходимо дождаться завершения и нажать Back to Projects:

Она вернет нас на страницу менеджера проектов, из которой можно открыть новое приложение по ссылке:

В результате мы увидим базовую сцену с простым кубиком:

Созданное нами приложение расположено внутри SDK по пути ./projects/simple_app/. Теперь, когда каркас проекта готов, можно приступать к созданию 3D-сцены и написанию логики приложения.

Подготовка и экспорт 3D-сцены

Blend-файл с базовой сценой находится в директории проекта: ./projects/simple_app/simple_app.blend. Откроем его в Блендере и вместо того, что есть по умолчанию, создадим в нем сцену с объектами, источником освещения и камерой.

Для каждого из «интерактивных» объектов сделаем простую анимацию перемещения, поворота (в режимах XYZ Euler либо Quaternion WXYZ) или масштабирования.

Также включим им опцию Selectable во вкладке Object->Selection and Outlining. Это сделает объекты доступными для выбора при клике по ним мышью.

Настроив по вкусу камеру, освещение и материалы объектов, экспортируем сцену через команду меню File -> Export -> Blend4Web (.json). Путь экспорта следует указать таким: ./projects/simple_app/assets/simple_app.json.

Добавление функционала

В директории проекта ./projects/simple_app/ в числе других будет находиться главный JS-файл приложения simple_app.js, содержащий шаблонный код. В нем и будем реализовывать простое взаимодействие пользователя с загруженной сценой.

Для реализации задуманного функционала нам понадобятся дополнительные модули:

animation.js — предоставляет API для управления анимацией объектов

container.js — методы, относящиеся к Canvas-элементу и его родительскому HTML-элементу

mouse.js — содержит ряд полезных методов, относящихся к мыши

scenes.js — API для доступа к объектам сцены

Добавим их подключение в самом начале скрипта к остальным модулям:

// import modules used by the app
var m_app       = require("app");
var m_cfg       = require("config");
var m_data      = require("data");
var m_preloader = require("preloader");
var m_ver       = require("version");

var m_anim      = require("animation");
var m_cont      = require("container");
var m_mouse     = require("mouse");
var m_scenes    = require("scenes");

В нашем примере по клику на объекте должна воспроизводиться его анимация, также будем и отменять анимацию у предыдущего выделенного объекта.
Для этого в конец функции load_cb() добавим обработчик события «mousedown» для нажатий мышью по элементу Canvas. Также при необходимости можно добавить обработчик «touchstart» для нажатий на сенсорном экране:

function load_cb(data_id, success) {
    ...
    var canvas_elem = m_cont.get_canvas();
    canvas_elem.addEventListener("mousedown", main_canvas_click, false);
    canvas_elem.addEventListener("touchstart", main_canvas_click, false);
}

Далее напишем соответствующую функцию-обработчик main_canvas_click():

function main_canvas_click(e) {
    if (e.preventDefault)
        e.preventDefault();

    var x = m_mouse.get_coords_x(e);
    var y = m_mouse.get_coords_y(e);

    var obj = m_scenes.pick_object(x, y);

    if (obj) {
        if (_previous_selected_obj) {
            m_anim.stop(_previous_selected_obj);
            m_anim.set_frame(_previous_selected_obj, 0);
        }
        _previous_selected_obj = obj;

        m_anim.apply_def(obj);
        m_anim.play(obj);
    }
}

Основная логика приложения содержится именно в ней. Алгоритм в общих чертах будет следующим:

1) Получение объекта сцены, который находился под курсором.

var x = m_mouse.get_coords_x(e);
var y = m_mouse.get_coords_y(e);

var obj = m_scenes.pick_object(x, y);

2) Отмена анимации у предыдущего выделенного объекта.

Остановка анимации:

m_anim.stop(_previous_selected_obj);

И выставление нулевого кадра, т.е. возвращение к первоначальному положению:

m_anim.set_frame(_previous_selected_obj, 0);

Для сохранения предыдущего объекта использована глобальная переменная _previous_selected_obj. Её нужно объявить где-либо, например, сразу после подключения модулей следующим образом:

var _previous_selected_obj = null;

3) Применение анимации к объекту.

Загрузка и расчет анимации, назначенной на объект в Blender’е:

Воспроизведение анимации:

Приведём код получившегося приложения целиком:

"use strict"

// register the application module
b4w.register("simple_app_main", function(exports, require) {

// import modules used by the app
var m_app       = require("app");
var m_cfg       = require("config");
var m_data      = require("data");
var m_preloader = require("preloader");
var m_ver       = require("version");

var m_anim      = require("animation");
var m_cont      = require("container");
var m_mouse     = require("mouse");
var m_scenes    = require("scenes");

var _previous_selected_obj = null;

// detect application mode
var DEBUG = (m_ver.type() == "DEBUG");

// automatically detect assets path
var APP_ASSETS_PATH = m_cfg.get_assets_path("simple_app");

/**
 * export the method to initialize the app (called at the bottom of this file)
 */
exports.init = function() {
    m_app.init({
        canvas_container_id: "main_canvas_container",
        callback: init_cb,
        show_fps: DEBUG,
        console_verbose: DEBUG,
        autoresize: true
    });
}

/**
 * callback executed when the app is initialized 
 */
function init_cb(canvas_elem, success) {

    if (!success) {
        console.log("b4w init failure");
        return;
    }

    m_preloader.create_preloader();

    // ignore right-click on the canvas element
    canvas_elem.oncontextmenu = function(e) {
        e.preventDefault();
        e.stopPropagation();
        return false;
    };

    load();
}

/**
 * load the scene data
 */
function load() {
    m_data.load(APP_ASSETS_PATH + "simple_app.json", load_cb, preloader_cb);
}

/**
 * update the app's preloader
 */
function preloader_cb(percentage) {
    m_preloader.update_preloader(percentage);
}

/**
 * callback executed when the scene data is loaded
 */
function load_cb(data_id, success) {

    if (!success) {
        console.log("b4w load failure");
        return;
    }

    m_app.enable_camera_controls();

    // place your code here
    var canvas_elem = m_cont.get_canvas();
    canvas_elem.addEventListener("mousedown", main_canvas_click, false);
    canvas_elem.addEventListener("touchstart", main_canvas_click, false);
}

function main_canvas_click(e) {
    if (e.preventDefault)
        e.preventDefault();

    var x = m_mouse.get_coords_x(e);
    var y = m_mouse.get_coords_y(e);

    var obj = m_scenes.pick_object(x, y);

    if (obj) {
        if (_previous_selected_obj) {
            m_anim.stop(_previous_selected_obj);
            m_anim.set_frame(_previous_selected_obj, 0);
        }
        _previous_selected_obj = obj;

        m_anim.apply_def(obj);
        m_anim.play(obj);
    }
}


});

// import the app module and start the app by calling the init method
b4w.require("simple_app_main").init();

Веб-приложение, разобранное в статье, является простым, но в то же время интерактивным. Это минимальный пример того, что позволяет движок Blend4Web и его API.

Исходные файлы приложения и сцены находятся в составе бесплатного дистрибутива Blend4Web SDK по пути ./projects/simple_app/.

Ссылка на приложение в отдельном окне

Изменения

[2014-05-08] Изначальная публикация.

[2014-06-30] Уточнен текст об опции инициализации alpha.

[2014-07-07] Незначительные правки текста об исходных файлах приложения.

[2014-07-22] Изменен путь к приложению.

[2014-08-06] Обновлен код примера по причине изменения API получения объекта под курсором.

[2014-10-29] Обновлен текст статьи по причине изменения API.

[2014-11-28] Правки текста об исходных файлах приложения.

[2015-04-23] Правки текста об исходных файлах приложения.

[2015-05-08] Обновлен текст статьи по причине изменения API.

[2015-09-30] Небольшие изменения в статье.

[2015-10-02] Статья переписана с учетом системы управления проектами.

[2017-01-12] Исправлены некорректные/битые ссылки.

[2017-04-21] Обновлен текст статьи.

Вы владеете HTML и CSS и умеете создавать простые (и не очень) статические веб-страницы, а хотели бы вдохнуть в них больше «жизни» и интерактивности? У вас есть работы (картины, фотографии, стихи, коллекция марок и т. п.), которыми вам хотелось бы поделиться с миром, но создание сайта-портфолио или блога, куда можно их разместить и без лишних усилий обновлять, вам не под силу? Или мечтаете вести дневник путешественника, или собирать необычные кулинарные рецепты, или отслеживать свою фитнес-активность и делать всё это онлайн на собственном сайте? Возможно, у вас есть любимый питомец, уход за которым требует особых процедур, и их обязательно нужно отслеживать и оперативно фиксировать? 

Но от упоминания JavaScript вас бросает в лёгкую (а иногда и не очень) дрожь, а количество технологий и концепций, которыми нужно овладеть, чтобы реализовать ваши задумки, приводит вас в замешательство и отчаяние? В итоге вы задаётесь вопросами: «Почему веб-программирование должно быть таким трудным? Неужели нельзя что-то придумать, чтобы сделать его проще?». 

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

Автор оригинальных картинок: Mart Virkus (toggl.com)

Маститые и умудрённые опытом фронтенд-разработчики, не спешите закрывать статью с криками, что сейчас тут будут что-то «втирать» новичкам и вам здесь делать нечего. Я уверен, вы тоже сможете почерпнуть для себя что-то полезное. Главное, помните: если что-то станет простым для новичков, это автоматически станет простым для всех! А значит, в какой-то мере упростит жизнь и вам. Это неплохо, согласитесь?

Итак, к делу! Эта статья будет целиком и полностью посвящена Mavo.

Mavo — это новый подход к разработке интерактивных веб-приложений только за счёт написания HTML и CSS, без необходимости написания кода на языке JavaScript и разворачивания собственного сервера.

Mavo разрабатывается группой учёных Haystack Group лаборатории компьютерных наук и искусственного интеллекта Массачусетского технологического института (MIT CSAIL) под руководством Лии Веру.

Следуй за белым кроликом!

Хотите узнать чуть больше о том, какие идеи были положены в основу Mavo, какие черты своих предшественников он впитал, какие развил, а от каких пришлось отказаться и почему? Тогда очень рекомендую к прочтению эти две публикации, специально подготовленные для ежегодного форума, посвящённого иновациям в области человеко-машинного взаимодействия, — The ACM Symposium on User Interface Software and Technology (UIST):

  1. Mavo: Creating Interactive Data-Driven Web Applications by Authoring HTML.
  2. Extending a Reactive Expression Language with Data Update Actions for End-User Application Authoring.

Небольшое отступление для читателей из России!

Сайт Mavo хостится на серверах Netlify, адреса которых попали в «чёрный список» в результате «войны» с мессенджером Telegram. А значит, ресурсы, размещённые на этих серверах, равно как и все связанные с ними сервисы заблокированы на территории России (по крайней мере, на момент написания этой статьи).

Есть, правда, и хорошая новость: мы с Лией Веру (Lea Verou) активно работаем над решением этой проблемы. Надеюсь, в скором времени мы и это уладим. А до тех пор, пожалуйста, пользуйтесь, например, VPN для работы с Mavo (это справедливо как при доступе к сайту Mavo, так и при изучении демо-приложений на Codepen, а также и при создании собственных веб-приложений).

(ОБНОВЛЕНИЕ) Те, кто не готов и/или не хочет связываться с VPN, могут поиграть с Mavo на Stackblitz или подключить его к свому проекту через cdnjs.

Я убежден (и, думаю, я не одинок), что лучший способ «пощупать» новую технологию и оценить, на что она способна, — это построить что-то полезное с её помощью. Не очень сложное, иначе мы можем просто не увидеть леса за деревьями, но нужное. Осталось только выбрать что. О! Есть идея.

Думаю, многие из вас изучают иностранный язык (может быть, для кого-то таким является язык программирования). И, скорее всего, для его изучения вы используете какое-нибудь приложение. Новые слова в этих приложениях обычно изучают с помощью карточек. Кстати, этот приём изучения иностранного языка отлично работает и в офлайне. Но сейчас не об этом.

Так вот, почему бы нам с вами вместе не разработать такое приложение? Назовём его… (барабанная дробь!) «Карточки». Это будет полноценное CRUD-приложение для изучения иностранного языка с помощью карточек, которое позволит:

  • создавать, удалять, изменять карточки, а также упорядочивать их с помощью перетаскивания;
  • импортировать карточки в приложение из файла и экспортировать их в файл;
  • отслеживать прогресс (функция самооценки).

Финальная версия приложения будет выглядеть примерно так:

Годится? Надеюсь, да. Тогда в путь!

На протяжении статьи я проведу вас по всем этапам разработки приложения. И по ходу чтения вы будете встречать фрагменты, помеченные с помощью особых меток.

Следуй за белым кроликом!

Во фрагментах, помеченных таким образом, содержится важная, но дополнительная информация про Mavo. При первом чтении эти фрагменты можно пропускать, не боясь упустить главную мысль.

Практика — путь к совершенству!

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

Запоминай через руки!

Готовы, следуя за нитью моего изложения, сразу применять новые знания на практике? Отлично! Ведь, как известно, мы лучше запоминаем то, что делают наши руки. Вы можете постепенно разрабатывать своё приложение, читая статью от начала и до конца, либо можете начать с любого интересующего вас этапа. 

В таких фрагментах будут приводиться ссылки на соответствующие версии приложения на Codepen.

Теперь всё. Начинаем!

Статическая веб-страница

Чтобы проиллюстрировать, как Mavo расширяет возможности HTML, мы создадим статическую HTML-страницу, которую затем с помощью Mavo превратим в полнофункциональное веб-приложение.

Предположим, у нас есть следующий HTML-код внутри элемента <body>:

<header>
  <h1>Карточки</h1>
</header>
<main>
  <article>
    <p>Слово или фраза</div>
    <p>Перевод</div>
  </article>
</main>

В приведённом выше фрагменте кода элемент <article> соответствует одной карточке.

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

Хотите полностью увидеть исходный код? Вы можете сделать это здесь.

Подключаем Mavo

Пока у нас есть только статический макет. Настало время превратить его в полноценное веб-приложение. Вот тут как раз Mavo и вступает в игру!

Чтобы использовать Mavo, нам необходимо подключить его JavaScript- и CSS-файлы к нашей странице. Для этого добавим в элемент <head> две следующие строки:

<head>
  ...
  <script src="https://get.mavo.io/mavo.min.js"></script>
  <link rel="stylesheet" href="https://get.mavo.io/mavo.css">
  ...
</head>

Небольшое отступление для читателей из России!

Вы можете загрузить соответствующие файлы из репозитория Mavo и подключить их к своей странице аналогичным образом.

(ОБНОВЛЕНИЕ) Вы также можете подключить Mavo к свому проекту через cdnjs.

Следуй за белым кроликом!

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

Подключив Mavo, нам необходимо указать, какой элемент страницы будет содержать наше будущее приложение. Таким элементом может быть любой HTML-элемент, даже <body> или <html>! К этому элементу нам необходимо добавить атрибут mv-app, а в качестве его значения указать имя нашего приложения — уникальный в пределах всей HTML-страницы идентификатор. Элемент с атрибутом mv-app называется корневым элементом приложения.

Следуй за белым кроликом!

Если не присвоить атрибуту mv-app значение и при этом в том же самом элементе нет ни одного из атрибутов: id или name, — Mavo автоматически присвоит приложению имя mavo1, mavo2 и т. п.

Однако я настоятельно рекомендую вам явно указывать имя приложения, так как оно используется (явно и неявно) в других местах приложения.

Запоминай через руки!

Итак, пусть в нашем случае элемент <main> будет содержать будущее приложение. Добавим к нему атрибут mv-app, а в качестве его значения укажем имя нашего приложения — flashcards:

<main mv-app="flashcards">
  ...
</main>

Атрибут property

Теперь пора сообщить Mavo, какие элементы приложения являются важными, то есть будут редактироваться и/или сохраняться, а также, возможно, будут использоваться в выражениях (но об этом чуть позже — запаситесь терпением).

В нашем приложении пока есть два таких элемента — это элементы <p>. Добавим к этим элементам атрибут property, сообщив тем самым Mavo, что эти элементы содержат данные, с которыми нужно работать. Элементы с атрибутом property называются свойствами (properties).

Следуй за белым кроликом!

Атрибут property можно добавить к любому HTML5-элементу — Mavo знает, как сделать его редактируемым. Например, содержимое элемента <span> вы сможете редактировать вручную с клавиатуры, а значение элемента <time> (дату или время) вы сможете установить с помощью соответствующего виджета.

Набор правил, по которому Mavo делает элементы редактируемыми, может быть легко расширен с помощью плагинов. Нужно, чтобы пользователь мог форматировать текст с помощью панели инструментов, аналогичной той, что есть у таких программ, как Microsoft® Wordpad или Microsoft® Word, т. е. работать с текстом, как в любом WYSIWYG-редакторе? Или вы хотите разрешить пользователю набирать текст с использованием команд языка Markdown? Нет никаких ограничений. Просто активируйте соответствующие плагины. Нет подходящего плагина? Не проблема. Напишите свой. Mavo поддерживает соответствующий функционал прямо «из коробки».

Имейте в виду, что значение атрибута property должно описывать назначение элемента так, как обычно его описывают значения атрибутов id или class.

Превратим наши элементы <p> в свойства:

...
  <p property="source">Слово или фраза</p>
  <p property="translation">Перевод</p>
...

Следуй за белым кроликом!

Если у элемента уже есть атрибут id, class или itemprop, точно описывающий его назначение, можно не присваивать атрибуту property значение. Например, одно из свойств нашего приложения можно было бы описать так: <p property class="source">.

Заметили какие-нибудь изменения в нашем приложении после добавления в него свойств? Уверен, что да. Вверху приложения появилась панель инструментов Mavo (Mavo bar) с кнопкой Edit. Эта кнопка позволяет переключаться между двумя режимами работы приложения: режимом чтения и режимом редактирования. Сейчас наше приложение находится в режиме чтения. Это означает, что мы не можем редактировать его данные непосредственно в окне браузера.

Следуй за белым кроликом!

Панель инструментов Mavo полностью настраиваемая (как и все элементы интерфейса, автоматически добавляемые Mavo в приложение): вы можете изменить её положение, внешний вид, задать набор доступных на ней кнопок или даже назначить ей свой HTML-элемент.

Чуть позже мы увидим один из вариантов такой кастомизации панели инструментов Mavo. А пока, если хотите чуть подробнее познакомиться с описанными возможностями, почитайте документацию на официальном сайте.

Что ж, самое время переключиться в режим редактирования и познакомиться с ним. Нажмите кнопку Edit.

Что же изменилось? Поменялось название кнопки: теперь её имя Editing. Это визуальный сигнал для нас: внимание, мы находимся в режиме редактирования. Попробуйте навести курсор мыши на любой из абзацев с текстом («Слово или фраза» или «Перевод»). Mavo сообщает нам с помощью жёлтой подсветки, что по этому фрагменту можно щёлкнуть и отредактировать его.

Смелее! Щёлкните по тексту и внесите в него изменения. Ну разве это не здорово?! Мы можем редактировать содержимое страницы непосредственно в окне браузера!

Практика — путь к совершенству!

Предположим, что помимо изучаемого слова (или фразы) и его перевода, мы хотим, чтобы на карточке присутствовал пример употребления этого слова (фразы) в предложении. Мы же знаем, что именно так нужно учить иностранные слова — в контексте, правда?

Усовершенствуйте приложение, добавив в него недостающий элемент, и дайте ему имя, например, example.

Атрибут mv-multiple

На данный момент в нашем приложении всего одна карточка. Откровенно говоря, это не очень-то полезно! Для полноценного приложения нам не хватает возможности добавлять новые карточки, удалять ненужные, а также переставлять карточки так, как нам удобно. Но как мы можем всё это реализовать?

Запоминай через руки!

Будучи разработчиками приложения, мы могли бы добавить в него новые карточки, просто добавив ещё элементов <article> в его HTML-код. Но тогда каким образом пользователь сможет добавлять и удалять карточки самостоятельно?

К счастью, в Mavo есть то, что позволит нам добавить в приложение соответствующий функционал на раз-два — атрибут mv-multiple. С помощью этого атрибута мы указываем Mavo, какие элементы приложения могут быть размножены. Атрибут mv-multiple превращает элемент, к которому он добавлен, в редактируемую коллекцию элементов (collection). При этом Mavo добавит к элементам такой коллекции элементы управления, с помощью которых можно добавлять в коллекцию новые элементы, удалять существующие и упорядочивать элементы коллекции с помощью перетаскивания. И да, стиль этих элементов управления тоже полностью настраиваемый!

Следуй за белым кроликом!

Если добавить атрибут mv-multiple к элементу без атрибута property, Mavo автоматически исправит эту ситуацию: добавит property со значением collection (или collection2, collection3, чтобы сохранить уникальность имени).

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

Что ж, давайте добавим атрибут mv-multiple к элементу <article> приложения, чтобы превратить нашу одинокую карточку (flashcard) в полноценную редактируемую коллекцию карточек (обратите внимание, что при этом мы добавили ещё и атрибут property):

<article property="flashcard" mv-multiple>
  ...
</article>

Следуй за белым кроликом!

Mavo позволяет указать имя свойства в качестве значения атрибута mv-multiple. Таким образом, мы могли бы описать коллекцию карточек чуть короче: <article mv-multiple="flashcard">.

Обратите внимание, что атрибут mv-multiple должен добавляться к размножаемому элементу, а не к контейнеру, в котором размещается коллекция. Очень распространена ошибка, когда разработчики пишут <ul mv-multiple> вместо <li mv-multiple>. И поначалу подобную ошибку достаточно трудно обнаружить. Пока, например, используемые в приложении стили не сделают её очевидной.

Теперь смело переключайтесь в режим редактирования. Заметили, что под карточкой появилась кнопка Add flashcard? Устроим ей тест-драйв: добавьте с её помощью пару новых карточек. Это просто что-то невероятное: мы можем динамически добавлять новые карточки в приложение, даже если в его исходном коде нет соответствующих элементов!

Следуй за белым кроликом!

Заметили, что добавление атрибута property к элементу <article> не сделало его содержимое редактируемым? Mavo считает этот элемент группой. Так происходит, когда атрибут property добавляется к элементу, содержащему внутри себя другие свойства, то есть элементы с атрибутом property.

Но и это ещё не всё! Наведите курсор мыши на любую из карточек. Видите, что у правого верхнего угла карточки Mavo добавил три новые кнопки (слева направо): для удаления карточки, добавления новой и перемещения существующей. И наводя курсор мыши на любую из этих кнопок, можно легко догадаться по генерируемой Mavo подсветке, к какой именно карточке они относятся.

Удобно, правда?

Следуй за белым кроликом!

Генерируемые Mavo кнопки работы с элементами коллекции полностью настраиваемые. Например, вы можете создать свою собственную кнопку перемещения элемента коллекции, добавив класс mv-drag-handle к соответствующему HTML-элементу.

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

Атрибут mv-storage

Запоминай через руки!
https://codepen.io/dsharabin/pen/WNeYwpj

Теперь, когда основной интерфейс будущего приложения разработан, предлагаю сделать следующее:

  1. Переключитесь в режим редактирования (если вы не сделали этого раньше).
  2. Добавьте несколько карточек, указав на каждой из них слово и его перевод.
  3. Вернитесь в режим чтения.
  4. И… обновите страницу.

Ой! Куда же делись все данные, которые мы только что ввели? Неужели Mavo не должен был сохранить их? Что пошло не так? Где мы ошиблись?

Только спокойствие! На самом деле, мы никогда не указывали Mavo, что он должен сохранять редактируемые данные. Тем более мы не указывали, где конкретно он должен их сохранять.

Так давайте сделаем это сейчас. Для этого в Mavo есть специальный атрибут — mv-storage. Осталось только выяснить, какие значения он может принимать. И оказывается, Mavo открывает нам широчайшие возможности. А плагины — открывают ещё большие!

Пусть наше приложение сохраняет данные в локальном хранилище браузера — localStorage. Это самый простой из доступных в Mavo вариантов и отлично подходит для нашего первого приложения. Всё, что нам нужно сделать, — просто добавить атрибут mv-storage со значением local к корневому элементу приложения (так называется элемент с атрибутом mv-app, помните?):

<main mv-app="flashcards" mv-storage="local">
  ...
</main>

А теперь взгляните на панель инструментов Mavo. Заметили новую кнопку Save? Помимо прямого назначения — сохранять изменения в приложении — у неё есть ещё одна полезная функция. Попробуйте отредактировать данные ещё раз. Обратите внимание, что кнопка Save теперь подсвечена. Наведите на неё курсор мыши, и Mavo подсветит вам данные, которые вы отредактировали, но не сохранили!

Здорово, да?

Нажмите кнопку Save и обновите страницу (при этом не обязательно переключаться в режим чтения). Ну что, теперь ваши данные сохранились? Отлично! Мы стали ещё на один шаг ближе к полноценному веб-приложению.

Атрибут mv-autosave

Сейчас наше приложение работает так, что пользователь должен нажимать кнопку Save всякий раз, когда ему нужно сохранить внесённые в приложение изменения. Это правильно с точки зрения сохранения жизненно важной информации, но часто пользователи забывают это делать. Как же быть? Вот бы наше приложение могло сохранять данные автоматически через какие-то промежутки времени! «А что, это реально можно сделать с помощью Mavo?» — спросите вы. А я с радостью и гордостью отвечу, что да, можно!

Итак, чтобы научить приложение автоматически сохранять изменения, вносимые пользователем в данные, мы можем воспользоваться атрибутом mv-autosave. Добавить его нужно к корневому элементу приложения. Значение этого атрибута — количество секунд, которое должно пройти с момента внесения пользователем изменений в данные до их сохранения приложением. Внесём соответствующие изменения в наше приложение:

<main mv-app="flashcard" mv-storage="local" mv-autosave="3">
  ...
</main>

Следуй за белым кроликом!

Атрибут mv-autosave="3" предписывает Mavo сохранять вносимые в данные изменения раз в три секунды. Наличие подобного рода задержки между сохранениями становится принципиально важным, если выбранный для сохранения данных сервис (бэкенд) хранит историю их изменения (например, GitHub и Dropbox). Отсутствие такой задержки сделает историю изменений просто-напросто бесполезной.

Чтобы заставить Mavo сохранять изменения немедленно, можно задать атрибут mv-autosave="0" или просто mv-autosave. При этом с панели инструментов Mavo будет удалена (за ненадобностью) кнопка Save.

Чтобы увидеть и оценить внесённые в приложение изменения, ещё раз обновите данные на какой-либо из карточек и обратите внимание на кнопку Save. Заметили? Сначала она была подсвеченной, но через три секунды погасла, указывая тем самым, что несохранённых данных в приложении нет. Теперь все изменения сохраняются автоматически!

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

<main mv-app="flashcards" mv-storage="local" mv-autosave="3">
  <article property="flashcard" mv-multiple>
    <p property="source">Слово или фраза</p>
    <p property="translation">Перевод</p>
  </article>
</main>

Практика — путь к совершенству!

Мы почти закончили с альфа-версией нашего приложения. Ура-ура! Теперь ваша очередь сделать его ещё лучше. Не волнуйтесь! Вы вооружены всеми необходимыми знаниями, чтобы выполнить задание, которое я вам предложу.

Усовершенствуйте приложение так, чтобы карточки, объединённые общей тематикой, можно было собирать в группы. Например, в одну группу входят все слова, имеющие отношение к одежде, в другую — названия профессий, в третью — названия продуктов питания и т. п.

Подсказки!

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

  1. Какой HTML-элемент вы будете использовать в качестве группирующего элемента (группы)? Пользователям приложения было бы удобно, если бы группе карточек можно было дать имя (название темы), а также если бы эту группу можно было сворачивать при необходимости до её заголовка.
  2. Какой атрибут (атрибуты) вы добавите к выбранному элементу (если, конечно, будете что-то добавлять). Будет ли этот элемент свойством или коллекцией?
  3. Будет ли у пользователей приложения возможность добавлять новые группы карточек, удалять ненужные, перемещать как сами группы, так и карточки между разными группами?

Вы, кстати, можете решить, что объединять карточки в группы с помощью отдельных элементов — не ваш метод. И это нормально. Может быть, вы захотите просто добавить к карточкам соответствующие теме метки (хэштеги). И это тоже будет прекрасное решение!

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

Атрибут mv-bar

Продолжим расширять функционал нашего приложения. Мы настроили его так, что данные пользователя хранятся в локальном хранилище браузера. Но наше приложение остаётся однопользовательским: пользователи не могут делиться своими карточками с другими пользователями. А было бы здорово иметь такую возможность! Да и учить иностранный язык в компании куда веселее, не так ли?

Есть ли в Mavo способ разрешить пользователям экспортировать из приложения свои карточки и импортировать в него чьи-то чужие? Нам повезло! И этот функционал поддерживается в Mavo, как говорится, «из коробки». Конечно, это не сделает наше приложение многопользовательским в каноническом понимании этого слова, но наличие подобного функционала — уже немало для столь простого приложения, согласитесь.

Запоминай через руки!

Для подобных задач в Mavo есть атрибут mv-bar, с помощью которого можно указывать, какие кнопки отображаются на панели инструментов Mavo (если там вообще нужны какие-либо кнопки). Обычно этот атрибут добавляется к корневому элементу приложения. Сами кнопки имеют очень логичные (с точки зрения их наименования на английском языке) идентификаторы. Вот лишь некоторые из них: edit, import, export.

Поскольку мы хотим лишь добавить кнопки к уже имеющемуся на панели инструментов Mavo набору, мы можем воспользоваться так называемым относительным синтаксисом (relative syntax). Такой синтаксис позволяет нам добавлять и удалять кнопки из дефолтного набора без необходимости явно перечислять все кнопки, входящие в него. Всё, что нам достаточно сделать в нашем случае, — просто начать значение атрибута mv-bar с ключевого слова with, а затем перечислить (через пробел) идентификаторы нужных нам кнопок:

<main mv-app="flashcards"
      mv-storage="local"
      mv-autosave="3"
      mv-bar="with import export">
      ...
</main>

Практика — путь к совершенству!

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

Выражения. MavoScript

Перефразируя известную фразу, произнесённую персонажем Евгения Евстигнеева в знаменитом советском фильме «Берегись автомобиля», спрошу: «А не замахнуться ли нам в нашем приложении на статистику?!» Предлагаю отображать где-то вверху приложения общее количество карточек в нём. Заинтригованы? На это я и рассчитывал.

Но прежде чем суметь «замахнуться» и реализовать намеченное, нам нужно узнать кое-что новое о Mavo.

Мы уже знаем, что важные элементы приложения (которые, в частности, можно редактировать и сохранять) называются свойствами. Напомню, это элементы, для которых указан атрибут property. Значение этого атрибута — имя свойства, описывающее его роль в приложении.

Так вот, мы можем использовать значение любого свойства, ссылаясь на него, в любом месте внутри приложения Mavo (даже в значениях HTML-атрибутов). Для этого нужно просто заключить имя свойства в квадратные скобки. Вот так: [имяСвойства]. Эта запись является примером так называемого простого выражения. Простые выражения позволяют нам производить вычисления всякий раз, как только что-то в приложении меняется, то есть реактивно.

Следуй за белым кроликом!

Язык выражений, поддерживаемый Mavo, называется MavoScript. Он очень похож на язык формул в электронных таблицах (таких как Microsoft® Excel, Apple Numbers или Google Sheets) и позволяет производить вычисления и другие операции с числами, текстом, списками и т. п.

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

Плюс, MavoScript позволяет работать с данными, имеющими иерархическую структуру.

Более подробно о выражениях Mavo и языке MavoScript можно почитать в официальной документации.

Запоминай через руки!

Перейдём от слов к делу и посмотрим на реактивность в действии. В качестве эксперимента, давайте добавим выражение [source] внутрь свойства flashcard. Например, между свойствами source и translation:

...
  <p property="source">Слово или фраза</p>
  [source]
  <p property="translation">Перевод</p>
...

Какие же изменения произошли в нашем приложении? Как минимум, мы видим, что значение свойства source отображается в карточке дважды. Так? Так!

Идём дальше. Переключимся в режим редактирования и попробуем изменить значение свойства source. Видите, что происходит в то время, как вы меняете значение этого свойства? Значение выражения [source] реактивно вычисляется, и изменения, которые вы вносите в значение свойства source, автоматически отображаются ниже: там, где мы использовали выражение. Ну не чудо ли?!

Это, разумеется, здорово, но пока мы не приблизились к решению нашей задачи — отображению информации о количестве карточек в приложении. Почему? Просто выражение [source], помещённое внутрь карточки, всегда будет возвращать ровно одно значение — значение свойства source именно этой карточки. А нам бы нужно как-то добраться до всех карточек в приложении.

А что если теперь мы поместим выражение [source] не внутри свойства flashcard, а снаружи? Вот так:

...
  [source]
  <article property="flashcard" mv-multiple>
    ...
  </article>
...

Как это будет отличаться от рассмотренного ранее случая? Чтобы увидеть эти самые изменения, добавьте в приложение несколько карточек. Обратите внимание, что теперь вместо одного значения над карточками мы видим список разделённых запятыми значений свойства source всех(!) имеющихся в приложении карточек. Если мы посчитаем, сколько значений в этом списке, то получим количество карточек в приложении. Согласны?

Осталось устранить одно маленькое логическое противоречие. Какое? Не кажется ли вам, что логичнее было бы считать количество самих карточек, а не количество значений их свойства source? В конце концов, добавляемая в приложение карточка уже существует до того, как пользователь заполнит её свойство source или translation. Как же поступить? Я предлагаю просто скорректировать выражение и сделать его более логичным: вместо [source] написать [flashcard]. В итоге получим:

...
  [flashcard]
  <article property="flashcard" mv-multiple>
    ...
  </article>
...

Как же отразились внесённые нами изменения на том, что мы видим в приложении? У нас всё ещё есть список разделённых запятыми значений, но значения эти теперь являются комплексными значениями — объектами. Каждый объект соответствует одной карточке и содержит все её свойства (даже если карточка пустая(!)).

Таким образом, теперь у нас есть, что посчитать (количество объектов, соответствующих карточкам, в списке), но остаётся вопрос, как это сделать. Что ж, у Mavo есть ответ и на этот вопрос. В MavoScript есть функция count(), которая позволит нам посчитать количество элементов в списке.

Следуй за белым кроликом!

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

Дело за малым — научиться правильно использовать функции в выражениях. Есть всего пара моментов, которые нужно иметь в виду.

  1. Функции являются частью выражения, следовательно, в квадратные скобки заключается всё выражение, а не функция в отдельности.
  2. Вкладывать одни квадратные скобки в другие нельзя.

Что ж, предлагаю испробовать функцию count() для подсчёта количества карточек в приложении в действии. А заодно и увидеть на примере, как правильно записать выражение с функцией:

...
<span>[count(flashcard)] шт.</span>
<article property="flashcard" mv-multiple>
  ...
</article>
...

Мы получили ровно то, к чему стремились, — теперь наше приложение показывает полезную статистику!

Практика — путь к совершенству!

Надеюсь, вы уже достаточно разогрелись и готовы продолжить экспериментировать с Mavo и… статистикой. Предупреждаю, здесь задание будет чуть позаковыристее, и вам придётся кое-что самостоятельно изучить. Но не волнуйтесь, нужными подсказками я вас вооружу.

Усовершенствуйте приложение так, чтобы статистика отображалась не только по общему количеству карточек в приложении, а также отдельно по каждой группе карточек (если вы добавляли соответствующий функционал ранее).

Подсказка!

Вам может понадобиться умение отбирать карточки, удовлетворяющие определённому критерию, и подсчитывать их количество. Для этих целей вам пригодится оператор where или функция filter().

Самооценка

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

Предлагаю остановиться на очень полезной и в то же время модной (можно сказать, хайповой) функции — функции самооценки.

Запоминай через руки!

Итак, добавим в наше приложение две кнопки: Плохо и Хорошо. Какого поведения мы ожидаем от приложения, когда пользователь нажимает эти кнопки? В принципе, идея достаточно простая:

  • если пользователь нажал кнопку Плохо, это означает, что он ещё не выучил содержащееся на карточке слово (фразу), и приложение должно переместить её в начало — пользователь при запуске приложения будет видеть эту карточку сразу;
  • если пользователь нажал кнопку Хорошо, это означает, что он выучил соответствующее слово (фразу), и приложение должно переместить карточку в конец, чтобы предоставить пользователю возможность поработать как можно раньше с карточками, которые он ещё не выучил.

«И мы правда сможем реализовать этот функционал, не прибегая к программированию на JavaScript?» — удивитесь вы. Да. Разве я не упоминал, что Mavo — чрезвычайно мощный инструмент и может вооружить нас всем необходимым?!

Теперь, когда мы определились с тем, что мы хотим сделать, нужно провести небольшие подготовительные работы и добавить соответствующие элементы в наше приложение:

...
<article property="flashcard" mv-multiple>
  ...
  <section>
    <h2>Оцените себя</h2>
    <button> Плохо</button>
    <button> Хорошо</button>
  </section>
</article>
...

Атрибут mv-action

Mavo предоставляет нам возможность описывать собственные правила, по которым должны обрабатываться пользовательские данные нашим приложением, — так называемые настраиваемые действия (custom actions).

Чтобы определить настраиваемое действие, необходимо добавить атрибут mv-action к соответствующему элементу приложения. Описанное с помощью данного атрибута действие выполняется при каждом щелчке по элементу, к которому добавлен этот атрибут. Это как раз соответствует тому, какое поведение мы ожидаем от кнопок самооценки — Плохо и Хорошо.

Следуй за белым кроликом!

Если добавить атрибут mv-action к элементу <form>, соответствующее настраиваемое действие выполнится при отправке формы.

Значением атрибута mv-action является выражение. При построении этого выражения можно использовать любые операции и функции, предоставляемые нам MavoScript, а также несколько специальных функций манипулирования данными: add(), set(), move() и delete().

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

И ещё один момент: Mavo ожидает в качестве значения атрибута mv-action выражение. А раз так, то нет необходимости отдельно выделять его с помощью квадратных скобок. Таким образом, правильно будет написать mv-action="выражение", а не mv-action="[выражение]". Более того, если вы напишете квадратные скобки, они будут считаться частью выражения, и вы можете получить не совсем тот результат, которого ожидаете.

Итак, вернёмся к реализации функции самооценки. При нажатии кнопок Плохо и Хорошо мы должны перемещать карточку внутри коллекции карточек на новое место: первое или последнее. Именно это действие позволяет реализовать функция move(). В качестве первого аргумента функции нужно указать перемещаемую карточку, а в качестве второго — новое место (позицию) этой карточки в коллекции. Имейте в виду, что элементы коллекции нумеруются с нуля, то есть первая карточка имеет в коллекции позицию 0.

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

...
<article property="flashcard" mv-multiple>
  ...
  <button mv-action="move(flashcard, 0)"> Плохо</button>
  ...
</article>
...

Обратите внимание, что в значении атрибута mv-action мы ссылаемся на свойство flashcard внутри самого этого свойства. Это позволяет нам работать с текущей карточкой и перемещать именно её.

Если мы попытаемся по аналогии реализовать и вторую часть функционала самооценки, то неминуемо столкнёмся с проблемой. Можете, не заглядывая вперёд, догадаться, с какой? 

Вспомним, что происходит при нажатии кнопки Хорошо: соответствующая карточка перемещается в конец коллекции, то есть становится последней. А чтобы сделать карточку последней, нам нужно знать, сколько всего карточек в коллекции (приложении). К счастью, мы уже знаем, как решить задачу вычисления количества карточек в приложении, и даже реализовали соответствующий функционал. Сможем ли мы воспользоваться найденным ранее способом решения в этой новой ситуации?

К сожалению, нет. И вот почему: чтобы подсчитать количество карточек в коллекции, мы ссылались на соответствующее свойство — flashcard — вне самого этого свойства. Но в этом случае нам пришлось бы сослаться на свойство flashcard внутри него. То есть нам пришлось бы написать что-то типа такого:

...
<article property="flashcard" mv-multiple>
  ...
  <button mv-action="move(flashcard, count(flashcard))">
     Хорошо
  </button>
  ...
</article>
...

И это не сработает! Вы можете легко в этом убедиться экспериментальным путём.

Так как же нам быть в этой ситуации?

Вычисляемые свойства. Элемент <meta>

Итак, с одной стороны, мы знаем, что выражение [count(flashcard)] возвращает в качестве результата количество карточек в приложении, если оно записано вне свойства flashcard. С другой стороны, нам необходимо использовать результат этого выражения внутри свойства flashcard. Да, дилемма!

Чтобы её разрешить, нам нужно суметь вычислить значение выражения [count(flashcard)] вне свойства flashcard и каким-то образом сохранить результат, чтобы впоследствии можно было его использовать в любом месте приложения. А в нашем случае — внутри свойства flashcard. Для решения такого рода задач в Mavo есть, так называемые, вычисляемые свойства (computed properties).

Запоминай через руки!

Для хранения результатов промежуточных вычислений, которые мы могли бы позже использовать в приложении, нужно выделить в коде отдельный HTML-элемент. И хотя в качестве такого элемента подойдёт любой HTML-элемент, рекомендуется использовать элемент <meta>: <meta property="имяСвойства" content="[выражение]">. У этого способа хранения результатов промежуточных вычислений есть неоспоримое преимущество: вне режима редактирования элемент <meta> скрыт как визуально, так и семантически.

Следуй за белым кроликом!

Имейте в виду, что по умолчанию вычисляемые свойства, в отличие от обычных свойств, не сохраняются.

Добавим вычисляемое свойство flashcardCount в приложение. Но не забывайте, что мы должны добавить это свойство обязательно вне свойства flashcard (но использовать его значение мы сможем в любой части приложения):

...
<meta property="flashcardCount" content="[count(flashcard)]">
<article property="flashcard" mv-multiple>
    ...
</article>
...

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

...
<meta property="flashcardCount" content="[count(flashcard)]">
<article property="flashcard" mv-multiple>
  ...
  <button mv-action="move(flashcard, flashcardCount)">
     Хорошо
  </button>
</article>
...

Вот мы и закончили! Наше приложение готово. Поздравляю!

Практика — путь к совершенству!

Есть и другой способ решения этой задачи — с помощью специального свойства $all.

Специальное свойство $all, использованное внутри коллекции, соответствует ей всей. Таким образом, отпадает необходимость прибегать к вычисляемому свойству для работы со всей коллекцией внутри этой коллекции. Попробуйте самостоятельно применить специальное свойство $all вместо вычисляемого свойства flashcardCount для реализации функционала самооценки другим способом. Какой из способов вам нравится больше? Почему?

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

Выводы

Мы прошли с вами достаточно долгий путь разработки пусть и простого, но полноценного интерактивного веб-приложения. И при этом мы не написали ни одной строчки кода на языке JavaScript. Если это не чудо, то я не знаю, как это назвать по-другому. И если вы читаете эти строки, то вы оказались «крепкими орешками». Благодарю вас за это.

Как известно, образование — то, что остается после того, как забыто все, чему учили в школе. Давайте напоследок соберём воедино всё, что, я надеюсь, останется в вашей памяти после прочтения этой статьи. Итак, чтобы превратить статическую HTML-страницу в полноценное приложение Mavo, необходимо выполнить нескольких несложных шагов:

  1. Подключить (в элементе <head>) к странице JavaScript- и CSS-файлы Mavo.
  2. Добавить атрибут mv-app к корневому элементу приложения.
  3. Указать, какие элементы страницы являются важными (будут редактироваться и/или сохраняться, и/или использоваться в выражениях) для приложения, снабдив их атрибутом property.
  4. Добавить атрибут mv-multiple к свойствам, которые должны быть преобразованы в коллекции.
  5. Указать Mavo, где сохранять данные приложения, добавив атрибут mv-storage к корневому элементу приложения.
  6. Определиться, нужно ли сохранять вносимые в данные изменения автоматически. Если да, то добавить атрибут mv-autosave к корневому элементу приложения.

    Дополнительно следует знать и учитывать, что:

  7. Панель Mavo полностью настраиваемая (как и все генерируемые Mavo элементы интерфейса). С помощью атрибута mv-bar, добавленного к корневому элементу приложения, можно определить, какие системные кнопки доступны на ней.
  8. Выражения (expressions) позволяют отображать (и использовать) текущее значение свойства (property) в разных частях приложения и выполнять вычисления с ним. Значение выражения (и его тип) зависит от места, которое это выражение занимает в коде приложения. У Mavo есть свой язык выражений, называемый MavoScript.
  9. Настраиваемые действия (custom actions) позволяют модифицировать данные приложения особым образом. Для определения настраиваемых действий в приложении используется атрибут mv-action.
  10. В приложениях могут использоваться так называемые вычисляемые свойства (computed properties) — это свойства, значениями которых являются выражения. Для хранения таких свойств, а также результатов промежуточных вычислений рекомендуется использовать элемент <meta>.

Вместо эпилога

Вот мы и разработали наше приложение. Идеальное ли оно? Конечно, нет. В этом мире нет ничего идеального. Всегда есть, что можно улучшить, и всегда найдётся функционал, который можно было бы включить в приложение (например, можно сделать приложение многоязычным). Как говорится, нет предела совершенству. Дерзайте! Улучшайте приложение на ваше усмотрение. Не бойтесь экспериментировать и пробовать что-то новое — это прекрасный способ учиться и закреплять приобретённые знания! Откуда знаю? Просто уже больше 17 лет учить людей — моя профессия (работаю в учебном центре «Сетевая Академия ЛАНИТ»)!

Всё, что мы узнали про Mavo, — всего лишь верхушка айсберга, и он способен на гораздо большее. Изучите документацию и примеры реализованных с помощью Mavo проектов и убедитесь в этом лично. Вот несколько источников для самостоятельной работы: официальный сайт Mavo и коллекции демо-приложений, выполненных Лией Веру и вашим покорным слугой.

Mavo ещё очень молод. И если вам понравился заложенный в него подход к разработке веб-приложений, вы можете стать полноценными участниками нашего сообщества. Как? Есть несколько вариантов:

  • вы можете присоединиться к команде разработчиков ядра Mavo, чтобы добавлять в него новый функционал, — загляните в репозиторий Mavo и вы найдёте там массу интересного;
  • или вы можете стать автором крутого и очень полезного плагина, за который вам обязательно скажут спасибо, и уверен, не один раз;
  • готовы доработать документацию Mavo, написать самоучитель, разработать примеры, на которых будут учиться новички и не только, — будем только рады;
  • ну, или просто заглядывайте в наш чат или на страничку Mavo в Twitter, чтобы обсудить с нами, что получается, а что нет, или просто сказать «Привет» (кстати, в Gitter есть комната и для русскоговорящих поклонников Mavo);
  • а вообще, просто рассказывайте о Mavo как можно большему количеству людей — он этого достоин!

Да пребудет с вами Mavo!

Благодарности

В этой части статьи я бы хотел упомянуть двух потрясающих людей и выразить им свою признательность.

В первую очередь, я очень благодарен Лие Веру (Lea Verou), которая не только сподвигла меня к написанию оригинала этой статьи на английском языке (и помогла мне воплотить её в жизнь), но и постоянно вдохновляет меня своим примером: тем, как она делает мир веб-разработки лучше для всех. Я никогда не встречал столь одарённого человека и безумно рад, что мне выпала счастливая возможность поработать с ней!

Я также благодарю Джеймса Мура (James Moore). Примеры, которые он использует в своем курсе «Функциональное программирование в JavaScript для начинающих» на платформе Udemy, а также выбранный им подход к обучению, мотивировали меня к созданию первой версии приложения «Карточки». Он замечательный учитель!

1260_6

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

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

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

Для создания интерактивных уроков можно использовать разное программное обеспечение: от создания интерактивностей в  программе MS PowerPoint до специального программного обеспечения.

Создание интерактивных упражнений в PowerPoint

Работать в среде PowerPoint удобно и полезно в связи с тем, что эта программа всегда под рукой. Не требуется интернет-соединения. Как правило, у вас уже имеется определённый опыт работы с этой программе презентаций. Если вы знаете для чего нужны таких два инструмента, как  гиперссылки и триггеры, то вам уже по силам создавать дидактические упражнения и даже игры для их использования на интерактивной доске.

Моё первое интерактивное упражнение, созданное в программе PowerPoint для работы на интерактивной доске «Собери яблоки», было подготовлено более 10-ти лет назад.

Посмотреть на весь экран.

На интерактивной доске могут работать сразу два ученика, «собирать яблоки». Это был своеобразный тренажёр для устного счёта. Вы можете создавать такие тренажёры и дидактические игры сами.

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

Для того, чтобы найти ресурсы на эту тему, необходимо воспользоваться рубрикой Работаем в PowerPoint. Здесь вы найдёте рекомендации по созданию, готовые интерактивные игры и упражнения, а также шаблоны, в том числе и с инструментами по перетаскиванию объектов.

Специализированное программное обеспечение

Если у вас нет на доске ничего, кроме драйверов, то, конечно, необходимо воспользоваться специальными программами. Большое распространение получили следующие программы для подготовки учебных материалов: WizTeachQwizdom OktopusRM EasiTeach Next Generation. Однако наиболее универсальной является SMART Notebook, с помощью которой можно готовить как уроки с на интерактивной доске в школе, так и для дистанционного обучения, где планшеты и  смартфоны учащихся превращаются в интерактивные поверхности. Впрочем, серьёзным минусом всех этих программ является их дороговизна. Бесплатные версии серьёзно ограничены.

Коллекции интерактивных образовательных ресурсов

Сразу хочу предупредить, что такие специализированные коллекции флипчартов (интерактивных материалов), как правило, имеются для конкретных интерактивных досок. Это, безусловно, значительно сужает их распространение. Нам нужны универсальные интерактивные задания образовательные ресурсы, которые можно было бы использовать на любой интерактивной доске. Как правило, такие ресурсы выполнены во flash или html5. Специализированных коллекций нет. Но вы можете воспользоваться общеизвестными: Единой коллекцией цифровых образовательных ресурсов или коллекцией Федерального центра информационно-образовательных ресурсов. А далее запустите встроенный внутренний поиск и наберите «интерактивные задания» или «интерактивные упражнения».

Не стоит забывать имеющиеся у вас мультимедийные предметные пособия на дисках. Многие из них имеют задания, которые легко можно воспроизвести на интерактивных досках. Вовсе не обязательно запускать каждый раз приобретённый вами диск.  Если доступ к его содержимому не заблокирован, то откройте папки и подберите необходимые вам интерактивные упражнения. Некоторые IT-компании подготовили программно-методические пособия, ориентированные для их использования на интерактивной доске. Это интерактивные плакаты компаний Новый Диск, Экзамен-медиа, некоторые другие.

Среди коллекций образовательных ресурсов особое место занимают  интерактивные тренажёры, симуляторы по предметам естественно-научного цикла Phet  Interactive Simulatoins. Большим преимуществом этой коллекции, помимо её добротной содержательности, является своевременный переход на html5 и, что особенно важно,  возможность загрузить созданный ресурс на компьютер и использовать его на интерактивной доске даже без доступа в Интернет.

Онлайн интерактивные доски

Обычно под онлайн досками принято подразумевать сервисы для совместной удалённой работы учителя и учащихся. Между тем, имеется другое направление: онлайн инструменты для интерактивных досок. Это, прежде всего, интерактивная онлайн доска Gynzy, которая не только содержит интерактивные образовательные ресурсы по всем учебным дисциплинам, но и обладает инструментами интерактивной доски, обычно недоступными без установки программного обеспечения. С помощью данного онлайн сервиса можно делать всё то, чем располагают интерактивные доски: рисовать, работать с текстом, в том числе и на разлинованной доске, загружать видео, звуковые файлы и изображения с компьютера или из сети Интернет.

Если у вас в классе уверенное Интернет-соединение, то воспользуйтесь оригинальной онлайн доской Classroomscreen, главное предназначение которой не совместная работа учащихся, а более организованная учебная деятельность с помощью ряда служебных инструментов.

Конструкторы интерактивных упражнений

Таких конструкторов довольно много. Но главное, что мы должны для себя решить: возможно ли использование созданных нами интерактивных упражнений в классе? Обладаем ли мы уверенным Интернет-соединением? И ещё одно: внимательно посмотрите опции таких  конструкторов. Хорошо, если в ряду инструментов они обладают также опциями drag-and-drop (перетаскивания объектов), инструментами рисования.

LearningApps — платформа, с помощью которой можно создать 20 видов интерактивностей, в основном вполне подходящих для интерактивной доски. Однако при всей доступности и полной бесплатности дизайн конструкторов явно устарел. Многие созданные упражнения плохо видны на интерактивной доске.

Classflow — уникальный многофункциональный сервис, который интегрирует в себе функции интерактивной доски, конструктора интерактивных уроков, тестов, опросов и дидактических игр. Имеет русскоязычную версию.

Study Stack — один из лучших конструкторов интерактивных упражнений. Он позволяет учителям и ученикам создавать флэш-карточки, кроссворды, тесты, поиск слов и другие игровые упражнения в  любой предметной области.

Raptivity — коллекция интерактивных конструкторов. Учитывая простоту в работе в конструкторами, преподаватели могут полностью сосредоточиться не на функционале и инструментах, а на содержании, чтобы в итоге получить добротный, методически выверенный продукт. Обычно я пишу в основном о бесплатных сервисах. Однако с  Raptivity случай особый. В течение 14 дней вы можете воспользоваться конструктором  бесплатно и использовать созданные упражнения не только онлайн, но и загрузить на свой компьютер, чтобы работать в дальнейшем автономно, без доступа в Интернет.

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

Purpose Games — бесплатный сервис, который во многом напоминает знакомый учителю LearningApps. И в то же время игры имеют некоторые свои особенности. Они, безусловно, могут украсить вашу методическую копилку.

С  Educandy вы можете создавать интерактивные обучающие игры в считанные минуты. Все, что вам нужно, это ввести некоторое количество слов, объединённых одной темой или создать небольшой тест по представленным шаблонам. А дальше Educandy превращает ваш контент в отличные интерактивные упражнения.

Wordwall представляет собой многофункциональный инструмент для создания как интерактивных, так и печатных материалов. Большинство шаблонов доступны как в интерактивной, так и в печатной версии. Многих учителей порадует тот факт, что сервис имеет русскоязычную версию. В вашем браузере она появится автоматически.  Интерактивные упражнения воспроизводятся на любом устройстве, имеющем доступ в интернет: на компьютере, планшете, телефоне или интерактивной доске. Однако бесплатная версия ограничена количеством созданных упражнений.

еТреники — отечественный онлайн-конструктор  учебных тренажёров. С его помощью вы можете создать 5 видов увлекательных интерактивных заданий.

Ума Игра — замечательный конструктор дидактических игр, создаваемых на основе  восьми прототипов. Игры хорошо смотрятся на интерактивной доске. Однако сервис временно недоступен в связи с реорганизацией портала и переходом на новую технологию html5. Все Ваши игры, опубликованные к этому моменту остаются доступными и Вы можете продолжать использовать их в своей работе. Редактирование существующих игр и визуализация неопубликованных материалов в этот период будет невозможна. Всем новым пользователям придётся потерпеть до 1 марта 2021 года, когда планируется запуск обновлённой платформы.

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

Мерсибо — замечательная онлайн платформа с готовыми дидактическими играми, рассчитанными на развитие речи, памяти, внимания, кругозора, обучение чтению и счету, подготовку к школе, успешную учебу в начальных классах, увеличение разнообразия видов учебной деятельности. Если вы воспользуетесь Студией Мерсибо, то сможете сами создавать интерактивные упражнения и игры. Сервис имеет как бесплатные игры, так и платные. Возможности Студии Мерсибо в бесплатной версии весьма ограничены.

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

Сегодня я занят восполнением огромной ямы, оставленной кодировкой по умолчанию, которую я не изменял раньше, и мне нужно научиться загружать на GitHub с помощью Git. Я не планировал обновлять ее, но я хотел придерживаться принципа хотя бы одной статьи в день. HTML-руководство по тегам еще не написано, чтобы вас не обманули, давайте напишем интерактивное руководство по Java.
Прежде всего, вам нужно знать концепцию, что такое взаимодействие, взаимодействие, то есть коммуникационное взаимодействие, интерактивная программа означает, что вы можете общаться с компьютером, конечно, это не то, что вы говорите, Компьютер может понимать, а затем думать и реагировать как человек, но вы можете давать конкретные инструкции, а компьютер может давать конкретные ответы. Новичкам нелегко достичь упомянутого выше состояния, и необходима огромная база данных. Но сначала мы можем развиваться в этом направлении, а именно в искусственном интеллекте.


Разберитесь в значении взаимодействия, тогда приступим
В предыдущем руководстве мы просто написали вывод Hello World! Простейшая небольшая программа с оператором, на этот раз мы могли бы также создать человека, который может поздороваться с введенным именем! Интерактивная программа. Как интерактивная программа, вывода недостаточно, поэтому нам также нужен ввод.
Как его ввести? Вы знаете, изучая, мы все понимаем, что стандартный вывод Java:

System.out

Значит, out is out, разве его антоним in that is in? Таким образом, стандартный оператор ввода Java:

System.in

К сожалению, это предложение не очень приемлемо для китайцев.

Итак, нам нужно ввести внешний класс:ScannerЧтобы решить эту проблему.
Давай, создай новый класс. Этому методу учили в прошлый раз. Я не вижу его таким. Я не буду смотреть на него снова. СинийСсылка на портал, Обратите внимание, что на этот раз вам нужно проверить основной метод создания, но у меня нет проблем, если вы захотите воспроизвести его снова.
Как его импортировать, сначала вы должны ввести на экране:

Scanner sc;

В это время вы обнаружите, что эммм … Почему вы сообщили об ошибке? Не паникуйте. Вы видели эту лампочку? Ткните это! как это:

Дважды щелкните содержимое длинного поля, и оно будет выглядеть следующим образом:

Обнаружили ли вы лишнюю строку выше? Правильно, поздравляем, вы успешно ввели класс Scanner.


Следующий шаг — обработать его, чтобы облегчить ввод. Как использовать Сканер для ввода? Запомните предложение со Сканером, введенное выше. В настоящее время это все еще бесполезное предложение. Давайте внесем несколько изменений после него и сделаем это так:

Scanner sc = new Scanner(System.in);

Таким образом, это предложение становится вводом значения с клавиатуры.Другими словами, кому это значение передается, вы должны определить другую вещь, которая принимает это значение.
Это еще одно понятие, переменные.
Что такое переменная? Как следует из названия, сумму можно изменить. В Java поддерживаются следующие типы переменных:

  • Переменные класса: переменные, не зависящие от методов, измененные с помощью static.
  • Переменные экземпляра: переменные, не зависящие от методов, но без статической модификации.
  • Локальные переменные: переменные в методах класса.

Нам нужно получить только последний тип локальной переменной, используемый в классе, и каково имя? Это определенно не будет одно или несколько чисел (при нормальных обстоятельствах). Очевидно, это будет не просто символ. Тогда это может быть только строка. Как Java представляет строку? В Java строка представлена ​​какString, Давайте определим переменную так, чтобы она принимала вводимое нами имя, давайте назовем ее именем, так как же нам разрешить ввод с клавиатуры имени переменной? Здесь используется класс Scanner, указанный выше. С помощью этого оператора входное значение (значение слова может относиться к числу или тексту) может быть плавно передано имени:

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

Затем я начал рассматривать эту проблему вывода. Сначала напишите оператор вывода, который выводит Hello, а затем возникает вопрос, как добавить имя? Все мы знаем, что содержимое в двойных кавычках выходного предложения все еще печатается, а? А как насчет цитат за пределами? Почему бы нам не попробовать название прямо снаружи? Попытайся!
Эээ (o⊙) … Если вы сообщите об ошибке, верно? Это не сработает. Эй, в Java правильный способ вывода оператора может быть таким:

System.out.println("текст"+переменная+"текст"+переменная+"текст"+переменная+...);

Итак, вы знаете, как его использовать? Если вы не знаете, я не могу этого сделать. Посмотрите на картинку:

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

Хм, развеселее? Развивайте больше контента самостоятельно! Как можно немного научиться не волновать?
Это конец этого руководства. Завтра давайте разберемся с типами переменных. Я чувствую, что многие знания были упущены. Не торопитесь. Если это руководство будет вам полезно, Щелкните значок «Нравится» и затем перейдите. Если у вас есть предложения или недостатки, укажите их.
Руководство Xiaobai, укажите источник для перепечатки.

Понравилась статья? Поделить с друзьями:
  • Код ошибки 0100600003 в налоговой как исправить
  • Как найти квартиру без риэлтора в казани
  • Как составить формулу соли nano
  • Как найти очки в лесу
  • Как легче найти нужный сайт