1 of 41

Vue.js

数据驱动 + 组件化的前端界面开发

@尤小右

@yyx990803

vuejs.org

2 of 41

Vue.js 概况

  • 2013 年底作为个人实验项目开始开发
  • 2014 年 2 月公开发布
  • 2014 年 11 月发布从头重写的 0.11
  • 截止 2015 年 1 月:3100+ Stars on GitHub

3 of 41

Vue.js 不是一个框架

4 of 41

路由

视图管理

数据持久化

5 of 41

路由

视图管理

数据持久化

灵活的接口

6 of 41

简单示例

Quick Demo

7 of 41

核心思想:

  1. 数据驱动
  2. 组件化

8 of 41

数据驱动

Data-Driven

9 of 41

视图

View

用户行为

User Input

数据模型

Model

渲染

Render

10 of 41

视图

View

用户行为

User Input

数据模型

Model

渲染

Render

视图只是数据的映射

“真相只有一个”

11 of 41

DOM

DOM 在单页 Web 应用中的问题�

  • 重新渲染整个视图是昂贵的
  • 手动更新 DOM 来保持视图和数据的同步很容易导致 bug

12 of 41

View

ViewModel

Model

通过 MVVM 的数据绑定实现自动同步

13 of 41

DOM

POJO

(原生JS对象)

Vue

View

ViewModel

Model

通过 MVVM 的数据绑定实现自动同步

14 of 41

var vm = new Vue({� el: '#demo',� data: {� msg: 'Hello Vue.js!'� }�})

<div id="demo">� <h1>{{msg}}</h1>�</div>

JavaScript

HTML

15 of 41

var vm = new Vue({� el: '#demo',� data: {� msg: 'Hello Vue.js!'� }�})

<div id="demo">� <h1>{{msg}}</h1>�</div>

JavaScript

指令 Directive

(插值其实被编译为 v-text 指令)

ViewModel

Model

View

HTML

16 of 41

View

Model

DOM Listeners

Directives

ViewModel

应用逻辑全部是数据操作

DOM 操作封装在指令中

17 of 41

组件化

Component-Oriented

18 of 41

每一个应用界面都可以

看作是组件构成的

Nav

Content

Item

Sidebar

Side

Item

19 of 41

每一个组件都可以看做是一个

ViewModel

Nav

Content

Item

Sidebar

20 of 41

所以可以把界面抽象为

ViewModel Tree

21 of 41

在 Vue.js 中注册组件

// 扩展 Vue 来自定义一个可复用的组件类

var MyComponent = Vue.extend({

template: '<p>{{msg}}</p>',

paramAttributes: ['msg']

})

// 全局注册该组件

Vue.component('my-component', MyComponent)

22 of 41

在 Vue.js 模板中使用组件

<my-component msg="Hello!"></my-component>

my-component 组件的模板将会被填充到该元素中,而 msg 则会被作为数据传入该组件实例。渲染结果如下。

<my-component>

<p>Hello!</p>�</my-component>

23 of 41

通过 paramAttributes

实现父子组件之间的数据传递

<my-component msg="{{msgFromParent}}"></my-component>

root

my-component

msgFromParent

msg

双向绑定

每一个组件都默认有自己的独立作用域。

24 of 41

组件之间也可以通过

事件系统进行通信

$dispatch()

25 of 41

组件之间也可以通过

事件系统进行通信

$broadcast()

26 of 41

一些实现细节

27 of 41

基于 ES5 Object.defineProperty

实现对 POJO (原生JS对象)的观察和依赖收集

Object

setter

getter

Property

收集依赖

触发更新

28 of 41

a

setter

getter

b

Watcher

a.b

收集依赖

Directive

v-text="a.b"

DOM

{{a.b}}

通知

更新

通知

依赖收集机制的实现类似 Knockout,精确到每一个属性,比脏检测效率得多,性能不受制于 watcher 的数量。

29 of 41

vm.msg = 'one'�vm.msg = 'two'�vm.msg = 'three'// 只会触发一次 DOM 更新

异步批量更新

30 of 41

var vm = new Vue({� data: {� nested: {� a: {� b: 'hi!'� }� }� }�})

可以直接替换多层嵌套的对象

// 直接替换对象�vm.nested = {� a: {� b: 'yo!'� }�}

31 of 41

var data = {� msg: 'hi'�}

var vm = new Vue({� data: data�})

可以直接修改原数据对象

// 直接修改原对象�data.msg = 'changed'// DOM 会在下一帧更新

32 of 41

var items = [a, b, c]�var vm = new Vue({� data: {� items: items� }�})�// 下一帧会触发更新�items.reverse()

数组的 mutating 方法会触发更新

33 of 41

对于直接的数组替换,

v-repeat 会进行 Array-diffing

确保尽可能地复用 vm 和 DOM 元素

// 不会导致性能问题哟

vm.items = vm.items.filter(fn)

* 即使用含有全新数据对象的数组替换,只要对象有 uid 也可以通过比较 uid 来达成有效复用。

34 of 41

// 如果 data 上不存在 prop 属性,

// 则必须要用 $set 或 $add 才会触发更新

data.$set('prop', value)�data.$add('prop', value)

// 删除属性要用 $delete�data.$delete('prop')��// 数组不能用 arr[0] = value, 要用 $set�arr.$set(0, value)

ES5 的局限:

不能侦测对象属性的添加/删除

35 of 41

优势和使用场景

36 of 41

侵入性低

不对整体架构做过多约束,方便与其他库或是已有的前端技术栈整合。

37 of 41

数据持久层

Data Persistence

Layer

服务器端

数据库

Database

View

View

Model

Model

以 POJO 作为 Model 使得 Vue 对于

数据持久层的接口非常灵活

38 of 41

鼓励模块化

基于组件的开发模式有利于将界面代码

自然分割成更容易维护的模块

39 of 41

基于 CommonJS 的单文件组件:Vueify

通过 Browserify 或者 Webpack 这样的模块构建工具,将一个组件的模板、CSS 和 JS 都写在同一个文件里。

40 of 41

轻量 + 高性能

~18kb min+gzip,无外部依赖

不依赖脏检测的高效数据绑定

41 of 41

Thanks

@尤小右

@yyx990803

vuejs.org