Всем привет.
Пишу эту статью по той причине, что сам не нашел достаточно материала на эти темы.
Примерно месяц назад я решил написать свою первую библиотеку. Вот требования к ней:
Когда работа была завершена, я решил добавить к библиотеке простой роутер, который будет реализован через «window.location.hash». И вот требования к нему:
Да, да, я знаю, что это «велосипед», что такая библиотека сейчас совсем не нужна, а реализация роутера через «window.location.hash» уже устарела, но это все было написано не для продакшена!
Главной целью всего этого было получение опыта, так как я только новичок и очень многое еще просто не понимаю. Пока я писал эти два маленьких проекта, я научился работать с циклами, узнал про свойства функций, я узнал и понял довольно много нового, стал смотреть на язык иначе.
Основана она будет на свойствах функций в JavaScript. Но также прошу заметить, что ее можно было реализовать и через классы в спецификации «ES6». Напишем вот такую заготовку:
Теперь можем добавить первый полноценный метод, который по сути является укороченным «addEventListener». В примере я опишу лишь два метода, чтобы было ясно, как они в общем устроены, и как самостоятельно их создать.
Можем по такому же принципу добавить в нашу библиотеку еще один метод — «render».
Теперь напишем функцию, через которую будем получать сами элементы.
Все вместе должно выглядеть примерно так:
Пожалуй, мы закончили с прототипом нашей маленькой библиотеки. Опробуем ее!
Вроде все работает.
Создадим объект-константу с именем «router», содержащую один метод-функцию — «getURL()».
Еще добавим пустой массив-переменную с именем «routes».
Теперь опишем функцию «renderRoute()», а в ней вспомогательную функцию — «isUndefined()», которая будет проверять наш роут на равенство с «undefined».
Далее реализуем функцию, которая будет отслеживать изменения «window.location.hash» и рендерить соответствующий контент.
Ну все, с роутером мы тоже закончили, осталось его протестировать. Вот базовый способ его запуска:
Действительной для этого роутера будет ссылка с атрибутом «href» такого вида — «href='#page'».
Ну вот и все, мы закончили, у нас получилось, мы молодцы!
Теперь с этими инструментами можно реализовать простенькое (а может и не простенькое) прогрессивное одностраничное приложение — PSPWA (ага, сам придумал, совместил SPA и PWA).
По правде говоря, я целый месяц мучился с двумя этими темами, пересмотрел кучу видео, прочел большое множество статей, но ничего из этого мне не помогло. Я бы хотел тогда наткнуться на статью, которую писал сейчас, она бы мне очень помогла.
Вот и закончилась моя первая статья. Дорогой Читатель, хочу сказать тебе спасибо за внимание! Я очень старался и надеюсь, что тебе поможет это небольшое!
Если нашли ошибку, пишите в комментарии, буду очень благодарен. Если будут какие-то вопросы — постараюсь ответить. Всем спасибо и пока!
SPA
PWA
Про «use strict»
Учебник — переменные
Учебник — функции
Учебник — циклы
Учебник — массивы
Учебник — объекты
Статься об ООП в JS от другого пользователя habr'а
Учебное видео по роутингу во фреймворке от WebForMySelf
Пишу эту статью по той причине, что сам не нашел достаточно материала на эти темы.
Примерно месяц назад я решил написать свою первую библиотеку. Вот требования к ней:
- Выбор элементов как JQuery — по селектору, через функцию вида "$(selector)".
- Вызов функций для выбранного элемента через методы библиотеки.
- Очень маленький вес (хоть и по причине малого функционала).
Когда работа была завершена, я решил добавить к библиотеке простой роутер, который будет реализован через «window.location.hash». И вот требования к нему:
- Рендер контента без перезагрузки страницы.
- Автоматизированная работа роутера, а именно рендер контента, соответствующего какому-либо роуту, без добавления дополнительных условий такого типа —
"if (window.location.hash == 'home') document.body.innerHTML = homePageContent"
. - Наличие страницы «404».
Да, да, я знаю, что это «велосипед», что такая библиотека сейчас совсем не нужна, а реализация роутера через «window.location.hash» уже устарела, но это все было написано не для продакшена!
Главной целью всего этого было получение опыта, так как я только новичок и очень многое еще просто не понимаю. Пока я писал эти два маленьких проекта, я научился работать с циклами, узнал про свойства функций, я узнал и понял довольно много нового, стал смотреть на язык иначе.
Ну, хватит тянуть, переходим к реализации
Начнем c библиотеки
Основана она будет на свойствах функций в JavaScript. Но также прошу заметить, что ее можно было реализовать и через классы в спецификации «ES6». Напишем вот такую заготовку:
"use strict";
function Library(element) {
// Вот первое свойство нашей функции, через параметр мы получаем выбранный элемент
this.element = element;
}
Теперь можем добавить первый полноценный метод, который по сути является укороченным «addEventListener». В примере я опишу лишь два метода, чтобы было ясно, как они в общем устроены, и как самостоятельно их создать.
// Создаем метод "on"
this.on = function(name, f) {
// Перебираем все элементы, которые позже получим через дополнительную функцию
for (var i = 0; i < this.element.length; i++) {
// В теле цикла находится сама функция, которую вызывает метод
// Используем параметры
this.element[i].addEventListener(name, f);
}
// Возвращаем главную функцию
return this;
}
Можем по такому же принципу добавить в нашу библиотеку еще один метод — «render».
// Опять создаем метод
this.render = function(content) {
// Снова перебираем элементы
for (var i = 0; i < element.length; i++) {
// В теле цикла снова находится наша функция
this.element[i].innerHTML = content;
}
// Не забываем про эту строчку!
return this;
}
Теперь напишем функцию, через которую будем получать сами элементы.
function $(selector) {
// Переменная "elements" будет содержать один или больше полученных элементов
var elements = document.querySelectorAll(selector);
// Возвращаем главную функцию с полученными элементами
return new Library(elements);
}
Все вместе должно выглядеть примерно так:
"use strict";
function Library(element) {
this.element = element;
this.on = function(name, f) {
for (var i = 0; i < element.length; i++) {
this.element[i].addEventListener(name, f);
}
return this;
}
this.render = function(content) {
for (var i = 0; i < element.length; i++) {
this.element[i].innerHTML = content;
}
return this;
}
}
function $(selector) {
var elements = document.querySelectorAll(selector);
return new Library(elements);
}
Пожалуй, мы закончили с прототипом нашей маленькой библиотеки. Опробуем ее!
// Пробуем рендер
$("body").render(`<div id="title">
Hello, this words was printed by a render function!</div>
<button id="btn">Alert</button>`);
// И листенер тоже
$("#btn").on("click", function() { alert("Button was clicked") });
// Да, мой английский - так себе...
// Ну а на странице должна появиться эта надпись
// А при нажатии всплыть уведомление
Вроде все работает.
Займемся роутером
Создадим объект-константу с именем «router», содержащую один метод-функцию — «getURL()».
Еще добавим пустой массив-переменную с именем «routes».
// Создаем объект
const router = {
// Теперь его метод
getURL() {
// Возвращаем наше текущее местоположение по "hash"
return window.location.hash.slice(1);
// Пропускаем первый символ, так как он всегда будет "#"
}
}
var routes = [];
Теперь опишем функцию «renderRoute()», а в ней вспомогательную функцию — «isUndefined()», которая будет проверять наш роут на равенство с «undefined».
// Вспомогательная функция
function renderRoute() {
function isUndefined(z) {
return typeof z === "undefined"; // Только строгое сравнение
// Если undefined, то функция вернет "true"
}
let url = router.getURL(); // По сути let url = window.location.hash.slice(1)
let route = routes.find(r => r.path === url);
// Перебираем массив "routes" и ищем роут с "path", равным переменной "url"
if (isUndefined(route)) {
// И снова перебор
route = routes.find(r => r.path === "***");
// Если роута с таким "path" нет, то адрес сменится на "***", это страница 404
}
// Создаем переменную "routerView" с нужным нам для рендера элементом
var routerView = document.querySelector("#router-view");
// Проверяем наличие нужного нам элемента в файле html
if (!view) {
console.log("Не удалось найти view-элемент!") // Если элемента нет
} else {
routerView.innerHTML = route.content; // Если элемент есть
}
}
Далее реализуем функцию, которая будет отслеживать изменения «window.location.hash» и рендерить соответствующий контент.
function initRoutes() {
// "Вешаем прослушку" на "window"
window.addEventListener("hashchange", renderRoute);
// Да, все правильно, без скобок, я сам долго мучился с этой ошибкой
renderRoute();
// Вызвали рендер для того, чтобы контент грузился сразу после загрузки страницы
}
Ну все, с роутером мы тоже закончили, осталось его протестировать. Вот базовый способ его запуска:
// Создаем наши страницы
var firstPage = `This is a first page`;
var secondPage = `This is a first page`;
var page404 = `This page not found, <a href='#'>First page</a>`;
// Заполняем массив "routes" объектами, содержащими "path" и "content"
var routes = [
{ path: "", content: firstPage }, // Пустой путь означает, что страница главная
{ path: "second_page", content: secondPage }, // Путь указываем без "#"
{ path: "page_404", component: page404 }
];
// Запускаем наш роутер
initRoutes();
Действительной для этого роутера будет ссылка с атрибутом «href» такого вида — «href='#page'».
Ну вот и все, мы закончили, у нас получилось, мы молодцы!
Итог
Теперь с этими инструментами можно реализовать простенькое (а может и не простенькое) прогрессивное одностраничное приложение — PSPWA (ага, сам придумал, совместил SPA и PWA).
По правде говоря, я целый месяц мучился с двумя этими темами, пересмотрел кучу видео, прочел большое множество статей, но ничего из этого мне не помогло. Я бы хотел тогда наткнуться на статью, которую писал сейчас, она бы мне очень помогла.
Вот и закончилась моя первая статья. Дорогой Читатель, хочу сказать тебе спасибо за внимание! Я очень старался и надеюсь, что тебе поможет это небольшое!
Если нашли ошибку, пишите в комментарии, буду очень благодарен. Если будут какие-то вопросы — постараюсь ответить. Всем спасибо и пока!
Источники
SPA
PWA
Про «use strict»
Учебник — переменные
Учебник — функции
Учебник — циклы
Учебник — массивы
Учебник — объекты
Статься об ООП в JS от другого пользователя habr'а
Учебное видео по роутингу во фреймворке от WebForMySelf