使用Vue.js在WordPress中建立單頁面應用SPA

xodyhu發表於2019-02-11

吐槽一下,掘金好像並不能插入gist的程式碼框 效果有點打折扣

部落格原文地址裡有gist程式碼:
使用Vue.js在WordPress中建立單頁面應用SPA

英文原文地址:premium.wpmudev.org/blog/creati…


在這篇文章裡,我將向你介紹如何使用Vue.js在WordPress中建立單頁面應用SPA(single page application):用WordPress做後端服務提供資料 ,用Vue.js獲取資料做前端渲染。

我們將用到WordPress的REST api (對外提供標準的RESTFul介面)和Vue.js (一個漸進式 JavaScript 框架)。如果你沒有用過Vue.js或者其他JavaScript框架,這會是一個很好的上手機會。

溫馨提示:本文面向有一定經驗的WordPress開發者,我假設你熟悉PHP, JavaScript和WordPress REST API。 如果你在這些方面是新手,推薦你先閱讀下面的教程:

我們將會用到很多Vue.js的功能,比如單檔案元件事件處理計算屬性,生命週期,還會用到Axios庫和WordPress REST API進行互動。如果你不熟悉也沒關係,可以先學習下面的教程來快速上手:

雖然Vue.js應用完全可以用ES5語法來寫,但是我將用到一些ES6和ES7的新特性,如果你想快速學習一下ES6的語法,可以看看下面的教程:

選擇Vue.js或其他JavaScript框架主要看你自己的需求和技術偏好,本文的目標是用實際案例帶你探索一下把WordPress和前端單頁面應用結合起來的可能性。現在,讓我們開始吧!

概述:如何在WordPress中開發Vue單頁面應用

我已經在WordPress中利用Vue.js和Twenty Seventeen 主題的子主題(child theme)開發了一個簡單的帶搜尋功能的單頁面應用,程式碼共享在GitHub 上,你可以下載下來,一邊閱讀本文一邊檢視程式碼。

單頁面應用(SPA)可以掛載在任意一個Wordpress頁面(page)上,只要這個WordPress頁面指定了特定的自定義頁面模板(Custom Page Templates),這個自定義頁面模板的主要作用就是提供一個DOM元素,用作vue例項的掛載點。

Integrating a Vue app in WordPress
用自定義頁面模板將Vue.js與 WordPress 結合起來

我們的這個SPA採用的是一種混合架構,伺服器端的程式WordPress既為其提供後端服務,也為其提供前端渲染(如佈局和主題等),前端頁面的部分資料是通過瀏覽器端的應用(Vue.js)來渲染的。這和常見的SPA前後端分離架構不同,通常伺服器端程式僅負責提供內容(通過API響應),並不生成頁面內容的HTML。

使用Vue.js快速搜尋WordPress的日誌

在WordPress的搜尋場景中,每次搜尋都會對伺服器的發起一次請求,導致網頁重新載入。即使你只想簡單快速的搜尋一下WordPress的日誌標題也可能等半天(因為網路延時),這使WordPress的搜尋體驗變得很差。

SPA單頁面應用,只有一個完整的頁面,它在載入頁面時,不會載入整個頁面,而是隻更新某個指定的容器中內容。使用SPA,可以讓使用者在進行搜尋時動態更新網頁而不是重新載入。這使得使用者體驗非常愉悅。你可以通過的示例直觀感受一下

codepen.io/karannagupt…

具備搜尋功能的Vue單頁面應用的元件剖析 {#vue-spa-overview}

在深入研究程式碼之前,讓我們瞭解一下這個單頁面應用的內部工作原理。下圖解釋了這個搜尋App中的元件互動流程。

vue搜尋spa內部結構
Vue單頁面搜尋應用的內部邏輯

讓我們總覽一下各個元件的作用:

  • AppNavigation用於為Vue Router設定瀏覽器訪問路徑,並將AppQuickSearchAppCustomSearch元件和路徑對映起來。
  • AppQuickSearch和AppCustomSearch是兩個完全相互獨立的父元件,每個元件都有各自的資料,方法和屬性,它們都有兩個子元件AppFilterSwitches和AppGetPosts。
  • AppFilterSwitches用來控制核取方塊或按鈕的開關切換。
  • AppGetPosts會從WordPress REST API獲取資料,並通過關鍵字和過濾條件對結果進行過濾,然後呼叫AppDisplayPost元件來展示篩選結果。
  • AppDisplayPost裡定義了搜尋結果的展示樣式和HTML。

以上這些都是在WordPress的某個指定了自定義頁面模板的頁面中進行的。

使用Vue單檔案元件

你可能已經看到過許多使用Vue.component方式來定義全域性元件的示例。在本文中,我將使用更強大的Vue單檔案元件

單檔案元件具有許多優點,比如能提供預編譯的JavaScript ,完整語法高亮,CommonJS 模組以及元件作用域的CSS等。通過vue單檔案元件可以對前端專案進行模組化開發,並且使程式碼管理更清晰明瞭。

現在你已經對本文涉及的技術和原理有了一個大致的瞭解,接下來就讓我們開始開發吧。

使用Vue CLI設定本地開發工作環境

開發Vue單檔案元件將會需要使用一系列工具,如Vue Loader,Webpack,Babel等。但是,不要害怕,我會做一些必要的簡化,省略處理配置檔案的步驟。

使用Vue CLI 可以快速構建一個Vue應用程式。Vue CLI 是一個基於 Vue.js 進行快速開發的完整系統,它確保了各種構建工具能夠基於智慧的預設配置即可平穩銜接,這樣你可以專注在撰寫應用上,而不必花好幾天去糾結配置的問題。所以讓我們先設定一下Vue CLI 。

第1步:安裝Node.js.

要使用Vue CLI,你需要在系統上安裝Node.js(node版本大於8.x,npm版本大於3.x)。您可以從Node.js下載頁面下載適用於您的平臺的安裝程式。安裝完成後,請測試以下命令是否生效:

node --version
npm --version

第2步:安裝Vue-CLI

接下來,開啟系統的終端 ,執行npm install -g vue-cli命令全域性安裝Vue-CLI(2.x)。完成後,執行vue --version命令進行測試。

設定vue cli 2
設定Vue-CLI(2.x)以建立Vue應用程式

在上面的圖片中,你會發現,我還用npm install -g eslint全域性安裝了ESLint全域性範圍內與 。這是因為我使用Visual Studio Code和相關外掛來檢查JavaScript程式碼的規範化。你可以使用任何你喜愛的程式碼編輯器,但強烈建議你配置一個JavaScript的程式碼檢查工具,比如( ESLint, JSHint , StandardJS)。

完成基本設定後,讓我們使用Vue CLI在WordPress的主題資料夾中建立一個專案。

使用Vue CLI建立Vue專案

我使用了vue提供的官方模板webpack-simple 。當然,你可以根據你的需求使用更復雜的預設模板或者手動選擇。

Vue CLI使用Webpack來配置Vue專案,並提供了開發伺服器和其他現代構建工具。這為我們提供了非常便捷的開發流程。除此之外,它還允許我們在開發期間使用下一代JavaScript語法(ES6 / ES7)編寫程式碼,在釋出時編譯成對瀏覽器相容性更好的ES5語法的JavaScript包。

第1步:在WordPress中設定Vue應用程式

要建立一個vue專案,首先在終端進入到一個WordPress的主題目錄或子主題目錄(這個主題要在WordPress後臺啟用啟用)。

導航到wordpress主題
進入到WordPress主題目錄

第2步:使用Webpack-Simple模板建立Vue應用程式

接下來,執行命令vue init webpack-simple project-name ,把project-name 替換成你的專案名字 (在我的示例中為spa),然後按照螢幕上的說明操作。這將在<project-name>目錄中建立Vue專案,其中包含現代構建工具的配置。

注意:如果你下載使用我的vuetwentyseventeen子主題,請跳過vue init此步。資料夾中已經包含了spa這個vue專案。

使用vue init和webpack模板的vue應用程式
使用vue init和Webpack模板建立Vue應用程式

第3步:安裝開發依賴項

在新建立的專案資料夾中你會看到到一個名為package.json的檔案。它基本上列出了所有專案所需的開發工具和依賴包。請執行以下命令來安裝這些所需的工具和庫:

cd spa
npm install

NPM將自動把所有依賴包下載並安裝到node_modules的資料夾中。

安裝dev依賴項
使用NPM安裝開發依賴項

請注意,不要在實際執行的線上WordPress中部署任何這些下載的依賴檔案。它們僅僅是在開發階段才需要。

第4步:在WordPress中啟動Webpack Dev Server

雖然看起來很奇怪,但你需要在執行WordPress本地服務(如XAMP,WAMP,VVV等)的同時,再執行在上一步中自動安裝的Webpack開發伺服器,使它們一同工作。

原因是這樣的,我們的單頁面應用實際上是獨立於後端的一個純靜態應用,在開發階段我們編寫的是vue單檔案元件,需要由Webpack伺服器來提供自動編譯和熱更新。只有在開發完成後,我們才能向WordPress提供最終編譯好的JavaScript包。

要啟動開發伺服器,請從Vue專案資料夾執行命令npm run dev 。然後,你將看到在瀏覽器中自動開啟localhost:8080,也就是vue的初始化專案。

執行webpack開發伺服器
執行Webpack開發伺服器

Vue.js的編譯打包

如果你在瀏覽器中檢視網頁原始碼,您會發現該頁面只包含一個JavaScript檔案 – build.js 。這是因為當你執行開發伺服器時,Webpack會自動編譯 ,使用不同的loaders處理專案的所有依賴檔案,最後打包為一個瀏覽器可識別的JavaScript檔案。

但請注意,該檔案實際上並沒有儲存在於您的系統上,而是由Node和Webpack在執行時動態生成的。

在記憶體中由webpack生成的javascript包
由Webpack在執行時動態生成的JavaScript包

要生成可以釋出的JavaScript檔案,你必須執行npm run build ,我們將在稍後階段提到。

現在我們有了一個功能齊全的Vue應用,是由安裝在WordPress主題資料夾內的Webpack開發伺服器來提供服務的。但是,現階段除了物理安裝路徑它與WordPress沒有一毛錢關係。那麼,讓我們來看看如何將Vue應用與WordPress進行整合。

將Vue 與WordPress整合

將Vue應用與WordPress整合基本上需要三個條件:

  • WordPress中的DOM元素,用做Vue例項的掛載點
  • 在WordPress的排隊引用機制(Enqueue Scripts)中加入Vue的編譯檔案(如build.js)
  • 在Vue中指定WordPress的DOM元素

在WordPress中為 Vue提供DOM元素

你可能希望將Vue例項掛在單個或多個WordPress頁面上,或者有條件地掛載。不管那種方式,Vue所需都是一個WordPress頁面上的DOM元素。

為此,你可以使用WordPress的Template Hierarchy(模板層次)來確定需要編輯哪個模板檔案。在我的示例中,我希望這個Vue SPA出現在任意一個指定了自定義頁面模板(Custom Page Template)的WordPress頁面上。你也可以使用主題的頁面模板來指定特定頁面,這取決於你的需求。

在我的示例子主題中,templates/vue-search-app-template.php 就是一個自定義頁面模板,它為Vue提供了DOM元素#wp-vue-app 。

在WordPress中註冊Vue應用程式

要讓WordPress能感知到Vue應用,你必須在WordPress中為Vue進行註冊/排隊 ( register/enqueue) 。因為在開發期間修改程式碼是很頻繁的,每次修改完vue程式碼之後都手動構建一次是很不方便的,為了方便,我們可以利用webpack的動態構建功能。

執行Webpack開發伺服器之後,我們就可以使用路徑http://localhost:8080/dist/build.js在WordPress中註冊Vue例項。

vue程式碼修改儲存後,Webpack開發伺服器就會自動編譯並自動更新頁面 。

在開發指令碼中註冊動態構建
在開發期間在WordPress中註冊動態構建路徑

這就是為什麼在開發過程中我們必須同時執行WordPress的本地伺服器和Webpack開發伺服器的原因。開發完成後,你必須把路徑修改成通過npm run build生成的檔案路徑。

在開發指令碼之後註冊構建
在開發之後在WordPress中註冊實際的構建檔案

另請注意,除了最終的編譯檔案之外,Vue專案資料夾中的所有檔案都不需要隨WordPress主題一起釋出。這些都僅在開發期間需要,並且每次修改後都必須進行重新編譯打包。

在我的示例主題中,我在includes/enqueue-scripts.php註冊了Vue編譯後的檔案地址。

在Vue中指定WordPress中的DOM掛載點

最後,要在WordPress中載入Vue應用程式,所需的只是告訴Vue要掛載的位置。要在vue中指定WordPress DOM元素有兩種方法,你可以在main.js使用el,或者,也可以使用$mount方法。

在我的示例中,我將vue應用掛載在自定義頁面模板的DIV容器#wp-vue-app 中。

在vue中指定安裝點
使用’el’在Vue中指定掛載點

就這樣,一個Vue初始專案將可以在WordPress中顯示了。

在wordpress中注入vue
在WordPress中渲染Vue應用程式

看起來不錯,Vue應用已經成功注入WordPress,你現在可以使用Vue構建幾乎任何你想要的東西。那麼,讓我們深入瞭解一下的用Vue來構建搜尋應用的內容。

在WordPress中構建單頁面搜尋應用

如果你再回頭看下 本文開頭流程圖 ,您就能更好的理解下面的搜尋應用呈現的最終效果:

vue搜尋應用程式wordpress
在WordPress中構建Vue搜尋應用程式

專案資料夾的結構

我用Vue示例專案作為基礎,從中刪除了spa/index.htmlsrc/assets ,得到了以下資料夾結構:

wordpress中的vue資料夾結構
WordPress中Vue搜尋應用程式的資料夾結構

子主題的includes資料夾裡的各個PHP檔案定義了相應的回撥函式,這樣我可以只使用一個functions.php檔案來設定<a rel="noreferrer noopener" href="https://developer.wordpress.org/reference/hooks/" target="_blank">WordPress Hooks</a> (鉤子函式)。我更喜歡這種方法將所有內容放在一個functions.php檔案中。

安裝ESLint和ESNext功能(可選)

如果你打算使用ESLint(我強烈推薦)或ESNext功能(如Async / Await),你還需要為專案新增一些額外的依賴包。

為WordPress和Vue配置ESLint

為了配置ESLint,我安裝了eslint-plugin-vue和wodrdpress的程式碼規範eslint-config-wordpress。先停止開發伺服器(Ctrl + C),然後從Vue專案資料夾中執行以下命令:

npm install --save-dev eslint eslint-plugin-vue複製程式碼
npm install --save-dev eslint-config-wordpress複製程式碼

接下來,將以下內容新增到.eslintrc.json檔案中:
“extends”:[“eslint:recommended”,“wordpress”,“plugin:vue / recommended”]

這將為WordPress設定JavaScript程式碼規範 ,並設定vue官方推薦的eslint預設規則。配合VS Code這樣的程式碼編輯器,不僅可以很大程度地避免基本語法錯誤,也保證了程式碼的可讀性。

為vue wordpress配置eslint
在Visual Studio程式碼中使用ESLint捕獲錯誤

設定Babel以使用Async / Await

Babel設定超出了本文的範圍,用以下方法基本上可以讓你在Vue專案中使用ES7 的Async / Await語法。執行以下命令新增babel-preset-vue-app 即可:

npm install --save-dev babel-preset-vue-app

然後,在Vue專案中的.babelrc檔案中新增預設(presets):
"presets": [["env", { "modules": false }], "stage-3", "vue-app"]

完成後,不要忘記使用npm run dev啟動開發伺服器。我提供的示例子主題Vue child theme已經為你配置好了所有這些,因此你只需要通過在spa目錄中執行npm install來安裝即可。

從vue訪問WordPress資料

Vue是在瀏覽器中執行的JavaScript,因此,它無法訪問WordPress中的任何資料。要使WordPress資料可用於Vue應用程式,您必須使用wordpress的wp_localize_script 函式。

我在子主題vuetwentyseventeenincludes/enqueue-scripts.php中完成了這個配置。

上面gist裡的註釋已經很明瞭,所以我在這裡解釋一下需要提供給Vue應用程式的資料:

  • wpData.template_directory_uri – 用來構建主題資料夾中靜態檔案的路徑
  • wpData.rest_url – 用來獲取WP資料的 REST API地址
  • wpData.app_path – 用於執行SPA的 WordPress頁面的URL地址
  • wpData.post_categories – wp的目錄,用於過濾條件的核取方塊

有了這些,我們終於可以開始開發vue單頁搜尋應用的單檔案元件了。

使用Vue單檔案元件構建單頁面搜尋應用

參照之前的元件架構,我開發的第一個元件是AppDisplayComponent。讓我們將從最基本的功能開始,這個元件僅顯示帖子標題,使用的是JavaScript原生的Fetch API和WordPress的日誌資源Api (Posts resource –  /wp/v2/posts)。

AppDisplayPost元件的基本版本

入門的基本元件
AppDisplayPost元件的簡單版本

接下來,我刪除了App.vue裡原有的示例內容,並用下面的方式呼叫AppDisplayPost元件用來在WordPress頁面上呈現日誌,如下所示:

app.vue元件的初始版本
App.vue來裡的AppDisplayPost元件

當然,並不是所有東西都能一次成功,這就是Chrome外掛Vue DevTools發揮作用的時候了。我建議你也安裝一個,它可以使用友好的介面進行Vue應用的除錯和檢查,而不是用很土的辦法所有內容都輸出到瀏覽器控制檯。

使用vue devtools進行除錯
使用Vue Devtools除錯Vue應用

我還建議你使用Postman之類的API工具與WP REST API進行互動。這可以節省你很多時間,並且資料展示也會更清晰,讓你更容易檢視API響應值:

休息客戶郵遞員與wordpress休息api互動
使用Postman之類的REST客戶端與WordPress REST API進行互動

第一次除錯在Vue應用中渲染WordPress日誌確實花了我一些時間,但利用Vue DevTools和Postman進行了幾輪嘗試之後就漸入佳境了,這讓我感覺不錯。我還決定對WordPRESS的API預設響應進行擴充套件以新增自定義內容。

擴充套件WordPress REST API的自定義內容

WordPress REST API的預設響應非常全面,但它很可能無法滿足你的所有需求。

例如,你可能希望顯示作者姓名,評論和日誌縮圖(特色影像)等資訊。如果你用Postman對日誌資源發起 GET請求 ,你會注意到這些資訊(作者、評論等)在預設響應中是不能直接使用的,需要根據響應裡得到的url發起二次請求。

當然,你可以通過一個簡單的方法來獲取更多資訊,將_embed=true引數新增到wp/v2/posts地址後面再發起api請求 。使用_embed,API將在響應中自動展開所有標記為embeddable: true的欄位。

對於我的Vue 單頁搜尋應用程式,我決定擴充套件API的響應,並新增以下自定義內容:

延伸wordpress rest api
擴充套件WordPress REST API的預設響應

如果你看一下我的子主題中AppDisplayPost元件,你會注意到我使用到的欄位vue_meta並不是API預設響應的內容。它是通過子主題中includes/extend-api.php檔案register_rest_field函式新增的,其中的程式碼非常簡單。如果你想要了解更多有關擴充套件API響應的知識,請檢視REST API HandbookModifying Reponses`部分。

接下來,我建立了一個AppGetPosts單檔案元件,把獲取日誌的程式碼邏輯移動到其中,AppDisplayPost元件只用來顯示日誌。

AppGetPosts元件從REST API中獲取資料

把獲取日誌的程式碼分離出去,意味著要通過props將資料傳遞給AppDisplayPosts元件 。

然後,在AppGetPosts中我為獲取到的每篇日誌的呼叫了AppDisplayPost 元件。

我決定使用Axios而不是原生的Fetch API來請求WordPress REST API。你也可以選擇使用jQuery (已經包含在WordPress中)來進行AJAX呼叫。

注意:要使用Axios,你必須通過在Vue專案資料夾中執行npm install axios進行生產環境下的安裝 。

用WordPress REST API獲取僅需欄位

我最近發現可以使用_fields引數從API響應中獲取僅需的欄位。這會有效減少api的網路傳輸負載,尤其是當api的JSON響應不出現的日誌內容時。要達到這個效果,只需將_fields與逗號分隔的欄位名稱一起新增到api的url後面即可,如下圖

檢索特定欄位休息api
使用_fields引數有選擇地獲取api響應中的欄位

WordPress 的REST API手冊中還沒有加入_fields引數的用法,因此你可能需要密切關注下手冊。

從WordPress REST API獲取所有帖子

目前,無法通過WordPress REST API一次性獲取所有日誌。所以,你必須向API迴圈發出多個請求,直到獲取到需要的所有資料為止。

我使用了分頁引數 per_page=100和wordpress的http標頭欄位X-WP-Total(提供了集合中的記錄總數)來計算總共要發起幾次API請求。per_page引數目前上限為100條記錄,這就是為什麼我們需要在超過100個日誌時向API發出多個請求。實現方法請看下面的gist中AppGetPosts元件的get_posts函式:

上面的gist中, get_posts 函式會在元件掛載後自動呼叫. 我用了ES7 的Async/Await 寫法將該函式定義為非同步函式(aynchronous function )。

你會注意到第一個Axios請求是await 的寫法-
const response = await axios(...) 。這是為了在第一次請求成功之前阻止後續程式碼的執行。這樣做是為了獲取x-wp-total來計算的API請求次數。

第二個await用法是在最後,在渲染資料前用 Promise.all確保所有Promises都成功執行。當然,你也可以在資料載入完成後就渲染資料,兩種用法都在下面的gist裡列出了:

當所需資料載入完成後,我在計算屬性中新增了搜尋關鍵字和相應的搜尋邏輯。在下面的gist中,你可以看到我是如何用 FilteredResults 來過濾 wpPosts 資料並呼叫 AppDisplayPost元件來顯示結果的。

AppQuickSearch和AppFilterSwitches元件

現在AppGetPosts可以很好地工作了,能夠處理資料獲取和日誌搜尋,然後我將使用者輸入框移動到父元件AppQuickSearch中,並使用props傳遞資料。

我建立了一個新的子元件AppFilterSwitches 用來顯示條件核取方塊(wp目錄列表,資料來源是WordPress的區域性物件 wpData),這個子元件會觸發(emits)一個自定義事件onFilterToggle ,AppQuickSearch做為父元件必須去偵聽這個事件。

最後,所有元件都合併到AppQuickSearch

最後,執行npm run build生成最終的編譯檔案。

生成最終應用構建
使用npm run build生成最終構建

如果你走到這一步了,你應該能很輕鬆的探索這個vue應用的其餘部分。最終版本的元件確實有很多,但它們建立在你剛看到的所有內容之上的。

探索路由和保持活動的元件

雖然我們的快速搜尋單頁應用到此就可以結束了,但是為了演示一下vue的路由機制(Vue routing)和元件的重複利用,我又新增了另一個元件AppCustomSearch

你可以在spa/src/app-routes.js找到路由功能,它提供兩個導航連結AppQuickSearch , AppCustomSearch,並提供了導航連結和元件之間的對映關係。Vue Router的內容超出了本文的範圍,如果你想在WordPress頁面上使用Vue路由,請記住Vue將使用`#`來模擬一個完整的 URL,這樣當 URL 改變時,頁面不會重新載入。如果你嘗試去掉url裡的#直接訪問在app-routers.js裡定義的路由,那麼這個地址會被WordPress REST API接管,因為WordPress api裡並沒有這個地址,所以最終將找不到頁面並返回404。

App.vue檔案是總元件,裡面呼叫了AppNavigationrouter-view元件。你會注意到router-view被包keep-alive 元件中間, 這是因為使用_keep-alive_元件可以快取非活動元件,以便保留元件狀態,避免在AppQuickSearchAppCustomSearch之間切換元件時重新渲染 。

就這些了!

總結

希望這篇文章對你有用。你可以在這裡下載這個子主題的檔案 ,當作一個練手專案來提高你的WordPress和JavaScript技能。


掘金好像不能插入gist,完整版的在這裡:使用Vue.js在WordPress中建立單頁面應用SPA

原文地址:premium.wpmudev.org/blog/creati…

相關文章