Vue.js 快速入门

开始使用

使用Vue.js

  1. 下载
    Vue.js官网将其下载至本地,通过script 标签引入。

    1
    <script src="js/vue.js"></script>
  2. 使用npm
    npm 是一个非常有用的JavaScript 包管理工具,通过npm 可以非常迅速地使用、安装和升级Vue.js 。

    1
    2
    3
    4
    // 安装
    npm install --global vue-cli
    // 测试
    vue -V
  3. 使用CDN
    这里推荐使用Bootstrap 的CDN 加速服务,地址为https://www.bootcdn.cn

    1
    <script src="https://cdn.bootcss.com/vue/2.6.10/vue.common.dev.js"></script>

    注:关于Vue的读法(读音 /vjuː/,类似于 view)。

集成测试

在这里推荐以下广泛的Web 测试插件,通过双向的绑定,可以很好的测试,亲测很有效。
插件名称为devtools,个人可以去Google 的插件商店自行安装。

Vue.js的特性

  1. 组件
    组件是Vue.js 最强大的特性之一。
    为了更好的管理一个大型的应用程序,往往需要将应用切割为小而独立、具有复用性的组件。
    在Vue.js 中,组件是基础HTML 元素的拓展,可以方便的自定义其数据与行为。

  2. 模板
    Vue.js 使用的是基于HTML 的模板语法,允许开发者将DOM 元素与底层Vue.js 实例中的数据相互绑定。
    所有的Vue.js 的模板都是合法的HTML ,所以能被遵循的浏览器和HTML解析器解析。
    在底层的实现中,Vue.js 将模板编译为虚拟的DOM 渲染函数,结合响应式系统,在应用状态变化时,Vue.js 能够智能地计算出重新渲染组建的最小代价并应用到DOM 操作上。

  3. 响应式设计
    随着智能设备的增加,响应式网络设计(RWD/AWD)的出现,目的在于为移动设备更好的体验,用技术来适应不同分辨率的屏幕。

  4. 过渡效果
    Vue.js 在插入、更新和移除DOM 时,提供了多种不同方式的应用过渡效果,主要包含以下工具:

  • 在CSS 过度和动画中自动应用class 。
  • 可以配合使用第三方CSS 动画库。
  • 在过渡钩子函数中直接使用JavaScript 操作DOM 。
  • 可以配合使用第三方JavaScript 动画库。
  1. 单文件组件
    为了更好的适应复杂的项目,Vue.js 支持以**.vue** 结尾的文件来定义一个完整组件,用以替代使用Vue.component 注册组件的方式。
    开发者可以使用webpack 或Browserify 等构建工具来打包单文件组件。
    该特性的好处在于上线后的应用,在通过压缩工具和基本的封装工具后,可能只有一个文件,这极大的减少了对于网络请求多个文件带来的文件缓存和延时问题。

项目

基础知识认知

  1. 神奇的包管理器-npm
    npm(Node Pack - age Manager, Node包管理器) 是Node.js 默认的用JavaScript 编写的软件包管理系统。
    npm 可以管理本地项目所需要的模块并自动维护依赖情况,也可以管理全局安装的JavaScript 工具。
    如果一个项目中存在package.json 文件,那么一定可以直接使用npm install 命令自动安装和维护当前项目所需的所有模块。
    安装:
  • 安装npm之前需要首先安装Node.js ,这是一个JavaScript 运行环境,实质是对Chrome V8 引擎进行了封装。
  • 系统会自动选择访问者适合的版本,版本共有LTS 版本、Current 版本。
  • 勾选同意复选框,单击Next 进入下一步,选择安装的地点和组件,再次点击Next ,开始安装。
  • 安装完成后,cmd 中输入node -V 测试Node.js 安装是否成功。
  • 再测试npm 是否安装成功,npm -v 。

为了方便开发者的使用,淘宝提供了定制的cnpm 命令行工具代替默认的npm 进行操作,其中使用方法和npm 相同。

1
npm install -g cnpm --registry=https://registry.npm.taobao.org
  1. 好用的浏览器-Chrome
    Google Chrome 是由Google 开发的免费网页浏览器。
    Chrome 是化学元素“铬”的英文名称,过去也用Chrome 称呼浏览器的外框。
    Chrome 相应的开放源代码计划名为Chromium ,因此Google Chrome 本身是非自由软件,未开发源代码。
    Chrome 代码是基于其他开放源代码软件所编写的,包括Apple WebKit、Mozilla、FireFox ,并开发出成为V8 的高性能JavaScript 引擎。

  2. Vue.js 的调试神器 vue-devtools
    所有的代码都不是一蹴而就的,都是在不断地调试过程中完善的。
    因为Vue.js 本身是打包到生产环境的JavaScript 代码,对于调试工作而言非常的不友好和方便,所以官方提供了vue-devtools 插件,就是为了解决调试的问题。
    安装步骤,可以自行参考其他的安装步骤。

  3. 非常智能的IDE-WebStorm
    开发环境中重要的一环就是面向开发者的开发编辑器,一个好用的开发编辑器可以极大地提高开发者编写代码时的流畅度,提高用户的用户的工作效率甚至是心情。
    集成开发环境(Integerated Development Environment, IDE) 是用于提供程序开发环境的应用程序,一般包括代码编辑器、编译器、调试器和图形化用户界面等工具,是集成了代码编写功能、分析功能、编译功能、调试功能等一体化的开发软件服务套。所有具备这一特性的软件或者软件套都可以叫做集成开发环境。
    作为一个开发者,选择一个合适而且好用的IDE是非常重要的一环,虽然在庞大的开发者团队中,每个人的爱好和使用习惯有所不同,但总有一些常用的IDE是受到大众认同的。
    WebStorm 的安装步骤可以自行参考其他的博客。

  4. 精简压缩生产环境-Webpack
    Webpack 是一个开源的前端打包工具,当Webpack 处理应用程序时,他会构建一个依赖关系图,其中包含应用程序所需的各个模块,然后将所有的模块打包成一个或多个模组。
    Webpack 可以通过终端或更改Webpack.config.js 文件来设定各项功能。
    Webpack 的优点如下:

  • Webpack 是以CommonJS 的形式来书写脚本,对AMD/CMD 的支持也很全面,方便旧代码进行代码迁移。
  • 能被模块化的不仅仅是JavaScript ,其他的静态资源同样可以进行模块化。
  • 开发便捷,能替代部分Grunt/Gulp 的工作,如打包、压缩混淆、图片转Base64 等。
  • 扩展性强,插件机制完整,特别是支持React热插拔(React-hot-loader)的功能让人眼前一亮。
    Webpack 的工作流程如下:
    webpack
  1. 前世今生-ECMAScript 6
    ECMAScript 是一种由Ecma 国际(前身为欧洲计算机制造协会)通过ECMA-26 标准化的脚本程序设计语言,该语言在万维网上应用广泛,往往被称为JavaScript ,但实际上后两者是ECMA-262 的标准的实现和扩展。
    为什么要使用ES 6 ?
    因为ES 6 是一次重大的版本升级,大多数的浏览器已经支持部分ES 6 特性,并继续实现其他的特性。
    ES 6 的排名前十位的最佳特性列表:
  • Default Parameters(默认参数) in ES 6
  • Template Literals(模板文本)in ES 6
  • Multi-line Strings(多汗字符串)in ES 6
  • Destructuring Assignment(解构赋值)in ES 6
  • Enhanced Object Literals(增强的对象文本)in ES 6
  • Arrow Functions(箭头函数)in ES 6
  • Promises in ES 6
  • Block-Scoped Constructs Let and Const(块作用域构造Let and Const)
  • Classes(类)in ES 6
  • Modules(模块)in ES 6

具体的特性简介,请看我的其他博客。

实例开发

Vue.js 作为一个前端页面视图层的渐进式框架,其本身只关注于视图层,通过一个页面进行一个组件化的输出与显示。
在一个Vue.js 工程中,用于显示内容最基层的实例称之为根实例,通过该实例可以通过页面或组建的更新和显示。

  1. 创建根实例

    1
    2
    3
    var app = new Vue({
    //选项
    })

    在实例化Vue.js 时,需要传入一个选项对象,它包含数据、模板、挂载元素、方法和生命周期钩子函数等选项,全部的选项可以在API 文档中查看。
    对于已经创建的构造器,可以扩展为其他的构造器,相当于对一个构造器的继承。

    1
    2
    3
    4
    var MyComponent = Vue.extend({
    //扩展选项
    })
    var myComponentInstance = new MyComponent()
  2. 实例的属性和方法
    每个Vue.js 实例在被创建之前都要经过一系列的初始化过程,而在初始化过程中加入一些data 属性,即表示此实例的一些响应事件或数据属性等。
    data 对象中既定的值发生变化时,试图会自动产生“响应”并及时匹配值,产生响应的效果。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    //数据对象
    var data = {a : 1}
    //实例,将对象加入到Vue.js实例中
    var app = new Vue({
    data : data
    })
    //相同的对象
    app.a === data.a
    //设置属性也会改变原来的值
    app.a = 2
    data.a // => 2
    //反之亦然
    data.a = 3
    app.a // => 3

    当数据变化时,视图会重新渲染。
    Vue.js暴露了一些有用的实例属性和方法,他们前缀都有**$** ,以便于用户定义的属性区分开。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var data = {a : 1}
    var app = new Vue({
    el: '#example',
    data: data
    })
    app.$data === data // => true
    app.$el === document.getElementById('example') // => true
    //$watch也是一个实例方法
    app.$watch('a', function (newValue, oldValue) {
    // 这个回调将在'app.a'的值改变之后调用
    })
  3. 生命周期
    当出现数据监听、编译模板、挂载实例到DOM和在数据变化时更新DOM 等操作时,会在此时允许插入开发者添加的特定代码。
    比如下面代码,created 钩子函数时间可以用来在一个实例被创建之后执行代码段:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    new Vue({
    data: {
    a: 1
    },
    created: function () {
    // 'this'指向此实例
    console.log('a is:' + this.a) // => "a is: 1"
    }
    })

    为什么要叫钩子函数呢?主要是对于某个实例事件发生后需要响应已经预设好的代码,即某一个钩子钩住了一个实例的状态或事件。
    当然也有一些其他的钩子函数,如mounted、updated、destoryed 。钩子函数中的this 此时指向的是调用的Vue.js 实例。
    下面展示一下Vue.js 完整实例的生命周期示意图:
    Vue.js-lifePng-332

路由开发

以前你可能学习过路由,Vue.js 也提供了相关的路由组件,通过对不同路由路径的定义,可以将Vue.js 中可供访问的路径标明,并且方便管理和调试。
在工程中,一般采用一个路径对应一个功能的形式来定义页面,因此,一个路由路径对应一个*.vue 文件,访问该路径,即相当于显示*.vue 文件。

  1. RESTful 模式的路由
    RESTful 作为一种软件架构风格,是设计风格而不是标准,只是提供了一组设计原则和约束条件,它主要用于客户端和服务端交互的软件,基于这个风格设计的软件可以更简洁、更有层次、更易于实现缓存等机制。
    在REST 样式的Web 服务中,每个资源都有一个地址,资源本身都是方法调用的目标,方法列表对所有资源都是一样的,这些方法都是标准方法,包括HTTP GET、POST、PUT、DELETE 等方法。

  2. 安装vue-router
    vue-router 提供了Vue.js 的路由控制和管理,也是官方提供的路由控制组件,通过vue-router 可以非方便的进行路由控制。
    用Vue.js+vue-router 的形式创建单页面应用是非常简单的。使用Vue.js 可以通过组合组件来构建应用程序,当开发者将vue-router 添加进来后,需要做的就是将**组件(Component)映射到路由(routers)**,然后告诉vue-router 在哪里渲染他们即可。
    安装vue-router 的方法:

  • 直接引入CDN
    1
    <script src="https://cdn.bootcss.com/vue-router/3.0.6/vue-router.common.js"></script>
  • 使用npm安装
    1
    npm install vue-router
    接着就只需要在工程中引用即可。
    1
    2
    3
    4
    5
    // 引入相关的包
    import Vue form 'vue'
    import VueRouter from 'vue-router'
    // 使用引入的包
    Vue.use(VueRouter)
  1. 动态路由
    动态路由得匹配,经常需要把某种模式匹配到的路由全部映射到同一个组件上。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    routrs:[
    {
    path: '/',
    name: 'HelloWorld',
    component: HelloWorld
    },
    {
    path: '/user/:id',
    component: User
    }
    ]

    一个路径的定义参数使用冒号”:”进行连接标记。
    当匹配到一个路由时,参数值会被设置到this.$route.params ,可以在每个组件内使用。
    开发者可以在一个路由中设置多个路径参数,对应的值都会被设置到$route.params 中,当用户进行访问时,也会自动匹配相关的路径。
    服用组件时,如果需要对路由参数的变化做出响应的话,可以简单的watch(监测变化)$route 对象。
    vue-router 使用path-to-regexp 作为路径匹配引擎,所以支持很多高级的匹配模式。如可选的动态路径参数、匹配0个或1个、一个或多个、自定义的正则表达式。

  2. 嵌套路由
    URL中各段动态路径也按某种结构对应嵌套的各层组件,即作为路由路径。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    routes: [
    {
    path: '/',
    name: 'HelloWorld',
    component: HelloWorld
    },
    {
    path: '/user/:id',
    comonpent: User,
    children: [
    {
    path: 'vip',
    comonpent: VIP
    }
    ]
    }
    ]

    注: 以“/”开头的潜逃路径会被当作根路径,这样就可以方便的使用嵌套组件。
    children 配置就是类似于routes 配置一样的路由配置数组,所以可以自由的嵌套多层路由。
    基于上述的配置,当用户在访问”/user/XXX/“这个路径(除了/user/vip 路径的其他任意路径)时,User 的出口是不会渲染任何东西的,这是因为没有匹配到合适的子路由。

  3. 编程式导航
    在vue-router 中提供了一个新的组件,实现对路径的导航功能,即router-link
    router-link 支持用户在具有路由功能的应用中(单击)导航,通过to 属性指定目标地址。默认渲染成带有正确标签的a 标签,可以通过配置tag 属性生成其他的标签。
    另外,当目标路由成功激活时,链接元素自动设置一个表示激活的CSS 类名。
    router-link 的优势:

  • 对于H5 的History 模式还是Hash 模式,他的行为都表现一致。
  • 在H5 History 模式下,router-link 会守卫单击事件,让浏览器不再重新加载页面。
  • 在H5 History 模式下,使用base 选项之后,所有的to 属性都不需要写(基路径)了。

除了使用router-link 创建a 标签来定义导航链接,开发者还可以借助router 实例中的方法,通过编写代码来实现。

  • router.push() 方法
    调用方法如下:
    1
    router.push(location, onComplete?, onAbort? )
  • router.replace() 方法
    1
    router.replace(location, onComplete?, onAbort?)
  • router.go() 方法
    1
    router.go(n)
  1. 命名路由
    有时候,通过一个名称来标识一个路由显得更方便一些,特别是在链接一个路由,或者执行一些跳转时。可以在创建router 实例时,在router 配置中给某个路由设置名称,即其name 的属性。
    如果遇到一个命名路由,可以使用前面介绍的router-link 给to 属性传递一个对象。
    代码如下:

    1
    2
    3
    <router-link :to="{name: 'user', params:{id:123}}">User</router-link>
    // 也可以使用JavaScript 的router.push() 方法实现页面的跳转和相关的传递参数操作。
    router.push({name: 'user', params: {id:123}})
  2. 命名视图
    有时一个工程需要同时(同级)展示多个视图,但是页面并不复杂或不需要重新编写新的页面进行嵌套时,可以使用视图的别名,通过组合不同名称的视图创建显示相关的页面。
    完整的调用方式如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    // 指定组件
    <router-view class="view one"></router-view>
    <router-view class="view two" name="a"></router-view>
    <router-view class="view three" name="b"></router-view>

    // 定义路由
    routes:[
    {
    path: '/',
    comonpents; {
    defalut: Foo,
    a: Bar,
    b: Baz
    }
    }
    ]

    // App.vue文件
    <template>
    <div id="app">
    <img src="./assets/logo.png">
    <router-view />
    <router-view name="a" />
    <router-view name="b" />
    </div>
    </template>

    // 新增测试路由
    const viewNamed = {template: '<div>默认视图</div>'}
    const viewNamedA = {template: '<div>视图A</div>'}
    const viewNamedB = {template: '<div>视图B</div>'}

    {
    path: '/viewNamed',
    comonpent: {
    default: viewNamed,
    a: viewNamedA,
    b: viewNamedB
    }
    }

    // 测试
    http://localhost:8080/#/viewNamed
  3. 重定向和别名
    重定向(Redirct) 就是通过各种方法将网络请求重新定义到其他位置,简单来说就是,当用户访问一个相关的路由地址时,将其访问的地址自动跳转到其他相关地址。
    示例1:
    从/a 重定向到/b 。

    1
    2
    3
    4
    5
    const router = new VueRouter({
    routes: [
    {path: '/a', redirct: '/b'}
    ]
    })

    示例2:
    重定向至一个命名路由。

    1
    2
    3
    4
    5
    const router = new VueRouter({
    routes: [
    {path: '/a', redirct: {name: 'foo'}}
    ]
    })

    示例3:
    对于重定向方法,可以通过一个方法和相关的判定,动态返回重定向目标,使用户跳转至不同的目标。

    1
    2
    3
    4
    5
    6
    7
    8
    const router = new VueRouter({
    routes: [
    {path: '/a', redirct: to => {
    // 方法接收 目标路由 作为参数
    // return重定向的 字符串路径/路径对象
    }}
    ]
    })

    示例4:
    Vue.js 也提供了别名访问,通过别名访问将会自动使用用户访问的路由,但是内容却会使用代码指定的路由路径。

    1
    2
    3
    4
    5
    const router = new VueRouter({
    routes: [
    {path: '/a', comonpent: A, alias: '/b'}
    ]
    })

    别名的功能在于为开发者提供可以自由的将UI 结构映射到任意的URL上,而不是受限于配置的嵌套路由结构。

  4. 路由组件传递参数
    在路由的跳转时,如果需要传递参数id ,那么该怎么做呢?

  • 可以使用$route.params.id 的方式进行传递,这种方法非常方便、简单。但是在组件中使用$route 会使之与其对应的路由形成高度耦合,限制了灵活性。
  • 使用props 将组件和路由解耦。开发者可以在任何地方使用该组件,使得该组件更易于重用和测试。

示例:

1
2
3
4
5
6
7
8
9
10
<template>
<div>用户路由解耦页面, Hello {{ id }}</div>
</template>

<script type="text/javascript">
export default {
// props传递参数
props: ['id']
}
</script>

在index.js 中新增其访问的路由和props 传递参数方式

1
2
3
4
5
6
// 路由解耦
{
path: '/userProps/:id',
comonpent: userProps,
props: true
}

访问路径http://localhost:8080/#/userProps/111

  1. H5 History 模式
    vue-router 默认使用Hash 模式,即使用URL 的Hash 来模拟一个完整的URL ,于是当URL 改变时,页面不会重新加载。
    当然如果不想要很长且无固定含义的Hash ,也可以使用路由的History 模式,这种模式充分利用history.pushState 的API 来完成URL 跳转,而无需重新加载页面。
    代码如下:
    1
    2
    3
    4
    const router - new VueRouter({
    mode: 'history',
    routes: [...]
    })
    当开发者使用History 模式时,URL 就像正常的URL 一样,例如http://yoursite.com/user/id ,这种方法更符合用户的习惯。

模板开发

Vue.js 是建立在视图层上的技术,所以Vue.js中的模板系统是非常重要的功能之一。

模板简介

任何一个用于Web编写或者面向使用者的应用必定有模板的存在。
模板从根本上定义了一个系统应当以怎样的交互形式来和UI风格面向使用者,而遵循这套模板进行设计和完善功能,也是软件开发的基本模式。
严格的模板引擎的定义是:输入模板字符串+数据,得到渲染过的字符串(页面)。

使用原因

原因如下:

  • 前端模板引擎要担负XSS 的防范。
  • 前端模板引擎要支持片段的复用。
  • 前端模板引擎要支持数据输出时的处理。
  • 前端模板引擎要支持动态数据。
  • 前端模板引擎要与异步流程严密结合。

模板语法

Vue.js 使用了基于HTML 的模板语法,允许开发者声明式地将DOM 绑定至底层的Vue.js 实例数据。
Vue.js 是一个允许开发者采用简洁的模板语法来声明式地将数据渲染进DOM 的系统。
结合响应系统,在应用状态改变时,Vue.js 能够智能的计算出重新渲染组件的最小代价并应用到DOM 操作上。

  1. 文本输出
    数据绑定常用的形式就是使用Mustache 语法(双大括号)的文本插值。
    代码如下:

    1
    <span>Message: {{ msg }}</span>

    Mustache 标签将会被代替为对应数据对象上的msg属性的值。无论如何,绑定的数据对象上msg 属性发生了改变,插值处的内容都会更新。

  2. 纯HTML 输出
    双括号会将数据解释为普通的文本,而非HTML 代码,为了输出真正的HTML 代码,开发者需要使用v-html 指令:

    1
    2
    3
    4
    5
    6
    7
    8
    <div v-html="rawHtml"></div>
    <script>
    export default{
    data() {
    rawHtml: '<div style="font-size: 30px; color: red;">Hello World!</div>'
    }
    }
    </script>

    这个div的内容将会被替换为属性值rawHtml ,直接作为HTML 会忽略解析属性值中的数据绑定。

  3. JavaScript 表达式
    在Vue.js 的模板中,一直都只绑定简单的属性键值,实际上对于所有的数据绑定,Vue.js 都提供了JavaScript 表达式支持。

    1
    2
    3
    4
    {{ number + 1 }}
    {{ ok ? 'YES' : 'NO' }}
    {{ message.split('').reverse.join('') }}
    <div v-bind:id="'list-' + id"></div>

    这一特性可以作为一种动画或者是控制显示。

  4. 指令参数
    指令(Directives)是带有v- 前缀的特殊属性。指令的值预期是单个JavaScript 表达式(v-for 除外)。
    指令的指责是当表达式的值改变时,将其产生的连带影响,响应式的作用于DOM。
    例如:

    1
    <p v-if="seen">现在开发者可以看见我了</p>

    这里,v-if 指令将根据表达式seen 的值的真假来插入/移除元素。
    v- 前缀作为一种视觉提示,用来识别模板中Vue.js 特定的特性,当开发者在使用Vue.js 为现有标签添加动态行为时,v- 前缀很有帮助,但是对于一些频繁使用的指令来说就非常繁琐了。
    因此,Vue.js 为v-bind 和v-on 这两个最常用的指令提供了特定简写。
    如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <!-- 完整语法 -->
    <a v-bind:href="url"></a>
    <!-- 缩写 -->
    <a :href="url"></a>

    <!-- 完整语法 -->
    <a v-on:clock="doSomething"></a>
    <!-- 缩写 -->
    <a @click="doSomething"></a>

    这些看起来与普通的HTML 略有不同,但是@ 其实也是合法字符,在所有支持Vue.js 的浏览器中都能被正确解析,而且,不会出现在最终渲染的标记中。

计算属性和观察者属性

为了让模板的内容更加干净和整洁,同时不会影响代码和内容的可用性,Vue.js 提出了计算属性和观察者。

计算属性

模版内的表达式非常便利,但这类表达式实际上多用于简单计算,因为在模板中放入太多的逻辑会让模板过重且难以维护。
如下:

1
2
3
<div id="example">
{{ message.split('').reverse().join('') }}
</div>

修改后的如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div id="example">
<p>Original message: {{ message }}</p>
<p>Computed reversed message: "{{ reverseMessage }}"</p>
</div>
<script>
var app = new Vue({
e1: "#example",
data: {
message: 'Hello'
},
computed: {
reverseMessage: function () {
return this.message.split('').reverse().join('')
}
}
})
</script>

开发者可以像绑定普通属性一样在模板中绑定计算属性,并且其名称也可以随时定义。Vue.js 知道app.reverseMessage 依赖于app.message ,因此app.message 发生改变时,所有依赖于app.reverseMessage 的绑定也会更新。而且我们是以声明的方式创建了这种关系:计算属性的getter 函数没有连带影响(side effect),这使得他易于测试和推理。

计算属性的缓存和方法

再上一个中,我们在表达式中调用方法来达到同样的效果。
其实可以将同一个函数定义为一个方法而不是一个计算属性。对于最终的结果,两种方式确实是相同的,然而不同的是,计算属性是基于他们的依赖进行缓存的,计算属性只有在他的相关依赖发生变化时才会重新求值,这就意味着只要message 还没有发生变化,多次访问reverseMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。

计算属性和被观察的属性

Vue.js 提供一种更加通用的方式来观察和响应Vue.js 实力上的数据变动:watch 属性。
当有一些数据需要随着其他数据变化是,很容易滥用watch -特别是之前使用过AngularJS 时,通常更好的想法是使用计算属性而不是命令式的watch 回调。
如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<div id="demo">{{ fullName }}</div>
<script>
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName; 'Bar',
fullName: 'Foo Bar'
},
watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
}
}
})
</script>

<!-- 计算属性版本 -->
<script>
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName; 'Bar'
},
watch: {
firstName: function () {
return this.firstName + ' ' + this.lastName
}
}
})
</script>

这个例子的目的在于对一种数据绑定是尽可能的减少代码量,增加复用效果。

计算属性的setter 方法

计算属性默认只有getter 方法,但在需要时开发者也可以提供一个setter方法:

1
2
3
4
5
6
7
8
9
10
11
12
<script>
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
},
set: function (newValue) {
var names = newVale.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
</script>

再运行vm.fullName = ‘John Doe’ 时,setter 方法就会被调用,vm.firstName 和vm.lastName 也会相应的被更新。

观察者

虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的watcher (观察者),这是为什么Vue.js 通过watch 选项提供一个更通用的方法来响应数据的变化。
当开发者想要在数据变化响应时,执行异步操作或开销较大的操作是很有用的。


页面渲染

对于一个网站而言,只是简单的静态页面是远远不够的。

条件渲染

条件渲染是重要的控制系统,执行不同的代码会有不同的显示效果,方便根据用户的权限或组别展示不同的页面,达到代码逻辑中if…else 的逻辑效果。

  1. v-if 应用
    在字符串模板或传统的语句中,if 模板应该是由相应的条件组成的。如下:

    1
    2
    <h1 v-if="ok">Yes</h1>
    <h1 v-else>No</h1>

    在Vue.js2.1 以上的版本中还提供了else-if 的功能,标签为v-else-if 。如下:

    1
    2
    3
    4
    <div v-if="type === 'A'">A</div>
    <div v-else-if="type === 'B'">B</div>
    <div v-else-if="type === 'C'">C</div>
    <div v-else>Not A/B/C</div>

    v-else-if 元素必须紧跟在v-if 或者v-else-if 元素之后,否则就会出现错误。

  2. v-show 应用
    另一个用于根据条件展示元素的指令时v-show ,其语法与v-if 基本类似。如下:

    1
    <h1 v-show="ok">Hello!</h1>

    不同的是,带有v-show 的元素始终会被渲染并保留在DOM中,v-show 简单地切换元素的CSS 属性display 。

列表渲染

列表渲染是网页开发中必不可少的内容,通过一个数组循环,可以极大地利用模板显示众多的内容和相关的列表。

  1. v-for 应用
    用v-for 把一个数组对应为一组元素,可以进行一个模板或一些内容的循环显示,v-for 指令使用item in items 形式的特殊语法,items 是源数据组,item 是数组元素迭代的别名。如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <ul id="example-1">
    <li v-for="item in items">
    {{ item.message }}
    </li>
    </ul>

    <script>
    var example = new Vue({
    el: "#example-1",
    data: {
    items: [
    {message: 'Foo'},
    {message: 'Bar'}
    ]
    }
    })
    </script>

    另外,在v-for 块中,拥有对父作用域属性的完全访问权限,v-for 还支持一个可选的第二参数为当前项的索引。如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <ul id="example-2">
    <li v-for="(item, index) in items">
    {{ parentMessage }} - {{ index }} - {{ item.message }}
    </li>
    </ul>

    <script>
    var example = new Vue({
    el: "#example-2",
    data: {
    parentMessage: 'Parent',
    items: [
    {message: 'Foo'},
    {message: 'Bar'}
    ]
    }
    })
    </script>
  2. of 分隔符
    开发者也可以使用of 替代in 作为分隔符,因为他是最接近JavaScript迭代器的语法,而这样的使用也更像自然语言。如下:

    1
    <div v-for="item of items"></div>

    v-for 也可以通过一个对象的属性来迭代,一个对象的v-for 和一个数组的循环是一致的。如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     <ul id="v-for-object" class="demo">
    <li v-for="value in object">
    {{ value }}
    </li>
    </ul>

    <script>
    var example = new Vue({
    el: "#v-for-object",
    data: {
    object: {
    firstName: 'Name',
    lastName: 'Bar',
    age: 30
    }
    }
    })
    </script>

    同时开发者也可以把第二个参数作为键名,实现加key 的双循环输出,这个方法同样也适用于对象。

  3. v-for 和v-if 同时使用
    如果v-for 和v-if 同时使用时,就存在优先级的问题,需要注意以下几点:

  • 但他们处于同一节点,v-for 的优先级比v-if 更高,这意味着v-if 将分别重复运行于每个v-for 循环中。如下:
    1
    <li v-for="todo in todos" v-if="! todo.isComplete">{{ todo }}</li>
  • 如果开发者的目的是有条件的跳过循环的执行,可以将v-if 置于外层元素(或