内容简介:使用 Vue.js 2.0 开发单页应用
早在去年9月份,流行的 JavaScript 框架 Vue.js 就发布了 V2 版本,从那时起,我就一直很想尝试一下,看看它是如何工作的。作为一个非常熟悉 Angular 和 React 的人,我很期待看到他们与 Vue 之间的相似之处和差异。
Vue.js 2.0 运行时有优秀的性能统计数据,相对较小的有效负载(通过压缩和gzip,Vue 打包运行时的版本仅有16kb),除此之外还更新配套库 vue-router 和 vuex(Vue 的状态管理库)。仅仅在一篇文章中很难覆盖相关的知识,但请留意后续的文章,我们将更深入地研究一些与核心框架很好地结合的库。
来自其他库的启发
在学习本教程的过程中,您会看到 Vue 的许多功能明显受其他框架的启发。这是件好事;看到新框架可以从其他框架中获取一些想法,并对其进行改进是非常好的。特别是,你会看到 Vue 的模板非常接近 Angular ,但其组件和组件生命周期方法更接近 React(和 Angular 2)。
其中一个例子是,与 React 以及现代的 JavaScript 框架非常相似, Vue 使用了虚拟 DOM 来提高渲染效率。Vue 使用了一个较为流行的虚拟 DOM 库 snabbdom 的一个分支。Vue 网站包括有关其虚拟 DOM 渲染的文档介绍,但作为一个用户,你需要知道的是,Vue 渲染速度非常快(事实上,它在许多情况下比 React 更好),也就是说,你可以放心地在一个可靠的平台上构建。
组件,组件,组件
与其他框架类似,Vue的核心构建块是组件。你的应用程序应该是一系列相互关联构建的组件,以生成最终的应用程序。Vue.js 进一步建议(虽然不强制)你在单独 .vue
文件中定义组件,然后可以通过构建 工具 来解析(我们稍后会介绍)。考虑到本文的目的是充分探索 Vue 以及使用他的感受,我将在示例应用程序中使用这个约定。
一个 Vue 文件是这样的:
<template> <p>This is my HTML for my component</p> </template> <script> export default { // 组件的所有代码都在这里 } </script> <style scoped> /* CSS 在这里 * 通过包含 `scoped`, 我们确保所有的 CSS * 仅作用于这个组件! */ </style>
另外,如果您不喜欢将组件的所有部分都放在一个文件中,则可以分别给每个元素指定一个 src
属性,并分别指向一个单独的 HTML 、 JS 或 CSS文件。
建立一个项目
虽然优秀的 [Vue CLI][https://github.com/vuejs/vue-cli] 已经存在,使我很容易地设置一个完整的项目,但当开始研究使用一个新的库的时候,我喜欢从头开始,这样我可以更多的了解这些工具。
目前,Webpack 是我首选的构建工具,我们可以将其与 vue-loader 插件相结合,以支持我之前提到的 Vue.js 组件格式。最后我们需要的是 Babel 和 ES2015 预设,这样我们就可以用让人喜欢的 ES2015 语法来编写所有的代码了。
设置 Webpack 配置方法如下:
- 让 Webpack 从
src/main.js
开始构建,输出到build/main.js
- 告知 Webpack 使用
vue-loader
来解析.vue
文件 - 告知 Webpack 使用 Babel 解析任何
.js
文件 - 告知
vue-loader
应该使用 Babel 转译所有的 JavaScript 。这意味着我们*.vue
文件中包含的 JavaScript 也会使用 Babel 进行转译。
module.exports = { entry: './src/main', output: { path: './build', filename: 'main.js', }, module: { loaders: [ { test: /\.vue$/, loader: 'vue', }, { test: /\.js$/, loader: 'babel', exclude: /node_modules/, }, ], }, vue: { loaders: { js: 'babel', }, }, }
最后,我们将创建一个HTML文件,准备工作就完成了!
<!DOCTYPE html> <html> <head> <title>My Vue App</title> </head> <body> <div id="app"> </div> <script src="/build/main.js"></script> </body> </html>
我们创建一个 ID 为 app
的空 div
元素,这是我们要放置我们的 Vue 应用程序的地方。
我总是喜欢使用一个 div
,而不是 body
元素,因为这样我可以控制页面的其余部分。
编写我们第一个 Vue.js 2.0 应用
我们将始终坚持每一个编程教程,包括 Vue ,首先编写一个应用,将 “Hello World” 示在屏幕上,然后再进行更复杂的操作。
我们将保存教程中的每一个程序,在我们深入了解其它复杂的东西之前,我们想编写一个在屏幕上显示 “Hello World” 的 Vue 程序。
每个 Vue 应用程序都必须引入库, 然后实例化一个新的 Vue 实例:
import Vue from 'vue' const vm = new Vue({ el: '#app', })
我们给 Vue 一个元素用于渲染到页面上,我们创建了一个 Vue 的应用程序!我们传递一个我们想要 Vue 替换成我们应用程序元素的选择器。这意味着当Vue运行时,它将使用 div#app
并将其替换为我们创建的应用程序。
我们使用 vm
作为变量名的原因是因为它代表 “视图模型” 。
虽然与 “模型 视图 视图模型(MVVM) 模式 没有严格的关联,但是 Vue 在一定程度上受到了它的启发,在 Vue 应用程序中使用 vm
作为变量名的约定也是来源于此。当然,您可以随意命名变量!
到目前为止,我们的应用程序还没有做任何事情,所以让我们创建第一个组件 App.vue
,它将是页面上实际渲染的内容。
Vue 没有硬性的规定应用程序的结构,所以完全取决你自己。最终在本例的APP中我对每一个组件创建了一个文件夹 (我喜欢用大写字母,表示一个组件),有如下四个文件:
-
index.vue
-
template.html
-
script.js
-
style.css
App/index.vue
只是简单引用了其它三个文件:
<template src="./template.html"></template> <script src="./script.js"></script> <style scoped src="./style.css"></style>
我喜欢称它为 index.vue
,但是您也可能希望将其称为 app.vue
,以便更容易搜索。相对于 App/app.vue
而言,我更喜欢在我的代码中引入 App/index.vue
, 但是你可能会不同意,所以你可以自由选择你和你的团队最喜欢的方式。
截止到目前,我们的模板里只有 <p>Hello World</p>
,和一个空的CSS文件。主要工作在 script.js
文件中,内容如下:
export default { name: 'App', data() { return {} }, }
这样做会创建一个组件,我们将给定名称为 App
,主要用于调试目的,稍后会介绍然后定义该组件拥有并负责的数据。现在我们没有任何数据,所以我们可以通过返回一个空的对象来告诉 Vue
。稍后,我们将看到一个使用数据的组件的例子。
现在我们可以回到 src/main.js
,告诉 Vue 实例渲染我们的 App
组件:
import Vue from 'vue' import AppComponent from './App/index.vue' const vm = new Vue({ el: '#app', components: { app: AppComponent, }, render: h => h('app'), })
首先,我们引入这个组件,相信 Webpack 和 vue-loader 来处理它。然后我们声明这个组件。这个步骤很重要:默认情况下,Vue组件不是全局变量。每个组件必须有一个它使用到的所有组件的列表,它将映射到标签。在本例中,我们像这样注册了我们的组件:
components: { app: AppComponent, }
这意味着在我们的模板中,我们可以使用 app
元素来引用我们的组件。
最后,我们定义 render
函数。这是一个辅助函数, 通常被称为 h
,这能够创建元素。它与 React 使用的 React.createElement
函数不一样。在本例中,我们传递给它一个字符串 'app'
,因为我们想渲染的组件被注册为了一个 app
标签。
通常(本教程的其余部分)我们不会在其他组件上使用 render
函数,如果你想要了解更多的信息, Vue.js 指南上的 render 函数 值得一读。
一旦我们做完这些,你应该就能在屏幕上看到 “Hello World” ,现在我们启动运行 Vue.js !
Vue 开发者工具
在使用 Vue 进行稍微复杂一点的应用程序之前,现在是时候说明应该安装 Vue Devtools 了。这些都内置在 Chrome 开发者工具中,给你一个很好的方式来查看你的应用程序,以及所有被传递的属性,每个组件的状态,等等。如图:
构建App
作为一个示例应用程序,我们将使用 GitHub API 构建一个应用程序,该应用程序允许我们输入用户名,并查看有关该用户的一些 GitHub 数据。我在这里选择了Github API,因为它是大多数人所熟悉的,可以在不进行身份验证的情况下使用,并为我们提供了相当数量的信息。
在开始应用程序之前,我想快速地思考一下我们需要哪些组件,并且我认为我们的 App
组件还应该提供额外的两个组件: GithubInput
,用来接受用户的输入,以及 GithubOutput
,在屏幕上显示用户信息。我们从输入开始。
Vue.js 中的组件形式
首先,我们创建 src/GithubInput/index.vue
,用来为我们的组件加载模板,脚本以及CSS文件。在创建这个组件时,我们做的不同之处就是创建一个与组件关联的数据 – 这与 React 中状态的概念非常相似:
export default { name: 'GithubInput', data() { return { username: '', } } }
这说明这个组件有一个数据, username
。我们将根据用户的输入进行更新。
模板 src/GithubInput/template.html
, 目前进包含简单的 <p>github input</p>
。 稍后我们会填入合适的字串。 我喜欢写入一些伪 HTML ,这样的话当创建一个新的组件时,我可以检查模板是否能正常连接。
最后,为了将组件显示到屏幕上,我需要注册它到 App
组件,因为 App
组件将会渲染它。
为了做到这些,我更新了 src/App/script.js
,并且告诉它 GithubInput
组件:
import GithubInput from '../GithubInput/index.vue' export default { name: 'App', components: { 'github-input': GithubInput, }, data() { return {} }, }
然后我可以更新 app
组件的模板:
<div> <p>Hello World</p> <github-input></github-input> </div>
Vue 组件有一个限制( Angular 和 React 也有这个限制)是每个组件必须有一个根节点,因此,当一个组件必须呈现多个元素时,要记住重要的一点就是将这些元素使用一个容器包裹起来,最常见的是使用一个 div
标签。
跟踪一个表单输入
我们的 GithubInput
组件需要做两件事情:
- 跟踪输入的当前值
- 报告当前值已经更改,以便其他组件能够知道并因此更新它们的状态。
我们可以通过创建一个带 input
元素的 form
表单来完成第一个版本。使用 Vue 的内置指令,使我们能够跟踪表单的值。 GithubInput
的模板看起来是这样的:
<form v-on:submit.prevent="onSubmit"> <input type="text" v-model="username" placeholder="Enter a github username here" /> <button type="submit">Go!</button> </form>
你会注意到两个重要的属性: v-on
和 v-model
。(愚人码头注:在 Vue 中这两个属性成为 指令 。)
v-on 用于 Vue 中如何绑定到 DOM 事件以及调用函数。例如 <p v-on:click="foo">Click me!</p>
,每次这个段落(愚人码头注: p
标签)被点击时都会调用组件的 foo
方法。如果您希望更详细地了解事件处理,我强烈推荐 关于事件处理的Vue文档 。
v-model 在表单输入和数据之间创建了一个双向绑定。 在背后, v-model
不有效地监听表单输入的变化事件,并且不断更新 Vue 组件的数据使之匹配。
考虑我们上面的模板,下面是我们如何使用 v-on
和 v-model
来处理表单中的数据:
-
v-on:submit.prevent="onSubmit"
绑定的onSubmit
方法将在表单提交时运行。增加.prevent
意味着 Vue 会自动阻止浏览器默认行为的发生 (如果不想让 Vue 这样做,我们可以在代码中调用event.preventDefault()
,但是我们也可以充分利用 Vue 的特性)。 -
v-model:username
绑定input
输入的值到一个值username
,在我们的代码中. 对于熟悉 Angular 的人会认为这同ng-model
非常相似。 当我们创建GithubInput
时我们声明它拥有一个数据段username
, 并且我们在这里将该数据段绑定到一个输入域。 两者会自动保持同步。
现在,回到我们组件的 JavaScript 中,我们可以声明 onSubmit
方法。请注意,这里的名称是完全随意的 – 你可以按理喜欢的方式命名 – 但是我喜欢按照将触发它的事件命名函数的约定。
name: 'GithubInput', methods: { onSubmit(event) { if (this.username && this.username !== '') { } } },
我们可以直接使用 this
来数据,所以 this.username
将提供文本框最新的值。如果该值不为空,我们想让其它组件知道数据发生了变化。为此,我们将使用一个消息总线。这些是组件可以发出事件并侦听其他事件的对象。如果你的应用程序越来越大时,您可能应该考虑使用更好的方式,比如 Vuex ,在后面的教程中,我们将会这样做。现在,消息总线已经完成能正常工作了。
好消息是, 根据 Vue 文档中的建议 ,我们可以使用一个空的 Vue 实例作为消息总线。我们将创建 src/bus.js
,它只需创建一个 Vue 实例并将其 export(导出):
import Vue from 'vue' const bus = new Vue() export default bus
在 GithubInput
中我们可以导入该模块,并在 username
发生变化时使用它来发送一个事件:
import bus from '../bus' export default { ..., methods: { onSubmit(event) { if (this.username && this.username !== '') { bus.$emit('new-username', this.username) } } }, ... }
随着我们表单的完成,我们已经准备好开始做一些与返回数据有关的事了。
显示来自 Github 的结果
我们将使用与之前组件使用的相同结构,来创建 GithubOutput
组件。在 GithubOutput/script.js
中,我们也同样导入总线模块,因为我们需要它来知道 username
是否变化。该组件将负责的数据将是一个对象,该对象将 GitHub 用户名映射到我们从 GitHub API 获得的数据。这意味着我们不必每次都向 API 请求数据;如果我们以前已经获取了数据,我们可以简单地重用它。我们还将存储我们给出的最后一个 username
,因此我们知道什么数据会显示在屏幕上。
import bus from '../bus' export default { name: 'GithubOutput', data() { return { currentUsername: null, githubData: {} } } }
在创建组件后,我们希望侦听消息总线上发出的任何 new-username
事件。幸运的是,Vue支持许多生 命周期钩子 ,包括 created
。因为我们是负责任的开发人员,因此我们通过使用 destroyed
事件,在组件销毁时停止事件监听:
export default { name: 'GithubOutput', created() { bus.$on('new-username', this.onUsernameChange) }, destroyed() { bus.$off('new-username', this.onUsernameChange) }, ... }
然后我们定义将被调用的 onUsernameChange
方法 ,并设置 currentUsername
属性:
methods: { onUsernameChange(name) { this.currentUsername = name } },
请注意,我们不必将 onUsernameChange
方法显式绑定到当前作用域上。当您在 Vue 组件上定义方法时,Vue 会自动在方法上调用 mymethod.bind(this)
,因此他们总是绑定在组件上的。这也就是为什么要把组件的方法定义在 methods
对象中的原因之一,因为 Vue 能完全识别且可以相应地设置它们。
条件渲染
如果我们没有 username
,就像在第一次创建组件时,我们还获取不到它的值,我们想要向用户显示一条消息。Vue 有 一些条件渲染技术 ,但最简单的是 v-if
指令,它需要一个条件表达式,只在条件为 true
时才渲染元素。它也可以与 v-else
配对使用:
<div> <p v-if="currentUsername == null"> Enter a username above to see their Github data </p> <p v-else> Below are the results for {{ currentUsername }} </p> </div>
这对于任何 Angular 开发者来说都是非常熟悉的。我们使用双等号而不是三等号,因为我们希望条件为 true
,不仅当 currentUsername
为 null
时,而且还有为 undefined
时,因为 null == undefined
为 true
。
从GitHub获取数据
Vue.js 没有附带内置的 HTTP 库,是有充分的理由的。有很多浏览器提供了原生的 fetch API ( 虽然写这篇文章时, IE11, Safari 或 iOS Safari 还未提供 )。基于本教程的目的,我不会使用polyfill,但如果你需要,你可以 在浏览器中轻松的 polyfill 这个 API 。如果你不喜欢 fetch API ,有很多HTTP的第三方库,比如 在Vue文档中提到的 Axios 。
我是非常支持框架,比如 Vue ,不搭载 HTTP 库;它可以保证框架包尺寸较小,而且能让开发者选择最适合他们的库,并根据需要也更容易定制它们的 API 。 在本文中我坚持使用 fetch API ,但你可以自由的选择一个你喜欢的库。
如果你需要了解 fetch API ,请查看 SitePoint 网站上 Ludovico Fischer 的文章 ,这篇文章将可以让你更快的了解 fetch API。
为了执行 HTTP 请求,我们在组件中定义另外一个方法 fetchGithubData
,它可以调用 GitHub API 和存储结果。它会先检查我们是否已经有这个用户的数据,而不是直接请求:
fetchGithubData(name) { // 如果我们已经有了该用户数据,就不再请求 if (this.githubData.hasOwnProperty(name)) return const url = `https://api.github.com/users/${name}` fetch(url) .then(r => r.json()) .then(data => { // 在这里我们需要更新 githubData 对象 }) }
最后,我们只需要在用户名发生改变时触发此方法即可:
onUsernameChange(name) { this.currentUsername = name this.fetchGithubData(name) }
还有一件事需要注意,由于 Vue 跟踪你处理的数据,以便它知道何时更新视图。这有一个很好的 响应式指南 详细解释了这种方式,但本质上,Vue 无法神奇地知道你在一个对象中添加或删除了一个属性,所以如果我们这样做:
this.githubData[name] = data
Vue 无法识别也就无法更新视图。因此我们可以使用特殊的方法 Vue.set
,它会明确的告知 Vue 我们添加了一个 key
。 上面的代码看起来会像这样:
Vue.set(this.githubData, name, data)
此代码将修改 this.githubData
,添加我们传递的 键( key
) 和 值( value
) 。它能通知 Vue 发生了变化因而它就能渲染了。
现在我们的代码看起来像这样:
const url = `https://api.github.com/users/${name}` fetch(url) .then(r => r.json()) .then(data => { Vue.set(this.githubData, name, data) })
虽然我们还没有编写视图代码来在屏幕上显示这些数据,但是您应该能够用用户名填充表单,然后使用 Vue 开发工具,以查看从 Github 获得的数据。这说明了这些开发工具是非常有用的和强大的; 你可以检查任何组件的本地状态,看看到底发生了什么。
在视图中显示一些统计信息
现在我们可以更新模板来显示一些数据。让我们在 v-if
指令来包装这段代码,这样我们只在请求完成时才渲染数据:
<div v-if="githubData[currentUsername]"> <h4>{{ githubData[currentUsername].name }}</h4> <p>{{ githubData[currentUsername].company }}</p> <p>Number of repos: {{ githubData[currentUsername].public_repos }} </div>
重构
我们可以做一些改进。上面的 HTML 代码只需要渲染一小部分 GitHub 数据(当前用户数据)就可以了。在另外一个组件中显示用户数据就非常完美了,我们可以将用户的数据提供给它,并且它可以渲染数据。
让我们创建一个 GithubUserData
组件,和其它组件的结构相同。但有一点不同 – 这个组件有个 data
属性, 它表示用户数据。 Properties (或者, “props”)表示这个数据是从它父组件传递来的, 这一点 Vue 与 React 非常相似。在 Vue 中你必须显式的声明组件需要的 属性(property) ,因此在这里我们的组件只需要一个 data
属性(prop) :
export default { name: 'GithubUserData', props: ['data'], data() { return {} } }
我真正喜欢 Vue 的其中一个原因是必须显式的声明,所有使用到的属性、数据以及组件都必须先声明才能使用。当项目变得越来越大和越来越复杂时,代码仍然很清晰。
在新的模板中,我们有着完全相同的 HTML,虽然我们可以使用 data
进行引用,而不是 githubData[currentUsername]
:
<div v-if="data"> <h4>{{ data.name }}</h4> <p>{{ data.company }}</p> <p>Number of repos: {{ data.public_repos }} </div>
为了使用这个组件,我们需要更新 GithubOutput
组件。首先,我们导入并注册 GithubUserData
:
import bus from '../bus' import Vue from 'vue' import GithubUserData from '../GithubUserData/index.vue' export default { name: 'GithubOutput', components: { 'github-user-data': GithubUserData, }, ... }
您可以在声明它时使用任何名称,所以在这里我用的是 github-user-data
,你可以用你想要的任意名称。你用破折号来隔开名称中有意义的单词,这是明智的。Vue 不强制要求这一规范,但是 W3C 规范在对自定义元素状态要求必须有一个破折号,以避免名称和将来版本的 HTML 中存在命名冲突。
一旦我们声明了组件,我们就可以在的模板中使用它:
<p v-else> Below are the results for {{ currentUsername }}: <github-user-data :data="githubData[currentUsername]"></github-user-data> </p>
这里的关键部分是如何将 data
属性传递给组件:
:data="githubData[currentUsername]"
该属性前开始的冒号至关重要,它告诉 Vue 我们所传递的属性是动态的,组件将在每次数据有变更时自动更新。Vue 会计算 githubData[currentUsername]
的值并确保 GithubUserData
组件在每次数据更改时候保持更新。
如果您发现 :data
有点短且不好理解,您也可以使用较长的 v-bind
语法:
v-bind:data="githubData[currentUsername]"
两者是等价的,所以可以使用你喜欢的方式。
结论
通过这些,我们的Vue.js 2.0 GitHub 应用程序已经相当好了!你可以在 GitHub 找到所有的代码,甚至可以查看 在线运行的应用程序 。
开始使用Vue时,我有很高的期望,因为我只听说了它好的一面,但现在我很高兴的说它真的达到了我的预期。使用Vue的感觉就像是采用React最好的部分并且将它们同Angular最好的部分融合。一些指令(像v-if,v-else,v-model等等)是非常容易开始使用的(也比React JSX语法中的条件更易快速理解),但是 Vue 组件系统非常类似于React的。
我们鼓励把现有系统拆分成小的组件,现在我的经验可以直白的告诉你这一过程是很轻松的。而且我不得不称赞 Vue 团队写的文档太棒了。文档指南相当优秀,API 文档也非常清晰,很容易找到你需要找的内容。
如果你喜欢这篇文章并且想要学习更多的只是,那么一定要去 Vue.js 官网 。如果你对 Vue 的其它库感兴趣,比如 状态控制的库 Vuex,以及路由库 Vue router,那么请锁定 SitePoiint 的 JavaScript 频道,我将在未来的文章里继续我的 Vue 探险之路!
原文链接: https://www.sitepoint.com/up-and-running-vue-js-2-0/
以上所述就是小编给大家介绍的《使用 Vue.js 2.0 开发单页应用》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Developer's Guide to Social Programming
Mark D. Hawker / Addison-Wesley Professional / 2010-8-25 / USD 39.99
In The Developer's Guide to Social Programming, Mark Hawker shows developers how to build applications that integrate with the major social networking sites. Unlike competitive books that focus on a s......一起来看看 《Developer's Guide to Social Programming》 这本书的介绍吧!