Как выполняется шаблонизация в html файле
Перейти к содержимому

Как выполняется шаблонизация в html файле

Основы шаблонов

Шаблон — это текстовый файл, определяющий структуру, или внешний вид выходного файла, с предусмотренными позициями, в которые будут помещаться данные при отображении по шаблону (в Express шаблоны также называют представлениями).

Выбор шаблонов Express

В Express можно использовать много движков отображающих шаблонов ( template rendering engines). В этом руководстве для шаблонов будет использован Pug (ранее известный как Jade) . Это наиболее популярный в Node язык шаблонов, который о себе заявляет так: чистый, чувствительный к пробелам синтаксис для написания HTML, на который сильно повлиял Haml.

Разные языки шаблонов используют различные подходы для определения внешнего вида и разметки позиций для данных—некоторые используют HTML для определения внешнего вида, тогда как другие применяют различные форматы разметки, которые затем должны компилироваться в HTML. Pug — второго типа; он использует представление (representation) HTML, в котором первое слово в каждой строке обычно представляет элемент HTML, а отступы в следующих строках применяются, чтобы представить вложенные элементы. Результатом является определение страницы, которое транслируется непосредственно в HTML, и которое, вероятно, более краткое и легче читается.

Примечание: недостаток применения Pug — это чувствительность к отступам и пробелам (если добавить лишний пробел в «плохом» месте, можно получить невразумительный код ошибки). Однако, если ваши шаблоны уже действуют, их очень легко читать и поддерживать.

Конфигурация шаблона

Когда создавался каркас (the skeleton website) веб-сайта LocalLibrary, он был настроен на использование Pug . Можно было заметить, что модуль pug включён в зависимости в файле package.json, и установлен (app.set(. )) как движок представлений в файле app.js. Эта установка показывает,, что движок представлений — pug, и что Express должен искать шаблоны в подкаталоге /views.

// View engine setup. app.set("views", path.join(__dirname, "views")); app.set("view engine", "pug"); 

Если посмотреть содержимое каталога views, можно увидеть файлы с расширением .pug, в которых шаблоны представлений по умолчанию. Это представление для домашней страницы (index.pug) и базовый шаблон (layout.pug), который следует заменить нашим содержимым.

/express-locallibrary-tutorial //the project root /views error.pug index.pug layout.pug

Синтаксис шаблонов

Пример файла шаблона (ниже) демонстрирует многие наиболее полезные черты Pug.

Сначала отметим, что файл отражает структуру типового HTML-файла, причём первое слов в (почти) каждой строке является элементом HTML, а отступы используются, чтобы показать вложенные элементы. Так, например, элемент body находится внутри элемента html , а элементы p (параграфы) — внутри элемента body, и так далее. Невложенные элементы (т.е. индивидуальные параграфы) располагаются в отдельных строках.

doctype html html(lang="en") head title= title script(type='text/javascript'). body h1= title p This is a line with #[em some emphasis] and #[strong strong text] markup. p This line has un-escaped data: ! is emphasised'> and escaped data: # is not emphasised'>. | This line follows on. p= 'Evaluated and escaped expression:' + title // You can add single line JavaScript comments and they are generated to HTML comments //- Introducing a single line JavaScript comment with "//-" ensures the comment isn't rendered to HTML p A line with a link a(href='/catalog/authors') Some link text | and some extra text. #container.col if title p A variable named "title" exists. else p A variable named "title" does not exist. p. Pug is a terse and simple template language with a strong focus on performance and powerful features. h2 Generate a list ul each val in [1, 2, 3, 4, 5] li= val 

Атрибуты элементов определены в скобках после соответствующих элементов. В скобках располагается список пар *имя атрибута=значение,*причём элементы списка разделяются запятой или пробелом. Например:

  • script(type=’text/javascript’) , link(rel=’stylesheet’, href=’/stylesheets/style.css’)
  • meta(name=’viewport’ content=’width=device-width initial-scale=1′)

Значения всех атрибутов экранируются (т.е. такие символы как » > » заменяются эквивалентными кодами HTML как » >» ) , чтобы предотвратить JavaScript инъекции и межсайтовые атаки.

Если после тэга стоит знак = , следующий текст рассматривается как выражение JavaScript. Например, ниже в первой строке, содержимое тэга h1 будет переменной title (которая определена в файле или передана в шаблон из Express). Во второй строке содержимое параграфа — это текстовая строка, соединённая с переменной title . В каждом из случаев поведение по умолчанию — экранировать строки.

h1= title p= 'Evaluated and escaped expression:' + title 

Если после тэга знак = отсутствует, тогда содержимое рассматривается как обычный текст. Внутри текста можно вставить экранированные или неэкранированные данные, применяя синтаксис #<> и !<> , как показано ниже. В простой текст можно также вставлять «сырой» HTML.

p This is a line with #[em some emphasis] and #[strong strong text] markup. p This line has an un-escaped string: ! is emphasised'>, an escaped string: # is not emphasised'>, and escaped variables: #. 

Примечание: Почти всегда желательно экранировать данные, полученные от пользователей (при помощи синтаксиса #<> ). Данные, которым можно верить (т.е. подсчитанное количество записей, могут быть выведены без экранирования значений.

Можно использовать символ конвейера (‘|‘) в начале строки, чтобы отметить простой текст («plain text»). Например, дополнительный текст, приведённый ниже, будет показан в той же строке, что и предыдущий, но не будет относиться к ссылке.

a(href='http://someurl/') Link text | Plain text 

Pug позволяет выполнять условные операции if , else , else if и unless — пример приведён ниже:

if title p Переменная с именем "title" существует else p Переменной с именем "title" не существует 

Можно также выполнять циклы (итерации), применяя синтаксис each-in или while . Фрагмент кода (ниже) содержит цикл по элементам массива, чтобы показать список элементов (отметим применение ‘li=’ для оценки «val» как переменной). Значение итератора val может быть также передано в шаблон как переменная!

ul each val in [1, 2, 3, 4, 5] li= val 

Синтаксис разрешает также комментарии (которые попадут в результат или нет, по вашему желанию), смеси для создания повторно используемых блоков кода, операторы выбора case, и много другого. Более подробная информация — в документации The Pug docs.

Расширение шаблонов

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

Например, базовый шаблон layout.pug, созданный в каркасе проекта, имеет такой вид:

doctype html html head title= title link(rel='stylesheet', href='/stylesheets/style.css') body block content 

Тэг block применён для отметки разделов контента, которые могут быть заменены в производных шаблона (если блок не переопределяется, будет использования его реализация в базовом классе).

Умолчание для index.pug (созданный для каркаса проекта) показывает, как можно заменить базовый шаблон. Тэг extends идентифицирует базовый шаблон, который следует использовать, а затем мы используем block section_name, чтобы отметить новый контент раздела, который мы заменяем.

extends layout block content h1= title p Welcome to # 

Next steps

  • Return to Express Tutorial Part 5: Displaying library data.
  • Proceed to the next subarticle of part 5: The LocalLibrary base template.

Found a content problem with this page?

  • Edit the page on GitHub.
  • Report the content issue.
  • View the source on GitHub.

This page was last modified on 3 авг. 2023 г. by MDN contributors.

Your blueprint for a better internet.

1. Введение

Шаблонизация (templating) — метод связывания данных и разметки. Удобный способ генерации HTML по шаблону и данным. Используется на клиенте и сервере.

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

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

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

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

Это — стандартный подход написания динамических элементов интерфейса, данные для которых изменяются со временем.

1.1. Использование шаблонизации

Весь процесс требует нескольких простых шагов:

  • Наличие данных, которыми будет наполнятся элемент интерфейса
  • Шаблон, по которому будет составлена разметка элемента
  • Библиотека, которая предоставляет средства шаблонизации

templating

Мы подробно рассмотрим это на примерах, но по сути это очень просто:

  • Подключить в проект выбранную библиотеку для шаблонизации
  • Составить HTML-шаблон необходимого вида
  • Сделать выборку шаблона в JS-файле
  • Произвести рендеринг шаблона вместе с данными

2. Шаблон

Шаблон — это строка в специальном формате, которая путём подстановки значений и выполнения встроенных фрагментов кода превращается в HTML.

Синтаксис шаблона зависит от библиотеки, самое важное — это понимать принцип работы шаблонизаторов. Мы будем использовать библиотеку Handlebars.

2.1. Синтаксис

Шаблон — это строка со специальными разделителями, которых в Handlebars всего три:

 div>>div> div><>div> div>>>div> 

То есть синтаксис Handlebars — это обычный HTML, с вставками вида > . Именно в те места, где указаны вставки, будут помещены данные.

div class="menu"> h3 class="menu-title">>h3> ul class="menu-list"> > li class="menu-item">>li> > ul> div> 

2.2. Методы хранения

Шаблон — это просто многострочный HTML-текст, ему не место в файле скриптов. Один из способов — записать его в HTML-файле в тег template .

Более современный способ, например при использовании Webpack , хранить шаблон в отдельном файле и импортировать его. Для этого в конфигурацию Webpack нужно добавить загрузчик Handlebars-шаблонов.

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

Давайте обернем шаблон в тег template и дадим ему уникальный идентификатор, чтобы можно было выбрать в JS-файле по селектору.

template id="menu-template"> div class="menu"> h3 class="menu-title">>h3> ul class="menu-list"> > li class="menu-item">>li> > ul> div> template> 

3. Использование шаблона

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

3.1. Добавить в проект библиотеку

Подключение библиотеки в проект происходит очень просто. Есть несколько вариантов.

  • Скачать файл библиотеки и подключить его в index.html
  • Использовать CDN-сервис для получения ссылки на файл библиотеки
  • Если используется инструмент вроде Webpack , можно ставить библиотеку как npm-пакет

Пока что используем CDN. В разделе документации о установке библиотеки есть ссылка на CDN-сервис на котором можно скопировать необходимый URL. Это — минифицированая версия библиотеки. Все что нужно сделать — это добавить еще один тег script перед нашим файлом скриптов и перед закрывающим тегом body в index.html .

script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.11/handlebars.min.js">script> 

3.2. Составить HTML шаблон

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

body> template id="menu-template"> div class="menu"> h3 class="menu-title">>h3> ul class="menu-list"> > li class="menu-item">>li> > ul> div> template> script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.11/handlebars.min.js">script> script src="js/scripts.js">script> body> 

3.3. Сделать выборку шаблона в скрипте

template — это тег, значит мы можем выбрать его по селектору тега/класса/идентификатора. Хорошей практикой считается давать тегам template , содержащим шаблон, идентификаторы, так как они уникальны.

Теперь в JS-файле мы можем по id выбрать сам тег template и его контент в виде строки, для этого используем свойство innerHTML .

const source = document.querySelector('#menu-template').innerHTML.trim(); 

3.4. Отрендерить шаблон с данными

У нас уже есть библиотека и шаблон из которого мы изъяли текстовый контент. Для работы с шаблоном в библиотеке Handlebars есть функция compile . Эта функция запускает компиляцию шаблона source и возвращает результат в виде функции, которую далее можно запустить с данными и получить строку-результат.

Handlebars.compile(source) 

Вызов Handlebars.compile(source) разбивает HTML-строку по разделителям и при помощи new Function создаёт на её основе функцию. Тело этой функции создаётся таким образом, что код, который в шаблоне оформлен как > , попадает в неё как есть, а переменные и текст прибавляются к специальному временному буферу, который в итоге возвращается.

const source = document.querySelector('#menu-template').innerHTML.trim(); const template = Handlebars.compile(source); 

template compilation

Теперь используя функцию-шаблон template можем передать ей данные как аргумент и она вернет HTML-строку.

Для начала добавим данные для списка. В шаблоне указаны какие-то переменные title и items .

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

Данные для шаблона — это что угодно, строка, объект, массив и т.д., зависит от задачи, чаще всего — объект или массив объектов. Так как у нас список с заголовком и набором пунктов, нам удобно использовать объект такого вида.

const menuData =  title: 'Eat it createElement, templates rule!', items: ['Handlebars', 'LoDash', 'Pug', 'EJS', 'lit-html'], >; 

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

4. Шаблоны и Webpack

Когда используем сборщик модулей, очень удобно работать со внешними шаблонами.

npm install handlebars 
npm install --save-dev handlebars-loader 

Обновляем конфигурацию Webpack, добавляя настройки загрузчика.

// В webpack.config.js  . module:  rules: [ .  test: /\.hbs$/, exclude: /node_modules/, use: "handlebars-loader" > ] > > 

В папке src создаем папку templates , в которой добавляем файлы шаблонов с расширением .hbs . Для нашего меню это будет menu.hbs . Помещаем разметку шаблона в файл, без тега template .

 div class="menu"> h3 class="menu-title">>h3> ul class="menu-list"> > li class="menu-item">>li> > ul> div> 

Там, где хотим использовать шаблон, импортируем файл с шаблоном. Особенность в том, что при импорте, handlebars-loader обработает файл шаблона и в menuTemplate уже будет лежать скомпилированная функция-шаблон готовая к использованию.

// В app.js import menuTemplate from '/path/to/templates/menu.hbs'; const menuData =  title: 'Eat it createElement, templates rule!', items: ['Handlebars', 'LoDash', 'Pug', 'EJS', 'lit-html'], >; const markup = menuTemplate(menuData); // html разметка с подставленным значениями 

5. Дополнительные материалы

  • Learn Handlebars in 10 Minutes or Less
  • A Beginner’s Guide to Handlebars
  • Правильная шаблонизация

Новый тег : введение стандарта шаблонизации на стороне клиента

Понятие шаблонизации в веб-разработке не является чем-то новым. Более того, серверные языки шаблонов и шаблонизаторы вроде Django (Python), ERB/Haml (Ruby), и Smarty (PHP) существуют уже далеко не первый день. Последние несколько лет можно наблюдать волну возникновения MVC-фреймворков. Они все немного отличаются друг от друга, но в большинстве своем в их основе лежит общий механизм воспроизведения слоя представления: шаблоны.

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

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

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

Спецификация для HTML-шаблонов от W3C должна заполнить этот пробел. В ней определён новый элемент , который является реализацией стандарта шаблонизации для DOM на стороне клиента. Шаблоны позволяют объявлять фрагменты разметки, которые парсятся как HTML, игнорируются при загрузке страницы, но могут быть инстанциированы позже. Цитата от Рафаеля Вайнштайна (Rafael Weinstein) (автора спецификации):

«Они обозначают место, куда можно поместить большой кусок HTML, который вы хотите оградить от какого-либо влияния со стороны браузера…какой бы ни была причина для этого»

Как определить поддерживается ли элемент?

Для выявления поддержки , создайте объект DOM и проверьте наличие свойства .content :

function supportsTemplate( ) < return 'content' in document.createElement('template'); > if (supportsTemplate()) < // Всё в норме. > else < // Используйте старые приёмы или библиотеки шаблонизации > 

Объявление содержимого шаблона

Элемент представляет шаблон. В него помещено «содержимое шаблона»; по сути инертные куски DOM, которые можно использовать многократно. Шаблоны можно рассматривать как фрагменты скаффолдинга, которые можно многократно использовать в приложении.

Чтобы создать шаблонный контент, напишите код разметки и оберните его в элемент :

template id="mytemplate"> img src="" alt="красивая картинка"> div class="comment"> div> template> 

Наблюдательный читатель должно быть заметил что изображение пустое. Это нас вполне устраивает и было сделано преднамеренно. Мы не получим ошибку 404 или ошибки в консоли потому, что ссылка на изображение битая, так как изображение не будет вызвано при загрузке страницы. Позже можно динамически сгенерировать URL-адрес изображения. Читайте основные принципы.

Основные принципы

Помещение содержимого в даёт нам несколько важных свойств:

  1. Содержимое фактически инертно, пока его не активировать. По сути, соответствующая разметка спрятана и не воспроизводится.
  2. Содержимое шаблона не может привести к каким-либо побочным эффектам. Скрипты не выполняются, изображения не загружаются, аудио не проигрывается… пока шаблон не активирован.
  3. Содержимое шаблона не считается частью страницы. Использование document.getElementById() или querySelector() на странице не возвратит дочерние элементы шаблона.
  4. Шаблоны можно помещать куда угодно: в , или ; и помещать в них любой тип содержимого, который может располагаться в этих частях страницы. Обратите внимание что «куда угодно» значит что можно без проблем использовать в местах, запрещённых парсером HTML… всех кроме дочерних элементов модели содержимого.
table> tr> template id="cells-to-repeat"> td>какое-то содержимое td> template> tr> table> 

Активация шаблона

Чтобы использовать шаблон, нужно его активировать. Иначе его содержимое не будет воспроизводиться. Наиболее простой способ — это создать глубокую копию его содержимого .content используя cloneNode() . .content — это неизменимое свойство, которое обозначает фрагмент документа с содержимым шаблона.

var t = document.querySelector('#mytemplate'); // Во время выполнения заполняем src. t.content.querySelector('img').src = 'logo.png'; document.body.appendChild(t.content.cloneNode(true)); 

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

Демо

Пример: инертный скрипт

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

button onclick="useIt()">Нажми на меня button> div id="container"> div> script> function useIt( ) < var content = document.querySelector('template').content; // Обновление чего-нибудь в DOM шаблона. var span = content.querySelector('span'); span.textContent = parseInt(span.textContent) + 1; document.querySelector('#container').appendChild( content.cloneNode(true)); > script> template> div>Количество раз, которое использован шаблон: span>0 span> div> script>alert('Спасибо!') script> template> 

Нажми на меня
Количество раз, которое использован шаблон: 0

Пример: Создание теневого дерева из шаблона

Большинство разработчиков прикрепляет теневое дерево к ведущему элементу изменяя строку разметки через .innerHTML :

div id="host"> div> script> var shadow = document.querySelector('#host').webkitCreateShadowRoot(); shadow.innerHTML = 'Ведущий элемент'; script> 

Проблема такого подхода состоит в том, что чем сложнее становится ваш теневой DOM, тем чаще вам приходится прибегать к конкатенации строк. Он не масштабируется, очень быстро получается путаница, все в печали. Благодаря именно таким подходам возник межсайтовый скриптинг! приходит на помощь.

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

template> style> @host < * < background: #f8f8f8; padding: 10px; -webkit-transition: all 400ms ease-in-out; box-sizing: border-box; border-radius: 5px; width: 450px; max-width: 100%; > *:hover < background: #ccc; > > div < position: relative; > header < padding: 5px; border-bottom: 1px solid #aaa; > h3 < margin: 0 !important; > textarea < font-family: inherit; width: 100%; height: 100px; box-sizing: border-box; border: 1px solid #aaa; > footer < position: absolute; bottom: 10px; right: 5px; > style> div> header> h3>Добавление комментария h3> header> content select="p"> content> textarea> textarea> footer> button>Опубликовать button> footer> div> template> div id="host"> p>Здесь должны быть инструкции p> div> script> var shadow = document.querySelector('#host').webkitCreateShadowRoot(); shadow.appendChild(document.querySelector('template').content); script> 

Инструкции для пользователя

Нюансы

Вот несколько нюансов, с которыми я столкнулся используя в полевых условиях:

  • Используя модуль modpagespeed, берегитесь этой ошибки. CSS-правила PageSpeed могут переместить шаблоны, в которых определяется строчный , в шапку.
  • Предварительный запуск шаблона невозможен, это значит что нельзя предварительно загрузить ресурсы, выполнить JS, загрузить исходный CSS, и т.д. Это касается и стороны сервера, и клиента. Шаблон воспроизводится только когда он активирован.
  • Будьте осторожны с вложенными шаблонами. Они ведут себя не так, как вы можете ожидать.
template> ul> template> li>Всякая всячина li> template> ul> template> 

Активация внешнего шаблона не означает активацию внутренних. То есть, во вложенных шаблонах дочерние шаблоны должны быть активированы вручную.

Путь к стандарту

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

Метод 1: Скрытый DOM

Один из подходов, который использовался разработчиками продолжительное время предусматривает создание «скрытого» DOM, который не отображается благодаря атрибуту hidden или display:none .

div >"mytemplate" hidden> img src="logo.png"> div >"comment">

Хотя этот приём работает, у него есть ряд недостатков. Вот краткий обзор этого приёма:

  • Использование DOM — браузер понимает DOM. Причём очень хорошо. Его легко можно клонировать.
  • Ничто не отображается — добавление hidden предотвращает отображение блока.
  • Брак инертности — хотя содержимое скрыто, на изображение всё равно происходит запрос.
  • Трудности стилизации и оформления — все CSS-правила документа, в который вставлен скрытый DOM, должны содержать приставку #mytemplate для того, чтобы они применялись только внутри шаблона. Это ненадёжно и не даёт гарантии, что в будущем не возникнет конфликтов пространства имен. Например, если на странице уже есть элемент с таким id , то мы влипли.

Метод 2: Перегрузка скрипта

Ещё один приём предусматривает перегрузку и управление его содержимым как строкой. Первым кто так сделал был Джон Резиг (John Resig), представивший в 2008 году свой микро-шаблонизатор. Сегодня их существует множество, в том числе шаблонизаторы нового поколения вроде handlebars.js.

script id="mytemplate" type="text/x-handlebars-template"> img src="logo.png"> div class="comment"> div>  script> 

Обзор этого приёма:

  • Ничто не отображается — браузер не отображает этот блок, потому что для установлено display:none по умолчанию.
  • Инертность — браузер не парсит содержимое как скрипт JS, потому что для него установлен тип отличный от “text/javascript”.
  • Проблемы с безопасностью — поощряется использование .innerHTML . Строчный парсинг предоставляемых пользователем данных может привести к уязвимости к межсайтовому скриптингу.

Заключение

Помните как упростилась работа с DOM благодаря jQuery? В результате в платформу был добавлен querySelector() / querySelectorAll() . Безусловная победа, не так ли? Благодаря этой библиотеке обращения к DOM с помощью CSS-селекторов стали общепринятыми и затем были включены в стандарты. Так происходит не всегда, но я обожаю такие случаи.

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

Дополнительные материалы

  • Спецификация W3C
  • Введение в Веб-компоненты
  • компоненты (видео) — невероятно полная презентация от вашего покорного слуги.

Создание представлений HTML с помощью шаблонов Razor

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

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

Xamarin предлагает лучшее из обоих миров, особенно при использовании обработчика шаблонов Razor HTML. С помощью Xamarin вы можете создавать кроссплатформенные представления HTML на основе шаблонов, которые используют JavaScript и CSS, но также имеют полный доступ к api-интерфейсам базовой платформы и быстрой обработке с помощью C#.

В этом документе объясняется, как использовать подсистему шаблонов Razor для создания представлений HTML+JavaScript+CSS, которые можно использовать на разных мобильных платформах с помощью Xamarin.

Программное использование веб-представлений

Прежде чем мы узнаем о Razor, в этом разделе рассматривается использование веб-представлений для отображения html-содержимого напрямую, в частности HTML-содержимого, создаваемого в приложении.

Xamarin предоставляет полный доступ к API базовой платформы как в iOS, так и в Android, поэтому легко создавать и отображать HTML с помощью C#. Ниже приведен базовый синтаксис для каждой платформы.

iOS

Отображение HTML в элементе управления UIWebView в Xamarin.iOS также занимает всего несколько строк кода:

var webView = new UIWebView (View.Bounds); View.AddSubview(webView); string contentDirectoryPath = Path.Combine (NSBundle.MainBundle.BundlePath, "Content/"); var html = "

Hello

World

"; webView.LoadHtmlString(html, NSBundle.MainBundle.BundleUrl);

Дополнительные сведения об использовании элемента управления UIWebView см. в рецептах для iOS UIWebView .

Android

Отображение HTML-кода в элементе управления WebView с помощью Xamarin.Android выполняется всего в нескольких строках кода:

// webView is declared in an AXML layout file var webView = FindViewById (Resource.Id.webView); // enable JavaScript execution in your html view so you can provide "alerts" and other js webView.SetWebChromeClient(new WebChromeClient()); var html = "

Hello

World

"; webView.LoadDataWithBaseURL("file:///android_asset/", html, "text/html", "UTF-8", null);

Дополнительные сведения об использовании элемента управления WebView см. в разделе Android WebView .

Указание базового каталога

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

   

ссылаться на следующие файлы: style.css, monkey.jpg и jscript.js. Параметр базового каталога сообщает веб-представлению, где находятся эти файлы, чтобы их можно было загрузить на страницу.

iOS

Выходные данные шаблона отображаются в iOS со следующим кодом C#:

webView.LoadHtmlString (page, NSBundle.MainBundle.BundleUrl); 

Базовый каталог указывается как NSBundle.MainBundle.BundleUrl , который относится к каталогу, в котором установлено приложение. Все файлы в папке Resources копируются в это расположение, например файл style.css , показанный здесь:

Действие сборки для всех статических файлов содержимого должно иметь значение BundleResource:

Android

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

webView.LoadDataWithBaseURL("file:///android_asset/", page, "text/html", "UTF-8", null); 

Специальная строка file:///android_asset/ относится к папке Android Assets в приложении, содержащей файл style.css .

Действие сборки для всех статических файлов содержимого должно иметь значение AndroidAsset.

Вызов C# из HTML и JavaScript

Когда HTML-страница загружается в веб-представление, она обрабатывает ссылки и формы так же, как если бы страница была загружена с сервера. Это означает, что если пользователь щелкнет ссылку или отправит форму, веб-представление попытается перейти к указанному целевому объекту.

Если ссылка находится на внешнем сервере (например, google.com), веб-представление попытается загрузить внешний веб-сайт (при условии, что имеется подключение к Интернету).

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

Действия формы следуют тому же правилу.

Вы не собираетесь размещать веб-сервер на клиенте; Однако вы можете использовать те же методы взаимодействия с сервером, которые используются в современных шаблонах адаптивного проектирования, чтобы вызывать службы по протоколу HTTP GET и асинхронно обрабатывать ответы, создавая JavaScript (или вызывая JavaScript, уже размещенный в веб-представлении). Это позволяет легко передавать данные из HTML обратно в код C# для обработки, а затем отображать результаты обратно на HTML-странице.

И iOS, и Android предоставляют механизм перехвата этими событиями навигации в коде приложения, что позволяет коду приложения реагировать (при необходимости). Эта функция имеет решающее значение для создания гибридных приложений, так как она позволяет машинный код взаимодействовать с веб-представлением.

iOS

Событие ShouldStartLoad в веб-представлении в iOS можно переопределить, чтобы позволить коду приложения обрабатывать запрос навигации (например, щелкнуть ссылку). Параметры метода предоставляют все сведения

bool HandleShouldStartLoad (UIWebView webView, NSUrlRequest request, UIWebViewNavigationType navigationType) < // return true if handled in code // return false to let the web view follow the link >

а затем назначьте обработчик событий:

webView.ShouldStartLoad += HandleShouldStartLoad; 
Android

В Android просто подкласс WebViewClient, а затем реализуйте код для ответа на запрос навигации.

class HybridWebViewClient : WebViewClient < public override bool ShouldOverrideUrlLoading (WebView webView, IWebResourceRequest request) < // return true if handled in code // return false to let the web view follow the link >> 

а затем задайте клиент в веб-представлении:

webView.SetWebViewClient (new HybridWebViewClient ()); 

Вызов JavaScript из C#

Помимо того, что в веб-представлении нужно загрузить новую HTML-страницу, код C# также может запускать JavaScript на текущей отображаемой странице. Целые блоки кода JavaScript можно создавать с помощью строк C# и выполнять их, а также создавать вызовы методов JavaScript, которые уже доступны на странице с помощью script тегов.

Android

Создайте выполняемый код JavaScript, а затем введите в него префикс «javascript:» и укажите веб-представлению, чтобы загрузить строку:

var js = "alert('test');"; webView.LoadUrl ("javascript:" + js); 
iOS

Веб-представления iOS предоставляют метод, специально предназначенный для вызова JavaScript:

var js = "alert('test');"; webView.EvaluateJavascript (js); 

Итоги

В этом разделе представлены функции элементов управления представлением веб-страниц в Android и iOS, которые позволяют создавать гибридные приложения с помощью Xamarin, в том числе:

  • Возможность загрузки HTML из строк, созданных в коде;
  • Возможность ссылаться на локальные файлы (CSS, JavaScript, Images или другие HTML-файлы);
  • Возможность перехвата запросов навигации в коде C#;
  • Возможность вызова JavaScript из кода C#.

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

Что такое Razor?

Razor — это модуль шаблонов, который был представлен с ASP.NET MVC, изначально для запуска на сервере и создания HTML-кода, который будет использоваться в веб-браузерах.

Модуль шаблонов Razor расширяет стандартный синтаксис HTML с помощью C#, чтобы можно было легко выразить макет и внедрить таблицы стилей CSS и JavaScript. Шаблон может ссылаться на класс Model, который может быть любым пользовательским типом и доступ к свойствам которого можно получить непосредственно из шаблона. Одним из его main преимуществ является возможность легко сочетать синтаксис HTML и C#.

Шаблоны Razor не ограничиваются использованием на стороне сервера, они также могут быть включены в приложения Xamarin. Использование шаблонов Razor вместе с возможностью программной работы с представлениями веб-сайтов позволяет создавать сложные кроссплатформенные гибридные приложения с помощью Xamarin.

Основные сведения о шаблоне Razor

Файлы шаблонов Razor имеют расширение CSHTML . Их можно добавить в проект Xamarin из раздела Шаблон текста диалогового окна Создание файла :

Новый файл — шаблон Razor

Ниже показан простой шаблон Razor ( RazorView.cshtml).

@model string  

@Model

Обратите внимание на следующие отличия от обычного HTML-файла:

  • Символ @ имеет особое значение в шаблонах Razor— он указывает, что следующее выражение является C# для оценки.
  • @model Директива всегда отображается как первая строка файла шаблона Razor.
  • За @model директивой должен следовать Тип. В этом примере в шаблон передается простая строка, но это может быть любой пользовательский класс.
  • Если @Model на шаблон ссылается весь шаблон, он предоставляет ссылку на объект, передаваемый в шаблон при его создании (в этом примере это будет строка).
  • Интегрированная среда разработки автоматически создаст разделяемый класс для шаблонов (файлов с расширением .cshtml ). Этот код можно просмотреть, но его не следует изменять. . Разделяемый класс называется RazorView в соответствии с именем файла шаблона .cshtml. Именно это имя используется для ссылки на шаблон в коде C#.
  • @using Инструкции также можно включить в верхнюю часть шаблона Razor, чтобы включить дополнительные пространства имен.

Затем окончательные выходные данные HTML можно создать с помощью следующего кода C#. Обратите внимание, что в поле Модель указывается строка «Hello World», которая будет включена в выходные данные отображаемого шаблона.

var template = new RazorView () < Model = "Hello World" >; var page = template.GenerateString (); 

Ниже приведены выходные данные, отображаемые в веб-представлении симулятора iOS и эмулятора Android:

Дополнительные возможности синтаксиса Razor

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

public class Monkey < public string Name < get; set; >public DateTime Birthday < get; set; >public List FavoriteFoods < get; set; >> 

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

var animal = new Monkey < Name = "Rupert", Birthday=new DateTime(2011, 04, 01), FavoriteFoods = new List >; 
Отображение свойств модели

Если модель является классом со свойствами, на них легко ссылаются в шаблоне Razor, как показано в этом примере шаблона:

@model Monkey  

@Model.Name

Birthday: @(Model.Birthday.ToString("d MMMM yyyy"))

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

var template = new RazorView () < Model = animal >; var page = template.GenerateString (); 

Окончательные выходные данные отображаются здесь в веб-представлении симулятора iOS и Android Emulator:

Операторы C#

В шаблон можно включить более сложный код C#, например обновление свойств Model и вычисление возраста в этом примере:

@model Monkey  @ < Model.Name = "Rupert X. Monkey"; Model.Birthday = new DateTime(2011,3,1); >

@Model.Name

Birthday: @Model.Birthday.ToString("d MMMM yyyy")

Age: @(Math.Floor(DateTime.Now.Date.Subtract (Model.Birthday.Date).TotalDays/365)) years old

Вы можете написать сложные однострочные выражения C# (например, форматирование возраста), окружив код с @() помощью .

Можно написать несколько операторов C#, окружив их с @<> помощью .

Операторы If-else

Ветви кода можно выразить с помощью @if , как показано в этом примере шаблона.

@model Monkey  

@Model.Name

Birthday: @(Model.Birthday.ToString("d MMMM yyyy"))

Age: @(Math.Floor(DateTime.Now.Date.Subtract (Model.Birthday.Date).TotalDays/365)) years old

Favorite Foods:

@if (Model.FavoriteFoods.Count == 0) <

No favorites

> else <

@Model.FavoriteFoods.Count favorites

>
Циклы

Можно также добавить конструкции циклов, такие как foreach . Префикс @ можно использовать в переменной цикла ( @food в данном случае) для отрисовки в ФОРМАТЕ HTML.

    @foreach (var food in @Model.FavoriteFoods)

  • @food >

Выходные данные приведенного выше шаблона отображаются в симуляторе iOS и Android Emulator:

Руперт X Обезьяна

В этом разделе рассматриваются основы использования шаблонов Razor для отрисовки простых представлений только для чтения. В следующем разделе объясняется, как создавать более полные приложения с помощью Razor, которые могут принимать ввод данных пользователем и взаимодействовать между JavaScript в представлении HTML и C#.

Использование шаблонов Razor с Xamarin

В этом разделе объясняется, как создать собственное гибридное приложение с помощью шаблонов решений в Visual Studio для Mac. В окне Создание > файла > доступно три шаблона:

  • Приложение Android WebView для приложения Android > App >
  • Приложение WebView приложения iOS >>
  • проект MVC ASP.NET

Окно Новое решение для проектов iPhone и Android выглядит следующим образом: в описании решения справа выделена поддержка обработчика шаблонов Razor.

Создание решений iPhone и Android

Обратите внимание, что шаблон .cshtml Razor можно легко добавить в любой существующий проект Xamarin. Использовать эти шаблоны решений необязательно. Для использования Razor для проектов iOS не требуется раскадровка; Просто добавьте элемент управления UIWebView в любое представление программным способом, и вы можете отобразить шаблоны Razor целиком в коде C#.

Ниже показано содержимое решения шаблона по умолчанию для проектов iPhone и Android:

Шаблоны iPhone и Android

Шаблоны предоставляют готовую инфраструктуру приложений для загрузки шаблона Razor с объектом модели данных, обработки ввода пользователем и обратного взаимодействия с пользователем через JavaScript.

Важные части решения:

  • Статическое содержимое, например файл style.css .
  • Файлы шаблонов Razor .cshtml, такие как RazorView.cshtml .
  • Классы моделей, на которые ссылаются шаблоны Razor, например ExampleModel.cs .
  • Зависящий от платформы класс, который создает веб-представление и отрисовывает шаблон, например MainActivity в Android и iPhoneHybridViewController в iOS.

В следующем разделе объясняется, как работают проекты.

Статическое содержимое

Статическое содержимое включает таблицы стилей CSS, изображения, файлы JavaScript или другое содержимое, которое может быть связано с HTML-файлом, отображаемым в веб-представлении, или ссылаться на нее.

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

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

Шаблоны Cshtml Razor

Шаблон содержит CSHTML-файл Razor, содержащий предварительно написанный код для обмена данными между HTML/JavaScript и C#. Это позволит создавать сложные гибридные приложения, которые не только отображают данные только для чтения из модели, но и принимают пользовательский ввод в HTML и передают их обратно в код C# для обработки или хранения.

Отрисовка шаблона

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

Блок-схема Razor

Вызов кода C# из шаблона

Обмен данными из отображаемого веб-представления, вызывающего обратно на C#, выполняется путем задания URL-адреса веб-представления, а затем перехвата запроса в C# для обработки собственного запроса без перезагрузки веб-представления.

Пример можно увидеть в том, как обрабатывается кнопка RazorView. Кнопка имеет следующий HTML-код:

Функция InvokeCSharpWithFormValues JavaScript считывает все значения из HTML-формы и задает location.href для веб-представления:

location.href = "hybrid:" + elm.name + "?" + qs; 

При этом предпринимается попытка перейти к веб-представлению по URL-адресу с помощью пользовательской схемы (например, hybrid: ).

hybrid:UpdateLabel?textbox=SomeValue&UpdateLabel=Click 

Когда собственное веб-представление обрабатывает этот запрос навигации, у нас есть возможность перехватить его. В iOS это делается путем обработки события HandleShouldStartLoad uiWebView. В Android мы просто подкласс WebViewClient, используемый в форме, и переопределяем ShouldOverrideUrlLoading.

Внутренние элементы этих двух перехватчиков навигации по сути одинаковы.

Во-первых, проверка URL-адрес, который веб-представление пытается загрузить, и если он не начинается с пользовательской схемы ( hybrid: ), разрешите навигацию выполняться в обычном режиме.

Для настраиваемой схемы URL-адресов — все в URL-адресе между схемой и «?». — имя обрабатываемого метода (в данном случае —UpdateLabel). Все элементы в строке запроса будут рассматриваться как параметры для вызова метода :

var resources = url.Substring(scheme.Length).Split('?'); var method = resources [0]; var parameters = System.Web.HttpUtility.ParseQueryString(resources[1]); 

UpdateLabel В этом примере выполняет минимальный объем операций со строкой в параметре textbox (добавление «C# говорит» к строке), а затем вызывает обратно в веб-представление.

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

Управление шаблоном из C#

Обмен данными с отображаемым html-представлением веб-страницы из C# осуществляется путем вызова JavaScript в представлении веб-страницы. В iOS это делается путем вызова EvaluateJavascript в UIWebView:

webView.EvaluateJavascript (js); 

В Android JavaScript можно вызвать в веб-представлении, загрузив JavaScript в качестве URL-адреса с помощью «javascript:» схемы URL-адресов:

webView.LoadUrl ("javascript:" + js); 

Создание приложения по-настоящему гибридным

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

HTML может отлично подходит для создания прототипов и отображения типов в Интернете, таких как форматированный текст и адаптивный макет. Однако не все задачи подходят для HTML и JavaScript. Например, прокрутка длинных списков данных лучше работает с помощью собственных элементов управления пользовательского интерфейса (таких как UITableView в iOS или ListView в Android).

Веб-представления в шаблоне можно легко дополнить элементами управления для конкретных платформ — просто измените MainStoryboard.storyboard с помощью Xcode на компьютере Mac или Resources/layout/Main.axml на Android.

Пример RazorTodo

Репозиторий RazorTodo содержит два отдельных решения для демонстрации различий между полностью управляемым HTML-приложением и приложением, объединяющим HTML с собственными элементами управления:

  • RazorTodo — полностью управляемое HTML-приложение с использованием шаблонов Razor.
  • RazorNativeTodo — использует собственные элементы управления представления списка для iOS и Android, но отображает экран редактирования с помощью HTML и Razor.

Эти приложения Xamarin выполняются как в iOS, так и в Android, используя переносимые библиотеки классов (PCL) для совместного использования общего кода, такого как классы баз данных и моделей. Шаблоны Razor .cshtml также можно включить в PCL, чтобы их можно было легко использовать на разных платформах.

Оба примера приложений включают API для общего доступа к Twitter и преобразования текста в речь с собственной платформы, демонстрируя, что гибридные приложения с Xamarin по-прежнему имеют доступ ко всем базовым функциям из представлений На основе шаблонов Html Razor.

Приложение RazorTodo использует HTML-шаблоны Razor для представлений списка и редактирования. Это означает, что мы можем почти полностью создать приложение в общей переносимой библиотеке классов (включая базу данных и шаблоны Razor .cshtml ). На снимках экрана ниже показаны приложения iOS и Android.

RazorTodo

Приложение RazorNativeTodo использует html-шаблон Razor для представления редактирования, но реализует собственный прокручивающийся список на каждой платформе. Это обеспечивает ряд преимуществ, в том числе:

  • Производительность. Собственные элементы управления прокруткой используют виртуализацию, чтобы обеспечить быструю и плавную прокрутку даже с очень длинными списками данных.
  • Собственный интерфейс . Элементы пользовательского интерфейса для конкретных платформ легко включены, например поддержка быстрой прокрутки индекса в iOS и Android.

Ключевым преимуществом создания гибридных приложений с помощью Xamarin является то, что вы можете начать с полностью управляемого HTML-интерфейса (например, в первом примере), а затем при необходимости добавить функциональные возможности для конкретных платформ (как показано во втором примере). Ниже показаны собственные экраны списков и html-экраны редактирования Razor в iOS и Android.

RazorNativeTodo

Итоги

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

Затем он обсудил механизм создания шаблонов Razor и синтаксис, который можно использовать для быстрого создания HTML в приложениях Xamarin с помощью . Cshtml Файлы шаблонов Razor. В ней также описаны шаблоны решений Visual Studio для Mac, которые позволяют быстро приступить к созданию гибридных приложений с помощью Xamarin.

Наконец, он представил примеры RazorTodo, которые демонстрируют, как объединить веб-представления с собственными пользовательскими интерфейсами и API.

Связанные ссылки

  • Пример RazorTodo
  • MVC 3 — обработчик представлений Razor (Майкрософт)
  • Введение в веб-программирование ASP.NET с использованием синтаксиса Razor (Майкрософт)

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *