Creating a Custom Directive for WordPress Post Listing on the Front End

Creating a Custom Directive for WordPress Post Listing on the Front End

在本系列的前一部分中,我們引導了 AngularJS 應用程序,為不同視圖配置了路由,并圍繞帖子、用戶和類別的路由構建了服務。使用這些服務,我們現在終于能夠從服務器獲取數據來為前端提供動力。

在本系列的這一部分中,我們將致力于為帖子列表功能構建自定義 AngularJS 指令。在本系列的當前部分中,我們將:

  • 介紹 AngularJS 指令以及為什么我們應該創建一個
  • 規劃帖子列表功能的指令及其所需的參數

  • 為帖子列表創建自定義 AngularJS 指令及其模板

所以讓我們首先介紹一下 AngularJS 指令以及為什么我們需要它們。

AngularJS 指令簡介

AngularJS 中的指令是一種修改 HTML 元素行為和重用可重復代碼塊的方法。它們可用于修改 HTML 元素及其子元素的結構,因此它們是引入自定義 UI 小部件的完美方式。

在分析本系列第一部分中的線框圖時,我們注意到帖子列表功能在三個視圖中使用,即:

  1. 發布列表
  2. 作者簡介

  3. 類別帖子列表

因此,我們可以創建一個自定義 AngularJS 指令,其中包含使用我們在本系列前面部分創建的服務來檢索帖子的業務邏輯,而不是編寫單獨的功能來列出這三個頁面上的帖子。除了業務邏輯之外,該指令還將包含在某些視圖上列出帖子的渲染邏輯。也在該指令中定義了帖子分頁和根據某些條件檢索帖子的功能。

因此,為帖子列表功能創建自定義 AngularJS 指令允許我們僅在一個位置定義該功能,這將使我們將來更容易擴展或修改此功能,而無需更改其中的代碼使用它的所有三個實例。

話雖如此,讓我們開始為帖子列表功能編寫自定義指令。

規劃帖子列表的自定義 AngularJS 指令

在我們開始編寫用于構建帖子列表功能指令的任何代碼之前,讓我們分析一下指令中所需的功能。

在最基本的層面上,我們需要一個可以在帖子列表、作者個人資料和類別頁面的視圖上使用的指令。這意味著我們將創建一個放置在 HTML 中的自定義 UI 小部件(或 DOM 標記),AngularJS 將根據我們為指令的特定實例提供的選項來處理其余的事情。

因此,我們將創建一個由以下標記標識的自定義 UI 小部件:

<post-listing></post-listing>

但是我們還需要這個指令是靈活的,即將參數作為輸入并采取相應的行動??紤]用戶個人資料頁面,我們只希望顯示屬于該特定用戶的帖子,或者類別頁面,其中將列出屬于該類別的帖子。這些參數可以通過以下兩種方式提供:

  1. 在 URL 中作為參數
  2. 直接將指令作為屬性值

在 URL 中提供參數似乎是 API 的本機,因為我們已經熟悉這樣做了。因此,用戶可以通過以下方式檢索屬于特定用戶的一組帖子:

https://127.0.0.1:8080/#/posts?author=1 

上述功能可以通過AngularJS提供的$routeParams服務來實現。我們可以在此處訪問用戶在 URL 中提供的參數。我們在本系列的前一部分中注冊路由時已經研究過它。

至于直接向指令提供參數作為屬性值,我們可以使用如下內容:

<post-listing post-args="{author=1}"></post-listing>

上面代碼片段中的 post-args 屬性采用參數來檢索一組特定的帖子,目前它采用作者 ID。此屬性可以采用任意數量的參數來檢索 /wp/v2/posts 路由支持的帖子。因此,如果我們要檢索由 ID 為 1 且屬于 ID 10 類別的用戶撰寫的一組帖子,我們可以執行如下操作:

<post-listing post-args="{author=1, filter[cat]=10}"></post-listing>

上述代碼中的 filter[cat] 參數用于檢索屬于某個類別的一組帖子。

分頁也是使用帖子列表頁面時的一個基本功能。該指令將處理后分頁,并且此功能將由服務器返回的 X-WP-Total 和 X-WP-TotalPages 標頭的值驅動與響應主體。因此,用戶將能夠在上一組帖子和下一組帖子之間來回導航。

確定了用于發布列表的自定義指令的實質內容后,我們現在已經有了相當堅實的基礎來開始編寫代碼。

為帖子列表構建自定義指令

為帖子列表功能構建指令包括兩個步驟:

  1. 創建用于檢索帖子和處理其他內容的業務邏輯。
  2. 為這些帖子創建一個渲染視圖以顯示在頁面上。

我們的自定義指令的業務邏輯將在指令聲明中處理。為了在 DOM 上呈現數據,我們將創建一個用于列出帖子的自定義模板。讓我們從指令聲明開始。

指令聲明

AngularJS 中的指令可以使用以下語法為模塊聲明:

/**  * Creating a custom directive for posts listing  */ quiescentApp.directive( 'postListing', [function() {     return {      }; }] ); 

在這里,我們使用模塊中可用的 .directive() 方法在模塊上聲明指令。該方法將指令的名稱作為第一個參數,并且該名稱與元素標簽的名稱密切相關。由于我們希望 HTML 元素為 <post-listing></post-listing>,因此我們提供了標簽名稱的駝峰式表示形式。您可以在官方文檔中了解有關 AngularJS 執行的規范化過程以匹配指令名稱的更多信息。

我們在上面的代碼中使用的用于聲明指令的符號稱為安全樣式的依賴注入。在這種表示法中,我們提供了一個依賴項數組作為指令所需的第二個參數。目前,我們尚未為自定義指令定義任何依賴項。但由于我們需要 Posts 服務來檢索帖子(我們在本系列的上一部分中創建的)以及本機 AngularJS 的 $routeParams 和 $location服務用于訪問URL參數和當前路徑,我們定義如下:

/**  * Creating a custom directive for posts listing  */ quiescentApp.directive( 'postListing', ['$routeParams', '$location', 'Posts', function( $routeParams, $location, Posts ) {     return {         restrict: 'E',         scope: {             postArgs: '='         },         link: function( $scope, $elem, $attr ) {                  }     }; }] ); 

然后,這些依賴項可供定義為數組最后一個元素的函數使用。該函數返回一個包含指令定義的對象。目前,我們在指令定義對象中有兩個屬性,即 restrict 和 link。

restrict 選項定義了我們在代碼中使用指令的方式,該選項可以有四個可能的值:

  1. A:用于將指令用作現有 HTML 元素的屬性。
  2. E:用于使用指令作為元素名稱。

  3. C:用于使用指令作為類名。

  4. M:用于將該指令用作 HTML 注釋。

restrict 選項也可以接受上述四個值的任意組合。

由于我們希望指令成為新元素 <post-listing></post-listing>,因此我們將限制選項設置為 E。如果我們要使用預先存在的 HTML 元素上的屬性來定義指令,那么我們可以將此選項設置為 A。在這種情況下,我們可以使用 在 HTML 代碼中定義該指令。

第二個 scope 屬性用于修改指令的范圍。默認情況下, scope 屬性的值為 false,這意味著指令的范圍與其父級的范圍相同。當我們向它傳遞一個對象時,會為該指令創建一個隔離的范圍,并且需要由其父級傳遞給該指令的任何數據都通過 HTML 屬性傳遞。這就是我們在代碼中所做的,我們使用的屬性是 post-args,它被標準化為 postArgs。

p>

scope 對象中的 postArgs 屬性可以接受以下三個值中的任意一個:

  1. =:表示傳遞給屬性的值將被視為對象。
  2. @:這意味著傳遞到屬性的值將被視為純字符串。

  3. &:表示傳遞給屬性的值將被視為函數。

由于我們選擇使用 = 值,因此傳遞到 post-args 屬性的任何值都將被視為 JSON 對象,我們可以使用該對象作為檢索帖子的參數。

第三個屬性 link 用于定義一個函數,該函數用于操作 DOM 并定義該指令所需的 API 和函數。該函數是處理指令所有邏輯的地方。

link 函數接受作用域對象、指令的 HTML 元素以及指令的 HTML 元素上定義的屬性的對象的參數。目前,我們分別為范圍對象和 HTML 元素傳遞兩個參數 $scope 和 $elem 。

讓我們在 $scope 屬性上定義一些變量,我們將使用該變量在 DOM 上呈現帖子列表功能。

/**  * Creating a custom directive for posts listing  */ quiescentApp.directive( 'postListing', ['$routeParams', '$location', 'Posts', function( $routeParams, $location, Posts ) {     return {         restrict: 'E',         scope: {             postArgs: '='         },         link: function( $scope, $elem, $attr ) {             // defining variables on the $scope object             $scope.posts = [];             $scope.postHeaders = {};             $scope.currentPage = $routeParams.page ? Math.abs( $routeParams.page ) : 1;             $scope.nextPage = null;             $scope.previousPage = null;             $scope.routeContext = $location.path();         }     }; }] ); 

因此,我們在 $scope 對象上定義了六個屬性,我們可以在 DOM 中訪問它們。這些屬性是:

  1. $posts:保存服務器返回的 post 對象的數組。
  2. $postHeaders:用于保存服務器將與響應正文一起返回的標頭的對象。我們將使用它們來處理導航。

  3. $currentPage:保存當前頁碼的整型變量。

  4. $previousPage:保存上一頁頁碼的變量。

  5. $nextPage:保存下一頁編號的變量。

  6. $routeContext:用于使用 $location 服務訪問當前路徑。

我們之前為 HTML 屬性定義的 postArgs 屬性已在指令內的 $scope 對象上可用。

現在我們準備使用 Posts 服務向服務器發出請求以檢索帖子。但在此之前,我們必須考慮用戶作為 URL 參數提供的參數以及 post-args 屬性中提供的參數。為此,我們將創建一個函數,使用 $routeParams 服務來提取 URL 參數,并將它們與通過 post-args 屬性提供的參數合并: p>

/**  * Creating a custom directive for posts listing  */ quiescentApp.directive( 'postListing', ['$routeParams', '$location', 'Posts', function( $routeParams, $location, Posts ) {     return {         restrict: 'E',         scope: {             postArgs: '='         },         link: function( $scope, $elem, $attr ) {             // defining variables on the $scope object             $scope.posts = [];             $scope.postHeaders = {};             $scope.currentPage = $routeParams.page ? Math.abs( $routeParams.page ) : 1;             $scope.nextPage = null;             $scope.previousPage = null;             $scope.routeContext = $location.path();                          // preparing query arguments             var prepareQueryArgs = function() {                 var tempParams = $routeParams;                 delete tempParams.id;                 return angular.merge( {}, $scope.postArgs, tempParams );             };         }     }; }] ); 

上述代碼中的 prepareQueryArgs() 方法使用 angular.merge() 方法,該方法擴展了 $scope。 postArgs 對象與 $routeParams 對象。但在合并這兩個對象之前,它首先使用 delete 運算符從 $routeParams 對象中刪除 id 屬性。這是必要的,因為我們將在類別和用戶視圖上使用此指令,并且我們不希望類別和用戶 ID 被錯誤地解釋為帖子 ID。

準備好查詢參數后,我們終于準備好調用服務器并檢索帖子,我們使用 Posts.query() 方法來執行此操作,該方法采用兩個參數:

  1. 包含用于進行查詢的參數的對象。
  2. 查詢完成后執行的回調函數

因此,我們將使用 prepareQueryArgs() 函數為查詢參數準備一個對象,并在回調函數中設置 上某些變量的值$scope 屬性:

// make the request and query posts Posts.query( prepareQueryArgs(), function( data, headers ) {     $scope.posts = data;     $scope.postHeaders = headers();     $scope.previousPage = ( ( $scope.currentPage + 1 ) &gt; $scope.postHeaders['x-wp-totalpages'] ) ? null : ( $scope.currentPage + 1 );     $scope.nextPage = ( ( $scope.currentPage - 1 ) &gt; 0 ) ? ( $scope.currentPage - 1 ) : null; }); 

回調函數獲取響應正文和響應標頭的兩個參數。這些分別由 data 和 headers 參數表示。

headers 參數是一個函數,它返回一個包含服務器響應標頭的對象。

剩下的代碼非常不言自明,因為我們正在設置 $scope.posts 數組的值。為了設置 $scope.previousPage 和 $scope.nextPage 變量的值,我們使用 x-wp-totalpages 屬性postHeaders 對象。

現在我們準備使用指令的自定義模板在前端渲染這些數據。

為指令創建自定義模板

為了使我們的指令發揮作用,我們需要做的最后一件事是為帖子列表制作一個單獨的模板并將其鏈接到指令。為此,我們需要修改指令聲明并包含 templateUrl 屬性,如下所示:

/**  * Creating a custom directive for posts listing  */ quiescentApp.directive( 'postListing', ['$routeParams', '$location', 'Posts', function( $routeParams, $location, Posts ) {     return {         restrict: 'E',         scope: {             postArgs: '='         },         templateUrl: 'views/directive-post-listing.html',         link: function( $scope, $elem, $attr ) {                  }     }; }] ); 

上面代碼中的 templateUrl 屬性引用了 views 目錄中名為 directive-post-listing.html 的文件。因此,在 views 文件夾中創建此文件并粘貼以下 HTML 代碼:

<!-- post listing starts --> <article class="post-entry"><h2 class="post-title"><a href="post-single.html">Good design is a lot like clear thinking made visual.</a></h2>     <figure class="post-thumbnail">         @@##@@     </figure><p class="post-meta">         By <a href="author.html">Bilal Shahid</a> in <a href="category.html">Quotes</a>     </p>     <div class="post-content">         <p>Created days forth. Dominion. Subdue very hath spirit us sixth fish creepeth also. First meat one forth above. You'll Fill for. Can't evening one lights won't. Great of make firmament image. Life his beginning blessed lesser meat spirit blessed seas created green great beginning can't doesn't void moving. Subdue evening make spirit lesser greater all living green firmament winged saw tree one divide wherein divided shall dry very lesser saw, earth the. Light their the.</p>     </div> </article><!-- post listing ends --><!-- pagination links start --><div class="post-pagination">     <a href="#" class="button">Older Posts</a>     <a href="#" class="button">Newer Posts</a> </div>		 <!-- pagination links end --> 

這是非常基本的 HTML 代碼,表示單個帖子條目和帖子分頁。我已從 views/listing.html 文件中復制了它。我們將使用一些 AngularJS 指令,包括 ng-repeat、ng-href、ng-src 和 ng -bind-html,顯示當前駐留在指令的 $scope 屬性中的數據。

將 HTML 代碼修改為以下內容:

<!-- post listing starts --> <article class="post-entry" ng-repeat="post in posts"><h2 class="post-title"><a ng-href="#/posts/{{post.slug}}">{{post.title.rendered}}</a></h2>     <figure class="post-thumbnail" ng-show="post.quiescent_featured_image">         @@##@@     </figure><p class="post-meta">         By <a ng-href="#/users/{{post.author}}">{{post.quiescent_author_name}}</a>          in <a ng-href="#/categories/{{category.term_id}}" ng-repeat="category in post.quiescent_categories">{{category.name}}{{$last ? '' : ',?'}}</a>     </p>     <div class="post-content" ng-bind-html="post.excerpt.rendered"></div>     </article><!-- post listing ends -->

上面的代碼使用 ng-repeat 指令來迭代 $scope.posts 數組。指令聲明中 $scope 對象上定義的任何屬性都可以直接在模板中使用。因此,我們在模板中將 $scope.posts 數組直接引用為 posts 。

通過使用 ng-repeat 指令,我們確保 article.post-entry 容器將在 中的每個帖子中重復posts 數組,每個帖子在內循環中被稱為 post 。這個 post 對象包含服務器返回的 JSON 格式的數據,包含帖子標題、帖子 ID、帖子內容和特色圖像鏈接等屬性,這是同伴添加的附加字段插件。

在下一步中,我們將帖子標題、帖子鏈接和特色圖像鏈接等值替換為 post 對象中的屬性。

對于分頁,將之前的代碼替換為以下代碼:

<!-- pagination links start --> <div class="post-pagination">     <a ng-href="#{{routeContext}}?page={{nextPage}}" class="button" ng-class="{'disabled': !nextPage}">Newer Posts</a>     <a ng-href="#{{routeContext}}?page={{previousPage}}" class="button" ng-class="{'disabled': !previousPage}">Older Posts</a> </div>		 <!-- pagination links end --> 

我們首先訪問我們在指令聲明中定義的 routeContext 屬性,并使用 ?page= 參數作為后綴,并使用 nextPage 和 previousPage 變量用于在帖子之間來回導航。我們還檢查下一頁或上一頁鏈接是否不是 null,否則我們將 .disabled 類添加到 Zurb Foundation 提供的按鈕。

現在我們已經完成了該指令,是時候對其進行測試了。我們通過在 HTML 中放置一個 <post-listing></post-listing> 標簽來實現這一點,最好位于

的上方標簽。這樣做意味著帖子列表將出現在頁腳上方。不要擔心格式和樣式,我們將在本系列的下一部分中處理它們。

這就是為帖子列表功能創建自定義 AngularJS 指令的過程。

接下來會發生什么?

在有關使用 WP REST API 和 AngularJS 創建前端的系列的當前部分中,我們為帖子列表功能構建了一個自定義 AngularJS 指令。該指令使用我們在本系列前面部分創建的 Posts 服務。該指令還以 HTML 屬性和 URL 參數的形式獲取用戶輸入。

在本系列的最后部分,我們將開始研究項目的最后一部分,即帖子、用戶和類別的控制器及其各自的模板。

Creating a Custom Directive for WordPress Post Listing on the Front EndCreating a Custom Directive for WordPress Post Listing on the Front End

? 版權聲明
THE END
喜歡就支持一下吧
點贊9 分享