使用Vue.js在WordPress中创建单页面应用SPA

8,817 阅读21分钟

吐槽一下,掘金好像并不能插入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…