- PVSM.RU - https://www.pvsm.ru -
В последнее время все чаще требуется максимально быстрая разработка прототипов веб-приложений. Интерфейсы усложняются, требуется отображение огромного количества данных. И вот я озадачился созданием легкого и максимально простого html-шаблонизатора. Кому интересно, что получилось на ~50 строках JS-кода — под кат.
Сделать односторонний (JS → HTML) шаблонизатор, связывающий JS данные с html отображением максимально просто. Решение должно быть быстрым, с минимальным порогом вхождения — тяп ляп и готово. Максимальная допиливаемость под конкретные требования — примитивность залог успеха.
Будем писать обычный html код, где для связи с js будут использоваться обычные data-атрибуты:
data-template — содержимое, которое будет отображаться внутри тега
data-namespace — данные, которые привязываются к JS
Данные должны записываться и обновляться прозрачно. Т.е. если у нас есть объект object со свойством data, то данный должны обновляться в html сразу после обычного:
object.data = 5;
Без всяких вспомогательных методов типа:
object.setData = function(val){
this.data = val;
document.getElementById("tpl").html = val;
}
object.setData(5);
— это норм подход, но что будете делать, если с сервера приходит большая пачка json данных, которые надо распихать по разным объектам и отобразить изменения в интерфейсе? Писать и вызывать свой сеттер для каждого свойства/набора свойств — мне такая реализация надоела.
Решение простое. Для каждого свойства объекта мы можем задать дефолтные сеттеры/геттеры, срабатывающие как раз при изменении изменении значения обычным присваиванием. Называется это Object.defineProperty(...) [1] — пересказывать статью не буду, перейду сразу к идее.
Нам надо пробежаться по всем свойствам объекта, которые имеют связь с html. Способов это сделать два:
1) Пробежаться по dom, вытащив оттуда все возможные (не повторяющиеся) значения атрибута data-namespace в отдельный массив
2) Для каждого объекта в js вручную будем задавать массив, который говорит, какие данные (только какие а не с чем) будут использоваться в связях.
Так как код претендует на наглядность реализации и примитивность — выбираем второй вариант.
Чтобы не ходить вокруг да около, сразу приведу пример с пояснениями.
html
<div data-template="dataA" data-namespace="test">тут должно быть значение dataA из объекта со значением свойства this_namespace=test</div>
<div data-template="dataB" data-namespace="test">тут должно быть значение dataB из объекта со значением свойства this_namespace=test</div>
<div data-template="dataA" data-namespace="test2">тут должно быть значение dataA из объекта со значением свойства this_namespace="test2"</div>
js
var obj1 = {
this_namespace: 'test', // имя которое будет использоваться для идентификации объекта
this_data: ['dataA', 'dataB'] // имена которое будет использоваться для идентификации свойств объекта
};
var obj2 = {
this_namespace: 'test2', // имя которое будет использоваться для идентификации объекта
this_data: ['dataA'] // имена которое будет использоваться для идентификации свойств объекта
}
Как видим, изначально в объекте нет никаких данных, мы их получим позже — для начала объект надо подготовить к такому.
Вся магия заключается в том, чтобы внутри объекта пробежаться по массиву this_data и насоздавать в этом же объекте по 2 свойства на каждый элемент массива:
1) __dataA, __dataB… — тут будут храниться значения
2) dataA, dataB… — и тут будут храниться значения =)
Смысл такой манипуляции в том, что если мы зададим например дефолтный сеттер просто для свойства dataA, который будет записывать переданное значение сюда же — получится рекурсивненько. Чтобы этого избежать, создается отдельное свойство с префиксом "__" (можно любой, например fake_ или magic_ — просто я выбрал такой чтобы не засорять namespace объекта).
Получается, что когда мы напишем obj.dataA = 3, это значение запишется в свойство obj.__dataA, а дефолтный геттер при запросе obj.dataA будет отдавать значение obj.__dataA. То есть по факту, в массиве obj вообще нету свойств dataA и dataB в чистом виде — сеттеры и геттеры подменяют их на свойство с префиксом.
Как я и говорил, нужно обеспечить максимально низкий порог вхождения — чтобы начинающим было проще. А кому надо могут переписать как хотят. В связи с этим, весь метод придания объекту нужного вида будет реализован через прототип объекта.
Тут код неудобно читать, так что сразу смотрим сюда (jsfiddle) [2] — там весь код с комментариями и запуск.
Спрашивайте, критикуйте, будьте здоровы!
Автор: axeax
Источник [4]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/231824
Ссылки в тексте:
[1] Object.defineProperty(...): https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
[2] сюда (jsfiddle): https://jsfiddle.net/axeax/ky9zbc18/
[3] Object.assign: https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
[4] Источник: https://habrahabr.ru/post/319014/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best
Нажмите здесь для печати.