Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. WordPress

Создание внешнего интерфейса WordPress: пользовательская директива для публикации сообщений

by
Difficulty:IntermediateLength:LongLanguages:
This post is part of a series called Building a WordPress-Powered Front End With the WP REST API and AngularJS.
Building a WordPress-Powered Front End: Bootstrapping, Routing, and Services
Building a WordPress-Powered Front End: Posts, Categories, and Users Controllers

Russian (Pусский) translation by Sergey Zhuk (you can also view the original English article)

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

В этой части серии мы будем работать над созданием пользовательской директивы AngularJS для функции публикации сообщений. В текущей части серии мы будем:

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

Итак, начнем с введения в директивы AngularJS и почему они нам нужны.

Представление директив AngularJS

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

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

  1. Листинг поста
  2. Профиль автора
  3. Список категорий сообщений

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

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

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

Планирование пользовательской директивы AngularJS для публикации в сообщениях

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

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

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

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

  1. В URL-адресе в качестве параметров
  2. Прямо к директиве в качестве значения атрибута

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

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

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

Атрибут post-args в приведенном выше фрагменте принимает аргументы для извлечения определенного набора сообщений, и в настоящее время он принимает идентификатор автора. Этот атрибут может принимать любое количество аргументов для извлечения сообщений, поддерживаемых маршрутом /wp/v2/posts. Таким образом, если бы мы получили набор сообщений, созданных пользователем, имеющим идентификатор 1 и принадлежащий к категории ID 10, мы могли бы сделать что-то вроде следующего:

Параметр filter[cat] в приведенном выше коде используется для извлечения набора сообщений, относящихся к определенной категории.

Разбиение на страницы также является важной функцией при работе со страницами для публикации сообщений. Директива будет обрабатывать постраничное разбиение на страницы, и эта функция будет зависеть от значений заголовков X-WP-Total и X-WP-TotalPages, возвращаемых сервером вместе с телом ответа. Следовательно, пользователь сможет перемещаться вперед и назад между предыдущими и следующими наборами сообщений.

Решив вкратце принять заказную директиву для публикации сообщений, у нас теперь есть достаточно прочная основа для начала написания кода.

Создание пользовательской директивы для публикации сообщений

Построение директивы для функции публикации записей включает в себя два шага:

  1. Создание бизнес-логики для извлечения записей и обработки других материалов.
  2. Создание представления для отображения этих сообщений на странице.

Бизнес-логика для нашей настраиваемой директивы будет обрабатываться в объявлении директивы. А для рендеринга данных в DOM мы создадим собственный шаблон для перечисления сообщений. Начнем с объявления директивы.

Объявление директивы

Директивы в AngularJS могут быть объявлены для модуля со следующим синтаксисом:

Здесь мы объявляем директиву на нашем модуле, используя метод .directive(), доступный в модуле. Метод принимает имя директивы в качестве первого аргумента, и это имя тесно связано с именем тега элемента. Поскольку мы хотим, чтобы наш HTML-элемент был вида <post-listing></post-listing>,  мы предоставляем представление имени тега в camel-case формате. Вы можете узнать больше об этом процессе нормализации, выполняемом AngularJS, чтобы согласовать имена директив в официальной документации.

Обозначение, которое мы используем в приведенном выше коде для объявления нашей директивы, называется безопасным способом инъекции зависимостей. И в этой нотации мы предоставляем массив зависимостей в качестве второго аргумента, который потребуется директиве. В настоящее время мы не определили никаких зависимостей для нашей настраиваемой директивы. Но так как нам нужна служба Posts для извлечения сообщений (которые мы создали в предыдущей части серии) и сервисы $routeParams и $location от AngularJS для доступа к параметрам URL и текущему пути, мы определяем их следующим образом:

Эти зависимости затем становятся доступными для функции, которая определена как последний элемент массива. Эта функция возвращает объект, содержащий определение директивы. В настоящее время у нас есть два свойства в объекте определения директивы: restrict и link.

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

  1. A: Для использования директивы в качестве атрибута существующего HTML-элемента.
  2. E: Для использования директивы в качестве имени элемента.
  3. C: для использования директивы в качестве имени класса.
  4. M: Для использования директивы в качестве комментария HTML.

Параметр restrict может также принимать любую комбинацию из четырех указанных выше значений.

Поскольку мы хотим, чтобы наша директива была новым элементом <post-listing></post-listing> , мы устанавливаем параметр ограничения равным E. Если мы должны были определить директиву, используя атрибуты на уже существующем HTML-элементе, то мы могли бы установить эту опцию в A. В этом случае мы могли бы использовать <div post-listing></div>, чтобы определить директиву в нашем HTML-коде.

Второе свойство scope используется для изменения области действия директивы. По умолчанию значение свойства scope равно false, что означает, что область действия этой директивы такая же, как и у ее родителя. Когда мы передаем ему объект, для этой директивы создается изолированная область действия, и любые данные, которые необходимо передать директиве родительским элементом, передаются через атрибуты HTML. Это то, что мы делаем в нашем коде, и атрибут, который мы используем post-args, который нормализуется в postArgs.

Свойство postArgs в объекте scope может принимать любое из следующих трех значений:

  1. =: Означает, что значение, переданное в атрибут, будет рассматриваться как объект.
  2. @: Означает, что значение, переданное в атрибут, будет рассматриваться как обычная строка.
  3. &: Значение, которое значение, переданное в атрибут, будет рассматриваться как функция.

Поскольку мы решили использовать значение =, любое значение, которое будет передано в атрибут post-args, будет рассматриваться как объект JSON, и мы могли бы использовать этот объект в качестве аргумента для извлечения сообщений.

Третье свойство, link  используется для определения функции, которая используется для управления DOM и определения API и функций, необходимых для этой директивы. Эта функция выполняет всю логику этой директивы.

Функция link принимает аргументы для объекта scope, HTML-элемента директивы и объекта для атрибутов, определенных в HTML-элементе директивы. В настоящее время мы передаем два аргумента $scope и $elem для объекта scope и элемента HTML соответственно.

Определим некоторую переменную в свойстве $scope, которую мы будем использовать для визуализации функции публикации записей в DOM.

Мы определили шесть свойств объекта $scope, к которым мы могли получить доступ в DOM. Этими свойствами являются:

  1. $posts: Массив для хранения объектов сообщений, которые будут возвращены сервером.
  2. $postHeaders: объект для хранения заголовков, которые будут возвращены сервером вместе с телом ответа. Мы будем использовать их для управления навигацией.
  3. $currentPage: целочисленная переменная, содержащая номер текущей страницы.
  4. $previousPage: переменная, содержащая номер предыдущей страницы.
  5. $nextPage: переменная, содержащая номер следующей страницы.
  6. $routeContext: для доступа к текущему пути с помощью службы $location.

Свойство postArgs, которое мы определили ранее для атрибутов HTML, уже будет доступно в объекте $scope внутри директивы.

Теперь мы готовы сделать запрос на сервер, используя службу Posts для извлечения сообщений. Но до этого мы должны учитывать аргументы, предоставленные пользователем как параметры URL, а также параметры, предоставленные атрибутом post-args. И для этой цели мы создадим функцию, которая использует службу $routeParams для извлечения URL-параметров и объединяет их с аргументами, предоставляемыми атрибутом post-args:

Метод prepareQueryArgs() в приведенном выше коде использует метод angular.merge(), который расширяет объект $scope.postArgs объектом $routeParams. Но прежде чем объединить эти два объекта, он сначала удаляет свойство id из объекта $routeParams, используя оператор delete. Это необходимо, так как мы будем использовать эту директиву в категориях и представлениях пользователей, и мы не хотим, чтобы идентификаторы категорий и пользователей ошибочно интерпретировались как идентификатор сообщения.

Подготовив аргументы запроса, мы, наконец, готовы сделать вызов на сервер и получить сообщения, и мы делаем это с помощью метода Posts.query(), который принимает два аргумента:

  1. Объект, содержащий аргументы для создания запроса.
  2. Функция обратного вызова, которая выполняется после завершения запроса.

Поэтому мы будем использовать функцию prepareQueryArgs() для подготовки объекта к аргументам запроса, а в функции обратного вызова мы устанавливаем значения определенных переменных в свойстве $scope:

Функция обратного вызова получает два аргумента для тела ответа и заголовков ответа. Они представлены аргументами data и headers соответственно.

Аргумент headers - это функция, которая возвращает сервер, содержащий заголовки ответа.

Остальной код довольно понятен, поскольку мы устанавливаем значение массива $scope.posts. Для установки значений переменных $scope.previousPage и $scope.nextPage мы используем свойство x-wp-totalpages в объекте postHeaders.

И теперь мы готовы предоставить эти данные в интерфейсе с помощью настраиваемого шаблона для нашей директивы.

Создание настраиваемого шаблона для директивы

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

Это свойство templateUrl в приведенном выше коде ссылается на файл с именем directive-post-listing.html в каталоге views. Поэтому создайте этот файл в папке views и вставьте следующий HTML-код:

Это очень простой HTML-код, представляющий одну запись в сообщении и постраничную публикацию. Я скопировал его из файла views/listing.html. Мы будем использовать некоторые директивы AngularJS, в том числе ng-repeat, ng-href, ng-src и ng-bind-html, чтобы отобразить данные, которые в настоящее время находятся в свойстве $scope директивы.

Измените код HTML следующим образом:

В приведенном выше коде используется директива ng-repeat для итерации массива $scope.posts. Любое свойство, которое определено в объекте $scope в объявлении директивы, доступно непосредственно в шаблоне. Следовательно, мы ссылаемся на массив $scope.posts непосредственно как posts в шаблоне.

Используя директиву ng-repeat, мы гарантируем, что контейнер article.post-entry будет повторяться для каждого сообщения в массиве posts, а каждое сообщение будет упоминаться как post во внутреннем цикле. Этот объект post содержит данные в формате JSON, возвращаемые сервером, содержащие такие свойства, как заголовок, почтовый идентификатор, постсодержание и ссылку на изображение, которое является дополнительным полем, добавленным плагином.

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

Для нумерации страниц замените предыдущий код следующим:

Сначала мы получаем доступ к свойству routeContext, который мы определили в нашем объявлении директивы, и добавим его параметром ?page= и используем значения nextPage и previousPage переменных для навигации вперед и назад между сообщениями. Мы также проверяем, не равна ли ссылка на следующую страницу или предыдущую страницу null, иначе мы добавим класс .disabled к кнопке, предоставленной Zurb Foundation.

Теперь, когда мы закончили эту директиву, пришло время ее протестировать. И мы делаем это, помещая тег <post-listing> </post-listing> в наш HTML, идеально прямо над тегом <footer></footer>. Это означает, что сообщение будет отображаться над нижним колонтитулом. Не беспокойтесь о форматировании и стилях, поскольку мы будем иметь дело с ними в следующей части серии.

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

Что дальше?

В текущей части серии о создании интерфейса с WP REST API и AngularJS мы создали специальную директиву AngularJS для функции публикации сообщений. Эта директива использует службу Posts,  которую мы создали в более ранней части серии. Директива также принимает пользовательский ввод в виде атрибута HTML и через параметры URL.

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

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.