Шаблоны проектирования js. Шаблоны проектирования в JavaScript простыми словами

До тех пор, пока вы разрабатываете простые приложения на языке Javascript, у вас не будет особых проблем с выводом данных на веб-страницу.

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

Например, нужно вывести на страницу список пользователей сайта со всеми их параметрами (например, id, имя. Могут быть также возраст, пол, и.т.д.). Предположим, что эти данные находятся внутри объекта usersData

Var usersData = [ { name: "Dima", id: 1 }, { name: "Katy", id: 2 }, { name: "Lena", id: 3 } ];

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

For(var i=0; i" + userData.name[i] + ""; }

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

Но, куда более наглядно будет вывод данных вот в такой форме:

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

    Такая форма записи становиться возможной при использовании так называемых шаблонов.

    Шаблон – это определенная заготовка в HTML-коде, которая написана по определенным правилам. Когда Javascript-код начинает взаимодействовать с такой заготовкой, код шаблона будет преобразовываться в HTML-код или узлы DOM-дерева на странице.

    Синтаксис шаблонов в Javascript может быть разным. Единого стандарта нет и все будет зависеть от того, какой библиотекой или плагином вы будете пользоваться.

    Вот шаблон, который создает меню на сайте:

    Здесь вместо фигурных скобок используется вот такая форма записи

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

    MyButton { box-shadow: ; background:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, ), color-stop(1, )); background:linear-gradient(to bottom, 5%, 100%); filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="", endColorstr="",GradientType=0);

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

    Интуитивно понятный код, даже не для программиста;

    Более сокращенная форма записи;

    Данные, javascript-код и вывод данных на страницы отделены друг от друга, так ими намного проще управлять.

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

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

    Простая фабрика

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

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

    Пример реализации

    Создадим неявный интерфейс для всех дверей:

    /* Door getWidth() getHeight() */ class WoodenDoor { constructor(width, height){ this.width = width this.height = height } getWidth(){ return this.width } getHeight(){ return this.height } }

    Организуем фабрику, которая будет их производить:

    Const DoorFactory = { makeDoor: (width, height) => new WoodenDoor(width, height) }

    Все, можно работать:

    Const door = DoorFactory.makeDoor(100, 200) console.log("Width:", door.getWidth()) console.log("Height:", door.getHeight())

    Паттерн полезен, если создание объекта требует некоторой логики. Имеет смысл вынести повторяющийся код в отдельную Простую фабрику.

    Фабричный метод

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

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

    Пример реализации

    Начнем с самого гамбургера:

    Class Burger { constructor(builder) { this.size = builder.size this.cheeze = builder.cheeze || false this.pepperoni = builder.pepperoni || false this.lettuce = builder.lettuce || false this.tomato = builder.tomato || false } }

    А вот и Строитель:

    Class BurgerBuilder { constructor(size) { this.size = size } addPepperoni() { this.pepperoni = true return this } addLettuce() { this.lettuce = true return this } addCheeze() { this.cheeze = true return this } addTomato() { this.tomato = true return this } build() { return new Burger(this) } }

    Вуаля! Вот наш бургер:

    Const burger = (new BurgerBuilder(14)) .addPepperoni() .addLettuce() .addTomato() .build()

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

    Синглтон

    У страны должен быть единственный президент, иначе начнется беспорядок.

    Этот паттерн оборачивает объект и динамически изменяет его поведение.

    Пример реализации

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

    /* Coffee interface: getCost() getDescription() */ class SimpleCoffee{ getCost() { return 10 } getDescription() { return "Simple coffee" } }

    Мы хотим иметь возможность добавлять в кофе различные добавки, для этого создадим некоторые декораторы:

    Class MilkCoffee { constructor(coffee) { this.coffee = coffee } getCost() { return this.coffee.getCost() + 2 } getDescription() { return this.coffee.getDescription() + ", milk" } } class WhipCoffee { constructor(coffee) { this.coffee = coffee } getCost() { return this.coffee.getCost() + 5 } getDescription() { return this.coffee.getDescription() + ", whip" } } class VanillaCoffee { constructor(coffee) { this.coffee = coffee } getCost() { return this.coffee.getCost() + 3 } getDescription() { return this.coffee.getDescription() + ", vanilla" } }

    Теперь вы можете сделать кофе на свой вкус:

    Let someCoffee someCoffee = new SimpleCoffee() console.log(someCoffee.getCost())// 10 console.log(someCoffee.getDescription())// Простой кофе someCoffee = new MilkCoffee(someCoffee) console.log(someCoffee.getCost())// 12 console.log(someCoffee.getDescription())// Простой кофе, молоко someCoffee = new WhipCoffee(someCoffee) console.log(someCoffee.getCost())// 17 console.log(someCoffee.getDescription())// Простой кофе, молоко, сливки someCoffee = new VanillaCoffee(someCoffee) console.log(someCoffee.getCost())// 20 console.log(someCoffee.getDescription())// Простой кофе, молоко, сливки, ваниль

    Фасад

    Чтобы включить компьютер достаточно нажать кнопку. Это очень просто, но внутри включающегося компьютера происходит много сложных действий. Простой интерфейс к сложной системе – это и есть Фасад .

    Пример реализации

    Создадим класс компьютера:

    Class Computer { getElectricShock() { console.log("Ouch!") } makeSound() { console.log("Beep beep!") } showLoadingScreen() { console.log("Loading..") } bam() { console.log("Ready to be used!") } closeEverything() { console.log("Bup bup bup buzzzz!") } sooth() { console.log("Zzzzz") } pullCurrent() { console.log("Haaah!") } }

    и простой Фасад для его сложных функций:

    Class ComputerFacade { constructor(computer) { this.computer = computer } turnOn() { this.computer.getElectricShock() this.computer.makeSound() this.computer.showLoadingScreen() this.computer.bam() } turnOff() { this.computer.closeEverything() this.computer.pullCurrent() this.computer.sooth() } }

    Так работать с компьютером намного проще:

    Const computer = new ComputerFacade(new Computer()) computer.turnOn() // Ouch! Beep beep! Loading.. Ready to be used! computer.turnOff() // Bup bup buzzz! Haah! Zzzzz

    Приспособленец

    В поездах дальнего следования воду для горячих напитков кипятят в больших емкостях – сразу для всех. Это позволяет экономить электричество (или газ).

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

    Паттерн Наблюдатель позволяет оповещать всех заинтересованных объектов о произошедших изменениях.

    Пример реализации

    Соискатели хотят получать уведомления:

    Const JobPost = title => ({ title: title }) class JobSeeker { constructor(name) { this._name = name } notify(jobPost) { console.log(this._name, "has been notified of a new posting:", jobPost.title) } }

    А Доска объявлений может эти уведомления рассылать:

    Class JobBoard { constructor() { this._subscribers = } subscribe(jobSeeker) { this._subscribers.push(jobSeeker) } addJob(jobPosting) { this._subscribers.forEach(subscriber => { subscriber.notify(jobPosting) }) } }

    // создаем подписчиков const jonDoe = new JobSeeker("John Doe") const janeDoe = new JobSeeker("Jane Doe") const kaneDoe = new JobSeeker("Kane Doe") // создаем доску объявлений // подписываем соискателей const jobBoard = new JobBoard() jobBoard.subscribe(jonDoe) jobBoard.subscribe(janeDoe) // оповещаем подписчиков о новой вакансии jobBoard.addJob(JobPost("Software Engineer")) // John Doe has been notified of a new posting: Software Engineer // Jane Doe has been notified of a new posting: Software Engineer

    Посетитель

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

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

    Пример реализации

    Смоделируем зоопарк с разными видами животных:

    Class Monkey { shout() { console.log("Ooh oo aa aa!") } accept(operation) { operation.visitMonkey(this) } } class Lion { roar() { console.log("Roaaar!") } accept(operation) { operation.visitLion(this) } } class Dolphin { speak() { console.log("Tuut tuttu tuutt!") } accept(operation) { operation.visitDolphin(this) } }

    Теперь мы хотим послушать, какие звуки они издают. Для этого создадим Посетителя:

    Const speak = { visitMonkey(monkey){ monkey.shout() }, visitLion(lion){ lion.roar() }, visitDolphin(dolphin){ dolphin.speak() } }

    Он просто обращается к каждому классу и вызывает нужный метод:

    Const monkey = new Monkey() const lion = new Lion() const dolphin = new Dolphin() monkey.accept(speak) // Ooh oo aa aa! lion.accept(speak) // Roaaar! dolphin.accept(speak) // Tuut tutt tuutt!

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

    Const jump = { visitMonkey(monkey) { console.log("Jumped 20 feet high! on to the tree!") }, visitLion(lion) { console.log("Jumped 7 feet! Back on the ground!") }, visitDolphin(dolphin) { console.log("Walked on water a little and disappeared") } }

    Monkey.accept(speak) // Ooh oo aa aa! monkey.accept(jump) // Jumped 20 feet high! on to the tree! lion.accept(speak) // Roaaar! lion.accept(jump) // Jumped 7 feet! Back on the ground! dolphin.accept(speak) // Tuut tutt tuutt! dolphin.accept(jump) // Walked on water a little and disappeared

    Стратегия

    Для упорядочивания некоторого набора данных вы используете алгоритм пузырьковой сортировки. Она отлично справляется с небольшими объемами, но тормозит с крупными. У быстрой сортировки противоположная проблема. Тогда вы решаете изменять алгоритм в зависимости от размера набора. Это ваша Стратегия.

    Шаблон Стратегия позволяет переключать используемый алгоритм в зависимости от ситуации.

    Пример реализации

    Воплотить Стратегию в JavaScript помогут функции первого класса.

    Const bubbleSort = dataset => { console.log("Sorting with bubble sort") // ... // ... return dataset } const quickSort = dataset => { console.log("Sorting with quick sort") // ... // ... return dataset }

    А это клиент, который может использовать любую стратегию:

    Const sorter = dataset => { if(dataset.length > 5){ return quickSort } else { return bubbleSort } }

    Теперь можно сортировать массивы:

    Const longDataSet = const shortDataSet = const sorter1 = sorter(longDataSet) const sorter2 = sorter(shortDataSet) sorter1(longDataSet) // Sorting with quick sort sorter2(shortDataSet) // Sorting with bubble sort

    Состояние

    Вы рисуете в Paint. В зависимости от вашего выбора кисть меняет свое состояние: рисует красным, синим или любым другим цветом.

    Паттерн Состояние позволяет изменять поведение класса при изменении состояния.

    Пример реализации

    Создадим текстовый редактор, в котором можно менять состояние текста – жирный, курсив и т. д.

    Это функции преобразования:

    Const upperCase = inputString => inputString.toUpperCase() const lowerCase = inputString => inputString.toLowerCase() const defaultTransform = inputString => inputString

    А вот и сам редактор:

    Class TextEditor { constructor(transform) { this._transform = transform } setTransform(transform) { this._transform = transform } type(words) { console.log(this._transform(words)) } }

    Можно работать:

    Const editor = new TextEditor(defaultTransform) editor.type("First line") editor.setTransform(upperCase) editor.type("Second line") editor.type("Third line") editor.setTransform(lowerCase) editor.type("Fourth line") editor.type("Fifth line") // First line // SECOND LINE // THIRD LINE // fourth line // fifth line

    Шаблонный метод

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

    Шаблонный метод определяет «скелет» алгоритма, но делегирует реализацию шагов дочерним классам.

    Пример реализации

    Создадим инструмент для тестирования, сборки и разворачивания приложения.

    Базовый класс определяет скелет алгоритма сборки:

    Class Builder { // Template method build() { this.test() this.lint() this.assemble() this.deploy() } }

    А дочерние классы – конкретную реализацию каждого шага:

    Class AndroidBuilder extends Builder { test() { console.log("Running android tests") } lint() { console.log("Linting the android code") } assemble() { console.log("Assembling the android build") } deploy() { console.log("Deploying android build to server") } } class IosBuilder extends Builder { test() { console.log("Running ios tests") } lint() { console.log("Linting the ios code") } assemble() { console.log("Assembling the ios build") } deploy() { console.log("Deploying ios build to server") } }

    Соберем проект:

    Const androidBuilder = new AndroidBuilder() androidBuilder.build() // Running android tests // Linting the android code // Assembling the android build // Deploying android build to server const iosBuilder = new IosBuilder() iosBuilder.build() // Running ios tests // Linting the ios code // Assembling the ios build // Deploying ios build to server

    • Перевод

    Примечание переводчика: Тема наследования в JavaScript является одной из самых тяжелых для новичков. С добавлением нового синтаксиса с ключевым словом class, понимание наследования явно не стало проще, хотя кардинально нового ничего не появилось. В данной статье не затрагиваются нюансы реализации прототипного наследования в JavaScript, поэтому если у читателя возникли вопросы, то рекомендую прочитать следующие статьи: Основы и заблуждения насчет JavaScript и Понимание ООП в JavaScript [Часть 1]

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

    JavaScript является очень мощным языком. Настолько мощным, что в нем сосуществует множество различных способов проектирования и создания объектов. У каждого способа есть свои плюсы и минусы и я бы хотел помочь новичкам разобраться в этом. Это продолжение моего предыдущего поста, Хватит «классифицировать» JavaScript . Я получил много вопросов и комментариев с просьбами привести примеры, и для именно этой цели я решил написать эту статью.

    JavaScript использует прототипное наследование Это означает, что в JavaScript объекты наследуются от других объектов. Простые объекты в JavaScript, созданные с использованием {} фигурных скобок, имеют только один прототип: Object.prototype . Object.prototype , в свою очередь тоже объект, и все свойства и методы Object.prototype доступны для всех объектов.

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

    Определения прототипа и создание объектовСпособ 1: Шаблон конструктор JavaScript имеет особый тип функции называемых конструкторами, которые действуют так же, как и конструкторы в других языках. Функции-конструкторы вызываются только с помощью ключевого слова new и связывают создаваемый объект с контекстом функции-конструктора через ключевое слово this . Типичный конструктор может выглядеть следующим образом:
    function Animal(type){ this.type = type; } Animal.isAnimal = function(obj, type){ if(!Animal.prototype.isPrototypeOf(obj)){ return false; } return type ? obj.type === type: true; }; function Dog(name, breed){ Animal.call(this, "dog"); this.name = name; this.breed = breed; } Object.setPrototypeOf(Dog.prototype, Animal.prototype); Dog.prototype.bark = function(){ console.log("ruff, ruff"); }; Dog.prototype.print = function(){ console.log("The dog " + this.name + " is a " + this.breed); }; Dog.isDog = function(obj){ return Animal.isAnimal(obj, "dog"); };
    Использование этого конструктора выглядит также как и создание объекта в других языках:
    var sparkie = new Dog("Sparkie", "Border Collie"); sparkie.name; // "Sparkie" sparkie.breed; // "Border Collie" sparkie.bark(); // console: "ruff, ruff" sparkie.print(); // console: "The dog Sparkie is a Border Collie" Dog.isDog(sparkie); // true
    bark и print методы прототипа, которые применяются для всех объектов созданных с помощью конструктора Dog . Свойства name и breed инициализируются в конструкторе. Это общепринятая практика, когда все методы определяются в прототипе, а свойства инициализируются конструктором.Способ 2: Определение класса в ES2015 (ES6) Ключевое слово class было зарезервировано в JavaScript с самого начала и вот наконец-то пришло время его использовать. Определения классов в JavaScript схоже с другими языками.
    class Animal { constructor(type){ this.type = type; } static isAnimal(obj, type){ if(!Animal.prototype.isPrototypeOf(obj)){ return false; } return type ? obj.type === type: true; } } class Dog extends Animal { constructor(name, breed){ super("dog"); this.name = name; this.breed = breed; } bark(){ console.log("ruff, ruff"); } print(){ console.log("The dog " + this.name + " is a " + this.breed); } static isDog(obj){ return Animal.isAnimal(obj, "dog"); } }
    Многие люди считают этот синтаксис удобным, потому что он объединяет в одном блоке конструктор и объявление статичных и прототипных методов. Использование точно такое же, как и в предыдущем способе.
    var sparkie = new Dog("Sparkie", "Border Collie"); Способ 3: Явное объявление прототипа, Object.create, фабричный метод Этот способ показывает, что на самом деле новый синтаксис с ключевым словом class использует прототипное наследование. Также этот способ позволяет создать новый объект без использования оператора new .
    var Animal = { create(type){ var animal = Object.create(Animal.prototype); animal.type = type; return animal; }, isAnimal(obj, type){ if(!Animal.prototype.isPrototypeOf(obj)){ return false; } return type ? obj.type === type: true; }, prototype: {} }; var Dog = { create(name, breed){ var proto = Object.assign(Animal.create("dog"), Dog.prototype); var dog = Object.create(proto); dog.name = name; dog.breed = breed; return dog; }, isDog(obj){ return Animal.isAnimal(obj, "dog"); }, prototype: { bark(){ console.log("ruff, ruff"); }, print(){ console.log("The dog " + this.name + " is a " + this.breed); } } };
    Этот синтаксис удобен, потому что прототип объявляется явно. Понятно что определено в прототипе, а что определено в самом объекте. Метод Object.create удобен, потому что он позволяет создать объект от указанного прототипа. Проверка с помощью .isPrototypeOf по-прежнему работает в обоих случаях. Использование разнообразно, но не чрезмерно:
    var sparkie = Dog.create("Sparkie", "Border Collie"); sparkie.name; // "Sparkie" sparkie.breed; // "Border Collie" sparkie.bark(); // console: "ruff, ruff" sparkie.print(); // console: "The dog Sparkie is a Border Collie" Dog.isDog(sparkie); // true Способ 4: Object.create, фабрика верхнего уровня, отложенный прототип Этот способ является небольшим изменение способа 3, где сам класс является фабрикой, в отличии от случая когда класс является объектом с фабричным методом. Похоже, на пример конструктора (способ 1), но использует фабричный метод и Object.create .
    function Animal(type){ var animal = Object.create(Animal.prototype); animal.type = type; return animal; } Animal.isAnimal = function(obj, type){ if(!Animal.prototype.isPrototypeOf(obj)){ return false; } return type ? obj.type === type: true; }; Animal.prototype = {}; function Dog(name, breed){ var proto = Object.assign(Animal("dog"), Dog.prototype); var dog = Object.create(proto); dog.name = name; dog.breed = breed; return dog; } Dog.isDog = function(obj){ return Animal.isAnimal(obj, "dog"); }; Dog.prototype = { bark(){ console.log("ruff, ruff"); }, print(){ console.log("The dog " + this.name + " is a " + this.breed); } };
    Этот способ интересен тем, что похож на первой способ, но не требует ключевого слова new и работает с оператором instanceOf . Использование такое же, как и в первом способе, но без использования ключевого слова new :
    var sparkie = Dog("Sparkie", "Border Collie"); sparkie.name; // "Sparkie" sparkie.breed; // "Border Collie" sparkie.bark(); // console: "ruff, ruff" sparkie.print(); // console: "The dog Sparkie is a Border Collie" Dog.isDog(sparkie); // true СравнениеСпособ 1 против Способа 4 Существует довольно мало причин, для того чтобы использовать Способ 1 вместо Способа 4. Способ 1 требует либо использование ключевого слова new , либо добавление следующей проверки в конструкторе:
    if(!(this instanceof Foo)){ return new Foo(a, b, c); }
    В этом случае проще использовать Object.create с фабричным методом. Вы также не можете использовать функции Function#call или Function#apply с функциями-конструкторами, потому что они переопределяют контекст ключевого слова this . Проверка выше, может решить и эту проблему, но если вам нужно работать с неизвестным заранее количеством аргументов, вы должны использовать фабричный метод.Способ 2 против Способа 3 Те же рассуждения о конструкторах и операторе new , что были упомянуты выше, применимы и в этом случае. Проверка с помощью instanceof необходима, если используется новый синтаксис class без использования оператора new или используются Function#call или Function#apply .Мое мнение Программист должен стремиться к ясности своего кода. Синтаксис Способа 3 очень четко показывает, что именно происходит на самом деле. Он также позволяет легко использовать множественное наследование и стековое наследования. Так как оператор new нарушает принцип открытости/закрытости из-за несовместимости с apply или call , его следует избегать. Ключевое слово class скрывает прототипный характер наследования в JavaScript за маской системы классов.
    «Простое лучше мудреного», и использование классов, потому что оно считается более «изощренным» является просто ненужной, технической головомойкой.
    Использование Object.create является более выразительным и ясным, чем использование связки new и this . Кроме того, прототип хранится в объекте, который может быть вне контекста самой фабрики, и таким образом может быть более легко изменен и расширен добавлением методов . Прям как классы в ES6.
    Ключевое слово class , возможно будет наиболее пагубной чертой в JavaScript. Я испытываю огромное уважение к блестящим и очень трудолюбивым людям, которые были вовлечены в процесс написания стандарта, но даже блестящие люди иногда делают неправильные вещи. - Eric Elliott
    Добавление чего-то ненужного и возможно пагубного, противоречащего самой природе языка является необдуманным и ошибочным.
    Если вы решите использовать class , я искренне надеюсь, что мне никогда не придется работать с вашим кодом. На мой взгляд, разработчики должны избегать использования конструкторов, class и new , и использовать методы, которые более естественны парадигме и архитектуре языка. ГлоссарийObject.assign(a, b) копирует все перечислимые (enumerable) свойства объекта b в объект a , а затем возвращает объект a
    Object.create(proto) создает новый объект от указанного прототипа proto
    Object.setPrototypeOf(obj, proto) меняет внутреннее свойство [] объекта obj на proto

    Теги: Добавить метки

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

    Есть много способов создавать шаблоны в Javascript, для них даже придумана отдельная спецификация именуемая Mustache . Она реализована на многих языках, включая Javascript. Например, библиотека Handlebars использует эту спецификацию и даже немного её расширяет. Или популярная мини-библиотека Underscore .

    С версии 3.5 WordPress уже имеет в своем ядре удобный шаблонизатор для JS. Он например используется в админке при создании блоков для медиа-загрузчика. В основе лежит вышеупомянутая библиотека Underscore , синтаксис немного переделан, чтобы больше соответствовать спецификации Mustache .

    Для создания шаблонов в WordPress есть метод wp.template

    wp.template(id)

    Создает объект шаблона из HTML кода. Чтобы получить готовый HTML код для использования в JS, в созданный объект нужно передать данные для заполнения шаблона.

    Возвращает

    Function. Функцию, в которую нужно передать данные для интерполяции шаблона.

    Использование var template = wp.template(id); var HTML = template(data); id(строка)

    Идентификатор HTML элемента который содержит HTML код шаблона. HTML элемент должен иметь указанный тут атрибут id с префиксом tmpl- .

    Например, если тут указать foo , то HTML элемент должен иметь id id="tmpl-foo" .

    Data(объект) JS объект данных, которые будут использованы для заполнения шаблона. Например: { text: "Привет" } .

    Заполнение шаблона (интерполяция)
    • {{{data.unescaped}}} - неочищенные данные.
    • {{data.escaped}} - очищенные данные.
    • - обработать js (eval).
    Префикс data.

    data в шаблоне - это объект исходных данных. В шаблоне нужно использовать именно ключ data .

    Чтобы соответствовать структуре данных возвращаемых функциями: wp_send_json_success() и wp_send_json_error() , wp.template оборачивает все полученные данные в переменную data . Поэтому перед каждым параметром в шаблоне нужно указывать data. , иначе мы получим ошибку: {property} is not defined .

    Правильно {{{data.name}}}

    Неправильно {{{name}}}

    Пример шаблона

    Это будет просто выведено.

    Выведем значение переменной escapedValue {{data.escapedValue}}.

    Если данные содержат разметку, выводим без экранирования:

    {{{data.unescapedValue}}}

    Когда нужно выполнить какую-то логику.

    Будет выведено, только если data.trueValue = true.

    Создание и генерация шаблона Создание шаблона

    Чтобы шаблон никак не фигурировал в DOM дереве, его принято создавать в теге script с указанием типа type="text/html" .

    Привет {{{data.name}}}

    Атрибут id должен начинаться с tmpl- , все что после этого префикса будет затем использовано в функции wp.template("my-template") .

    Создание шаблона в теге script это хак, который отлично подходит для создания html элемента, который никак не используется браузером. Когда указан непонятный для браузера тип он просто игнорирует html тег, а это нам и нужно.

    Шаблон также можно создать в любом другом HTML элементе (например в , который затем можно скрыть), единственное что нужно это указать id атрибут.

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

    Генерация шаблона

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

    Пример (шаблон указан выше)

    // JS var template = wp.template("my-template"), data = { name: "Виктор" }; jQuery(".my-element").html(template(data));

    В результате получим в HTML:

    Привет Виктор

    Пример комментирования на AJAX с использование шаблона

    Создаем шаблон и подключаем скрипт в файле темы functions.php:

  • {{{data.gravatar}}} {{data.comment_author}}