什么是组件?

组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以是原生 HTML 元素的形式,以 is 特性扩展。

使用组件

注册

之前说过,我们可以用 Vue.extend() 创建一个组件构造器:

var MyComponent = Vue.extend({
// 选项…
})
要把这个构造器用作组件,需要用 Vue.component(tag, constructor) 注册 :

// 全局注册组件,tag 为 my-component
Vue.component(‘my-component’, MyComponent)
对于自定义标签名字,Vue.js 不强制要求遵循 W3C 规则(小写,并且包含一个短杠),尽管遵循这个规则比较好。

组件在注册之后,便可以在父实例的模块中以自定义元素 <my-component> 的形式使用。要确保在初始化根实例之前注册了组件:

<div id=”example”>
<my-component></my-component>
</div>
// 定义
var MyComponent = Vue.extend({
template: ‘<div>A custom component!</div>’
})

// 注册
Vue.component(‘my-component’, MyComponent)

// 创建根实例
new Vue({
el: ‘#example’
})
渲染为:

<div id=”example”>
<div>A custom component!</div>
</div>
A custom component!
注意组件的模板替换了自定义元素,自定义元素的作用只是作为一个挂载点。可以用实例选项 replace 决定是否替换。

Read More →

通过 Vue.js 的过渡系统,可以在元素从 DOM 中插入或移除时自动应用过渡效果。Vue.js 会在适当的时机为你触发 CSS 过渡或动画,你也可以提供相应的 JavaScript 钩子函数在过渡过程中执行自定义的 DOM 操作。

为了应用过渡效果,需要在目标元素上使用 transition 特性:

<div v-if=”show” transition=”my-transition”></div>
transition 特性可以与下面资源一起用:

v-if
v-show
v-for (只在插入和删除时触发,使用 vue-animated-list 插件)
动态组件 (介绍见组件)
在组件的根节点上,并且被 Vue 实例 DOM 方法(如 vm.$appendTo(el))触发。
当插入或删除带有过渡的元素时,Vue 将:

尝试以 ID “my-transition” 查找 JavaScript 过渡钩子对象——通过 Vue.transition(id, hooks) 或 transitions 选项注册。如果找到了,将在过渡的不同阶段调用相应的钩子。

自动嗅探目标元素是否有 CSS 过渡或动画,并在合适时添加/删除 CSS 类名。

如果没有找到 JavaScript 钩子并且也没有检测到 CSS 过渡/动画,DOM 操作(插入/删除)在下一帧中立即执行。

Read More →

基础用法

可以用 v-model 指令在表单控件元素上创建双向数据绑定。根据控件类型它自动选取正确的方法更新元素。尽管有点神奇,v-model 不过是语法糖,在用户输入事件中更新数据,以及特别处理一些极端例子。

Text

<span>Message is: {{ message }}</span>
<br>
<input type=”text” v-model=”message” placeholder=”edit me”>
Message is:

Checkbox

单个勾选框,逻辑值:

<input type=”checkbox” id=”checkbox” v-model=”checked”>
<label for=”checkbox”>{{ checked }}</label>
false
多个勾选框,绑定到同一个数组:

<input type=”checkbox” id=”jack” value=”Jack” v-model=”checkedNames”>
<label for=”jack”>Jack</label>
<input type=”checkbox” id=”john” value=”John” v-model=”checkedNames”>
<label for=”john”>John</label>
<input type=”checkbox” id=”mike” value=”Mike” v-model=”checkedNames”>
<label for=”mike”>Mike</label>
<br>
<span>Checked names: {{ checkedNames | json }}</span>
new Vue({
el: ‘…’,
data: {
checkedNames: []
}
})
Jack John Mike
Checked names: []
Radio

<input type=”radio” id=”one” value=”One” v-model=”picked”>
<label for=”one”>One</label>
<br>
<input type=”radio” id=”two” value=”Two” v-model=”picked”>
<label for=”two”>Two</label>
<br>
<span>Picked: {{ picked }}</span>
One
Two
Picked:
Select

单选:

<select v-model=”selected”>
<option selected>A</option>
<option>B</option>
<option>C</option>
</select>
<span>Selected: {{ selected }}</span>
Selected: A
多选(绑定到一个数组):

<select v-model=”selected” multiple>
<option selected>A</option>
<option>B</option>
<option>C</option>
</select>
<br>
<span>Selected: {{ selected | json }}</span>

Selected: [ “A” ]
动态选项,用 v-for 渲染:

<select v-model=”selected”>
<option v-for=”option in options” v-bind:value=”option.value”>
{{ option.text }}
</option>
</select>
<span>Selected: {{ selected }}</span>
new Vue({
el: ‘…’,
data: {
selected: ‘A’,
options: [
{ text: ‘One’, value: ‘A’ },
{ text: ‘Two’, value: ‘B’ },
{ text: ‘Three’, value: ‘C’ }
]
}
})
Selected: A
绑定 value

对于单选按钮,勾选框及选择框选项,v-model 绑定的 value 通常是静态字符串(对于勾选框是逻辑值):

<!– 当选中时,`picked` 为字符串 “a” –>
<input type=”radio” v-model=”picked” value=”a”>

<!– `toggle` 为 true 或 false –>
<input type=”checkbox” v-model=”toggle”>

<!– 当选中时,`selected` 为字符串 “abc” –>
<select v-model=”selected”>
<option value=”abc”>ABC</option>
</select>
但是有时我们想绑定 value 到 Vue 实例的一个动态属性上,这时可以用 v-bind 实现,并且这个属性的值可以不是字符串。

Checkbox

<input
type=”checkbox”
v-model=”toggle”
v-bind:true-value=”a”
v-bind:false-value=”b”>
// 当选中时
vm.toggle === vm.a
// 当没有选中时
vm.toggle === vm.b
Radio

<input type=”radio” v-model=”pick” v-bind:value=”a”>
// 当选中时
vm.pick === vm.a
Select Options

<select v-model=”selected”>
<!– 对象字面量 –>
<option v-bind:value=”{ number: 123 }”>123</option>
</select>
// 当选中时
typeof vm.selected // -> ‘object’
vm.selected.number // -> 123
参数特性

lazy

在默认情况下,v-model 在input 事件中同步输入框值与数据,可以添加一个特性lazy,从而改到在 change 事件中同步:

<!– 在 “change” 而不是 “input” 事件中更新 –>
<input v-model=”msg” lazy>
number

如果想自动将用户的输入转为 Number 类型(如果原值的转换结果为 NaN 则返回原值),可以添加一个特性 number:

<input v-model=”age” number>
debounce

debounce 设置一个最小的延时,在每次敲击之后延时同步输入框的值与数据。如果每次更新都要进行高耗操作(例如在输入提示中 Ajax 请求),它较为有用。

<input v-model=”msg” debounce=”500″>
edit me

注意 debounce 参数不会延迟 input 事件:它延迟“写入”底层数据。因此在使用 debounce时应当用 vm.$watch() 响应数据的变化。若想延迟 DOM 事件,应当使用 debounce 过滤器。

方法处理器

可以用 v-on 指令监听 DOM 事件:

<div id=”example”>
<button v-on:click=”greet”>Greet</button>
</div>
我们绑定了一个单击事件处理器到一个方法 greet。下面在 Vue 实例中定义这个方法:

var vm = new Vue({
el: ‘#example’,
data: {
name: ‘Vue.js’
},
// 在 `methods` 对象中定义方法
methods: {
greet: function (event) {
// 方法内 `this` 指向 vm
alert(‘Hello ‘ + this.name + ‘!’)
// `event` 是原生 DOM 事件
alert(event.target.tagName)
}
}
})

// 也可以在 JavaScript 代码中调用方法
vm.greet() // -> ‘Hello Vue.js!’

Read More →

v-for

可以使用 v-for 指令基于一个数组渲染一个列表。这个指令使用特殊的语法,形式为 item in items,items 是数据数组,item 是当前数组元素的别名:

示例:

<ul id=”example-1″>
<li v-for=”item in items”>
{{ item.message }}
</li>
</ul>
var example1 = new Vue({
el: ‘#example-1’,
data: {
items: [
{ message: ‘Foo’ },
{ message: ‘Bar’ }
]
}
})
结果:

Foo
Bar
在 v-for 块内我们能完全访问父组件作用域内的属性,另有一个特殊变量 $index,正如你猜到的,它是当前数组元素的索引:

<ul id=”example-2″>
<li v-for=”item in items”>
{{ parentMessage }} – {{ $index }} – {{ item.message }}
</li>
</ul>
var example2 = new Vue({
el: ‘#example-2’,
data: {
parentMessage: ‘Parent’,
items: [
{ message: ‘Foo’ },
{ message: ‘Bar’ }
]
}
})
结果:

Parent – 0 – Foo
Parent – 1 – Bar
另外,你可以为索引指定一个别名(如果 v-for 用于一个对象,则可以为对象的键指定一个别名):

<div v-for=”(index, item) in items”>
{{ index }} {{ item.message }}
</div>
从 1.0.17 开始可以使用 of 分隔符,更接近 JavaScript 遍历器语法:

<div v-for=”item of items”></div>
template v-for

类似于 template v-if,也可以将 v-for 用在 <template> 标签上,以渲染一个包含多个元素的块。例如:

<ul>
<template v-for=”item in items”>
<li>{{ item.msg }}</li>
<li class=”divider”></li>
</template>
</ul>
数组变动检测

变异方法

Vue.js 包装了被观察数组的变异方法,故它们能触发视图更新。被包装的方法有:

push()
pop()
shift()
unshift()
splice()
sort()
reverse()
你可以打开浏览器的控制台,用这些方法修改上例的 items 数组。例如:example1.items.push({ message: ‘Baz’ })。

替换数组

变异方法,如名字所示,修改了原始数组。相比之下,也有非变异方法,如 filter(), concat() 和 slice(),不会修改原始数组而是返回一个新数组。在使用非变异方法时,可以直接用新数组替换旧数组:

example1.items = example1.items.filter(function (item) {
return item.message.match(/Foo/)
})
可能你觉得这将导致 Vue.js 弃用已有 DOM 并重新渲染整个列表——幸运的是并非如此。 Vue.js 实现了一些启发算法,以最大化复用 DOM 元素,因而用另一个数组替换数组是一个非常高效的操作。

track-by

有时需要用全新对象(例如通过 API 调用创建的对象)替换数组。因为 v-for 默认通过数据对象的特征来决定对已有作用域和 DOM 元素的复用程度,这可能导致重新渲染整个列表。但是,如果每个对象都有一个唯一 ID 的属性,便可以使用 track-by 特性给 Vue.js 一个提示,Vue.js 因而能尽可能地复用已有实例。

例如,假定数据为:

{
items: [
{ _uid: ’88f869d’, … },
{ _uid: ‘7496c10′, … }
]
}
然后可以这样给出提示:

<div v-for=”item in items” track-by=”_uid”>
<!– content –>
</div>
然后在替换数组 items 时,如果 Vue.js 遇到一个包含 _uid: ’88f869d’ 的新对象,它知道它可以复用这个已有对象的作用域与 DOM 元素。

track-by $index

如果没有唯一的键供追踪,可以使用 track-by=”$index”,它强制让 v-for 进入原位更新模式:片断不会被移动,而是简单地以对应索引的新值刷新。这种模式也能处理数据数组中重复的值。

这让数据替换非常高效,但是也会付出一定的代价。因为这时 DOM 节点不再映射数组元素顺序的改变,不能同步临时状态(比如 <input> 元素的值)以及组件的私有状态。因此,如果 v-for 块包含 <input> 元素或子组件,要小心使用 track-by=”$index”

问题

因为 JavaScript 的限制,Vue.js 不能检测到下面数组变化:

直接用索引设置元素,如 vm.items[0] = {};
修改数据的长度,如 vm.items.length = 0。
为了解决问题 (1),Vue.js 扩展了观察数组,为它添加了一个 $set() 方法:

// 与 `example1.items[0] = …` 相同,但是能触发视图更新
example1.items.$set(0, { childMsg: ‘Changed!’})
至于问题 (2),只需用一个空数组替换 items。

除了 $set(), Vue.js 也为观察数组添加了 $remove() 方法,用于从目标数组中查找并删除元素,在内部它调用 splice() 。因此,不必这样:

var index = this.items.indexOf(item)
if (index !== -1) {
this.items.splice(index, 1)
}
只用这样:

this.items.$remove(item)
使用 Object.freeze()

在遍历一个数组时,如果数组元素是对象并且对象用 Object.freeze() 冻结,你需要明确指定 track-by。在这种情况下如果 Vue.js 不能自动追踪对象,将给出一条警告。

对象 v-for

也可以使用 v-for 遍历对象。除了 $index 之外,作用域内还可以访问另外一个特殊变量 $key。

<ul id=”repeat-object” class=”demo”>
<li v-for=”value in object”>
{{ $key }} : {{ value }}
</li>
</ul>
new Vue({
el: ‘#repeat-object’,
data: {
object: {
FirstName: ‘John’,
LastName: ‘Doe’,
Age: 30
}
}
})
结果:

FirstName : John
LastName : Doe
Age : 30
也可以给对象的键提供一个别名:

<div v-for=”(key, val) in object”>
{{ key }} {{ val }}
</div>
在遍历对象时,是按 Object.keys() 的结果遍历,但是不能保证它的结果在不同的 JavaScript 引擎下是一致的。

值域 v-for

v-for 也可以接收一个整数,此时它将重复模板数次。

<div>
<span v-for=”n in 10″>{{ n }} </span>
</div>
结果:

0 1 2 3 4 5 6 7 8 9
显示过滤/排序的结果

有时我们想显示过滤/排序过的数组,同时不实际修改或重置原始数据。有两个办法:

创建一个计算属性,返回过滤/排序过的数组;
使用内置的过滤器 filterBy 和 orderBy。
计算属性有更好的控制力,也更灵活,因为它是全功能 JavaScript。但是通常过滤器更方便,详细见 API