安装

简单安装

官网下载网址:

https://vuejs.org/js/vue.js

https://vuejs.org/js/vue.min.js

其他安装方式:https://cn.vuejs.org/v2/guide/installation.html

注:在网页中引入js文件即可

简单入门

**注:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

### 网页测试方式

在网页(需要引入```vue.js```文件)f12的控制台```console```中编写```js```代码测试网页(查看网页的反馈)

### 网页渲染

#### 简单字符串数据渲染(响应式绑定)

```html
<div id="app">
{{ message }}
</div>

//这里注意要放在标签的下面,下面例子类似
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})

可以在console中输入app.message = '改变'测试数据绑定的效果

绑定标签的属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div id="app-2">
<span v-bind:title="message">
鼠标悬停几秒钟查看此处动态绑定的提示信息!
</span>
</div>

var app2 = new Vue({
el: '#app-2',
data: {
message: '页面加载于 ' + new Date().toLocaleString()
}
})

可以在console中输入app2.message = '改变',再查看悬停信息测试效果
注:此处的v-bind:title可以简写为:title

条件和循环

条件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div id="app-3">
<p v-if="seen">现在你看到我了</p>
</div>

var app3 = new Vue({
el: '#app-3',
data: {
seen: true
}
})

这里seen为true(非初始化数据都行)时标签显示
seen为false(false,0,null,undefine等)时标签隐藏(不会占位置)
可以在console中输入app3.seen = false测试效果

循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<div id="app-4">
<ol>
<li v-for="todo in todos">
{{ todo.text }}
</li>
</ol>
</div>

var app4 = new Vue({
el: '#app-4',
data: {
todos: [
{ text: '学习 JavaScript' },
{ text: '学习 Vue' },
{ text: '整个牛项目' }
]
}
})

可以在console中输入app4.todos.push({ text: '新项目' })添加一个别表元素测试效果

事件和表单元素

点击事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<div id="app-5">
<p>{{ message }}</p>
<button v-on:click="reverseMessage">反转消息</button>
</div>

var app5 = new Vue({
el: '#app-5',
data: {
message: 'Hello Vue.js!'
},
methods: {
reverseMessage: function () {
this.message = this.message.split('').reverse().join('')
}
}
})

可以在console中输入app5.reverseMessage = function(){alert('测试')}修改事件函数
再点击测试效果(此处可能有延迟,我是点两次才有效果)
split('')将字符串以某分隔符分割(空字符是一个个分割)
reverse()将原数据进行翻转(第一个放在最后,第二个放在倒数第二个,类推)
join('')将数据以某个分割符(空字符是一个个紧凑拼接)拼接成一个字符串
注:此处v-on:click可以简写@click

输入框内容绑定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div id="app-6">
<p>{{ message }}</p>
<input v-model="message">
</div>

var app6 = new Vue({
el: '#app-6',
data: {
message: 'Hello Vue!'
}
})

可以在console中输入app6.message = '改了'查看输入框信息测试效果
在输入框中输入数据,app6.message的值也会跟着改变

组件

简单组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div id="app">
<ol>
//创建一个组件实例
<todo-item></todo-item>
</ol>
</div>

//定义一个组件
Vue.component('todo-item', {
template: `<li>这是待办项</li>`
});

//必须创建实例
var app = new Vue({
el: "#app"
});

注:这里Vue.component是定义全局组件

使用参数

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
<div id="app-7">
<ol>
<todo-item
v-for="item in groceryList"
v-bind:todo="item"
v-bind:key="item.id">
</todo-item>
</ol>
</div>

Vue.component('todo-item', {
props: ['todo'],
template: '<li>{{ todo.text }}</li>'
});

var app7 = new Vue({
el: "#app-7",
data: {
groceryList: [
{ id: 0, text: '蔬菜' },
{ id: 1, text: '奶酪' },
{ id: 2, text: '随便' }
]
}
});

与上一个例子相比:可以利用循环同时生成一系列列表元素
可以在console中输入app7.groceryList[0].text = '改了'修改列表数据

组件与自定义元素的关系

你可能已经注意到

组件非常类似于自定义元素——它是 ```Web``` 组件规范的一部分,这是因为 ```Vue``` 的组件语法部分参考了该规范。例如 ```Vue``` 组件实现了 ```Slot API``` 与 ```is``` 特性。但是,还是有几个关键差别:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>
> ```Web Components``` 规范已经完成并通过,但未被所有浏览器原生实现。目前 ```Safari 10.1+```、```Chrome 54+``` 和 ```Firefox 63+``` 原生支持 ```Web Components```。相比之下,```Vue``` 组件不需要任何 ```polyfill```,并且在所有支持的浏览器 (```IE9``` 及更高版本) 之下表现一致。必要时,```Vue``` 组件也可以包装于原生自定义元素之内。
>
> ```Vue``` 组件提供了纯自定义元素所不具备的一些重要功能,最突出的是跨组件数据流、自定义事件通信以及构建工具集成。
>
> 虽然 ```Vue``` 内部没有使用自定义元素,不过在应用使用自定义元素、或以自定义元素形式发布时,依然有很好的互操作性。```Vue CLI``` 也支持将 ```Vue``` 组件构建成为原生的自定义元素。

## ```Vue```实例

### 创建和相关

#### 创建

```html
var vm = new Vue({
// 选项
})

**注:所有的

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

### 数据和方法

#### 数据响应式绑定

```html
// 我们的数据对象
var data = { a: 1 }

// 该对象被加入到一个 Vue 实例中
var vm = new Vue({
data: data
})

// 获得这个实例上的属性
// 返回源数据中对应的字段
vm.a == data.a // => true

// 设置属性也会影响到原始数据
vm.a = 2
data.a // => 2

// ……反之亦然
data.a = 3
vm.a // => 3

上面的js代码可以在console中测试
只有实例被创建时,data数据才是响应式的

注意定义变量时需要初始化

1
2
3
4
5
6
7
data: {
newTodoText: '',
visitCount: 0,
hideCompletedTodos: false,
todos: [],
error: null
}

阻止数据响应式绑定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div id="app">
<p>{{ foo }}</p>
<!-- 这里的 `foo` 不会更新! -->
<button v-on:click="foo = 'baz'">Change it</button>
</div>

var obj = {
foo: 'bar'
}

//禁止obj被响应式绑定
Object.freeze(obj)

new Vue({
el: '#app',
data: obj
})

可以去掉Object.freeze(obj)再运行测试效果

实例的属性和方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var data = { a: 1 }
var vm = new Vue({
el: '#example',
data: data
})

vm.$data === data // => true
vm.$el === document.getElementById('example') // => true

// $watch 是一个实例方法
vm.$watch('a', function (newValue, oldValue) {
// 这个回调将在 `vm.a` 改变后调用
})

可以在console中测试效果
注:===是判断数据的类型以及值是否相同,(判断类型时会短路)

生命周期钩子

1
2
3
4
5
6
7
8
9
10
11
12
13
14

```html
new Vue({
data: {
a: 1
},
created: function () {
// `this` 指向 vm 实例
console.log('a is: ' + this.a)
}
})
// => "a is: 1"

created钩子会在实例被创建后的调用

其他钩子

1
2
3
4
5
6
7
8
beforecreate:可以在这加个loading事件,在加载实例时触发
created:初始化完成时的事件写在这里,如在这结束loading事件,异步请求也适宜在这里调用
beforeMount
mounted:挂载元素,获取到DOM节点
beforeUpdate
updated:如果对数据统一处理,在这里写上相应的函数
beforeDestroy:可以做一个确认停止事件的确认框
destroyed

与箭头函数冲突

不要在选项属性或回调上使用箭头函数,比如

()
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

## 模板语法

**注:```{{}}```语法是```Mustache```语法**

### 插值

#### 文本绑定

```html
<div id="app">
//可以随时更新数据
<span>Message: {{ msg }}</span>

//只能一次性插值,不能更新,会影响该节点下的其他数据绑定
<span v-once>这个将不会改变: {{ msg }}</span>
</div>

var app = new Vue({
el: '#app',
data: {
msg: 'Hello Vue!'
}
})

可以在console中输入app.msg = '改了'测试效果

解析文本中的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

```html
<div id="app-9">
<p>Using mustaches: {{ rawHtml }}</p>
//span的内容被替换
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
</div>

var app9 = new Vue({
el: '#app-9',
data: {
rawHtml: '<span style="color:red">This should be red.</span>'
}
});

使用v-html表可以解析文本中的HTML标签

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

> 你的站点上动态渲染的任意 ```HTML``` 可能会非常危险,因为它很容易导致 ```XSS``` 攻击。请只对可信内容使用 ```HTML``` 插值,绝不要对用户提供的内容使用插值。
>
> 简言之,尽量不用```v-html```解析文本中的```HTML```标签

#### 特性(```v-bind```)

**注:```Mustache```语法不能作用在```HTML```特性上,应使用```v-bind```指令**

```html
<div id="app-10">
//简单设置属性值
<div v-bind:id="dynamicId"></div>
//设置是否可用
<button v-bind:disabled="isButtonDisabled">Button</button>
</div>

var app10 = new Vue({
el: '#app-10',
data: {
dynamicId: 'div_vue',
isButtonDisabled: false
}
});

注:此处的布尔值不能是undefine(会报错),除了false和null其他都表现为true

使用
1
2
3
4
5
6
7
8
9
10
11
12

```html
例:
{{ number + 1 }}

{{ ok ? 'YES' : 'NO' }}

{{ message.split('').reverse().join('') }}

<div v-bind:id="'list-' + id"></div>

注:只能使用单个表达式

模板表达式都被放在沙盒中,只能访问全局变量的一个白名单,如

```和``` Date``` 。你不应该在模板表达式中试图访问用户定义的全局变量。
1
2
3
4
5
6
7
8
9
10

### 指令

#### 解释

> 指令是带有```v-```前缀的特殊特性
>
> 指令特性的值预期是单个```JavaScript```表达式(```v-for```例外)
>
> 指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于```DOM

1
例:<p v-if="seen">现在你看到我了</p>

参数

一些指令能够接受一个“参数”,在指令名称之后以冒号表示

1
2
3
4
<a v-bind:href="url">...</a>
在这里href是参数,告知v-bind指令将元素的href特性与表达式url的值绑定

<a v-on:click="doSomething">...</a>

动态参数(2.6.0新增)

1
2
3
4
<a v-bind:[attributeName]="url"> ... </a>
这里的attributeName会作为一个JavaScript表达式进行动态求值,求得的值将会作为最终的参数来使用

<a v-on:[eventName]="doSomething"> ... </a>

对动态参数的约束

动态参数预期会求出一个字符串,异常情况下值为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
>
> 这个特殊的```null```值可以被显示地用于移除绑定
>
> 任何其他非字符串类型的值都将会触发一个警告

> 对动态参数表达式的约束
>
> 动态参数表达式有一些语法约束,因为某些字符,例如空格和引号,放在```HTML```特性名里是无效的
>
> 同样,在```DOM```中使用模板时也需要回避大写键名

```html
例:
<!-- 这会触发一个编译警告 -->
<a v-bind:['foo' + bar]="value"> ... </a>

<!-- 在 DOM 中使用模板时这段代码会被转换为 `v-bind:[someattr]` -->
<a v-bind:[someAttr]="value"> ... </a>

修饰符

修饰符(

1
2
3
4
5
6
7
8
9
>
> 用于指出一个指令应该以特殊方式绑定

```html
<form v-on:submit.prevent="onSubmit">...</form>

.prevent修饰符告诉v-on指令对于触发的事件调用event.preventDefault()

注:event.preventDefault() 阻止默认行为,如a标签的href

缩写(
1
2
3
4
5
6
7
8
9
10
11

```html
<!-- 完整语法 -->
<a v-bind:href="url">...</a>
<!-- 缩写 -->
<a :href="url">...</a>

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

计算属性

使用计算属性的原因

在模板中放入太多的逻辑会让模板过重且难以维护

而且可读性较差

基础例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<div id="example">
<p>Original message: "{{ message }}"</p>
<p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>

var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
}
})

注:计算属性是带有缓存的
如果message的值不变,再次获取会直接获取,不会计算
如果message的值改变,计算属性也随之改变

计算属性缓存
方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14

```html
//下面调用函数的做法和上面例子的结果相同
<p>Reversed message: "{{ reversedMessage() }}"</p>

// 在组件中
methods: {
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}

注:虽然结果相同,但是计算属性是带有缓存的
如果message的值不变,不在调用方法,直接返回值,效率较方法要高

1
2
3
4
5
6
7
8
9
特殊情况
computed: {
now: function () {
return Date.now()
}
}

这个计算属性是不会更新的
因为Date.now()不是响应式依赖

计算属性
侦听属性
1
2

> 侦听属性:```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
<div id="demo">{{ fullName }}</div>

//下面的侦听属性的方式,重复代码
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
}
}
})

下面是计算属性的方式
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
})

计算属性的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

```html
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}

侦听器

作用

当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的

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
44
45
46
47
48
49
50
51
52
<div id="watch-example">
<p>
Ask a yes/no question:
<input v-model="question">
</p>
<p>{{ answer }}</p>
</div>
<!-- 因为 AJAX 库和通用工具的生态已经相当丰富,Vue 核心代码没有重复 -->
<!-- 提供这些功能以保持精简。这也可以让你自由选择自己更熟悉的工具。 -->
<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.13.1/lodash.min.js"></script>
<script>
var watchExampleVM = new Vue({
el: '#watch-example',
data: {
question: '',
answer: 'I cannot give you an answer until you ask a question!'
},
watch: {
// 如果 `question` 发生改变,这个函数就会运行
question: function (newQuestion, oldQuestion) {
this.answer = 'Waiting for you to stop typing...'
this.debouncedGetAnswer()
}
},
created: function () {
// `_.debounce` 是一个通过 Lodash 限制操作频率的函数。
// 在这个例子中,我们希望限制访问 yesno.wtf/api 的频率
// AJAX 请求直到用户输入完毕才会发出。想要了解更多关于
// `_.debounce` 函数 (及其近亲 `_.throttle`) 的知识,
// 请参考:https://lodash.com/docs#debounce
this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
},
methods: {
getAnswer: function () {
if (this.question.indexOf('?') === -1) {
this.answer = 'Questions usually contain a question mark. ;-)'
return
}
this.answer = 'Thinking...'
var vm = this
axios.get('https://yesno.wtf/api')
.then(function (response) {
vm.answer = _.capitalize(response.data.answer)
})
.catch(function (error) {
vm.answer = 'Error! Could not reach the API. ' + error
})
}
}
})
</script>

1
2

### 绑定```HTML Class

对象语法

  • 简单使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div v-bind:class="{ active: isActive }"></div>
active这个class存在与否取决于isActive的布尔值


.div_red{
color: red;
}

<div id="app-12" v-bind:class="{div_red: isRed}">
红色
</div>

var app12 = new Vue({
el: '#app-12',
data: {
isRed: false
}
});
  • 和普通
    1
    2


data: {
isActive: true,
hasError: false
}

结果为

可以和普通的class属性共存

1
2

- 定义在模板里

data: {
classObject: {
active: true,
‘text-danger’: false
}
}

1
2

- 使用计算属性

data: {
isActive: true,
error: null
},
computed: {
classObject: function () {
return {
active: this.isActive && !this.error,
‘text-danger’: this.error && this.error.type === ‘fatal’
}
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14

#### 数组语法

> 可以把一个数组传给```v-bind:class```,以应用一个```class```列表

- 简单使用

```html
<div v-bind:class="[activeClass, errorClass]"></div>

data: {
activeClass: 'active',
errorClass: 'text-danger'
}

  • 使用三元表达式
1
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
  • 数组语法与对象语法混合使用
1
<div v-bind:class="[{ active: isActive }, errorClass]"></div>

用在组件上

在一个自定义组件上使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>
> 这个元素上已经存在的类不会被覆盖

- 简单使用

```html
Vue.component('my-component', {
template: '<p class="foo bar">Hi</p>'
})

<my-component class="baz boo"></my-component>

结果为:
<p class="foo bar baz boo">Hi</p>

  • 带有数据绑定的
1
2
3
4
<my-component v-bind:class="{ active: isActive }"></my-component>

isActive为true时结果为:
<p class="foo bar active">Hi</p>

绑定内联样式

对象语法

1
2
3
4
5
6
7
8
9
10
11
12
>
> ```CSS```属性名可以用驼峰式(```camelCase```)或短横线分隔(```kebab-case```,记得用引号括起来)来命名

- 数据绑定

```html
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>

data: {
activeColor: 'red',
fontSize: 30
}
  • 对象数据绑定
1
2
3
4
5
6
7
8
9
10
<div v-bind:style="styleObject"></div>

data: {
styleObject: {
color: 'red',
fontSize: '13px'
}
}

可读性更好一些

数组语法

1
2
3
<div v-bind:style="[baseStyles, overridingStyles]"></div>

v-bind:style的数组语法可以将多个样式对象应用到同一个元素上

自动添加前缀

1
2
3
4
5
6
7
8
9
10
11
12
13
>
> ```Vue.js```会自动侦测并添加响应的前缀

#### 多重值(2.3.0+)

> 从2.3.0起你可以为```style```绑定中的属性提供一个包含多个值的数组
>
> 常用于提供多个带前缀的值

```html
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>

注:这样写只会渲染数组中最后一个被浏览器支持的值。在本例中,如果浏览器支持不带浏览器前缀的 flexbox,那么就只会渲染 display: flex

条件渲染

1
2

#### ```v-if```和```v-else

1
2
3
4
5
6
<h1 v-if="awesome">Vue is awesome!</h1>

<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>

注:v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别

在组件中使用
1
2
3
4
5
6
7

```html
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

```html
<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,v-else-if 也必须紧跟在带 v-if 或者 v-else-if 的元素之后

使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14

> ```Vue```会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染

```html
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address">
</template>

注:那么在上面的代码中切换 loginType 将不会清除用户已经输入的内容。因为两个模板使用了相同的元素,<input> 不会被替换掉——仅仅是替换了它的 placeholder

加一个唯一的

1
2
3
4
5
6
7
8
9
10
11
12

```html
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address" key="email-input">
</template>

注:<label> 元素仍然会被高效地复用,因为它们没有添加 key 属性

1
2
3
4
5
6

> ```v-show```也是通过条件控制标签是否显示
>
> 不同的是带有```v-show```的元素始终会被渲染并保留在```DOM```中
>
> ```v-show```只是简单地切换元素的```CSS```属性```display

**注:

1
2

### ```v-if``` VS ```v-show

v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。

v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。

相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于

```进行切换。
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
>
> 一般来说,`v-if` 有更高的切换开销,而 `v-show` 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 `v-show` 较好;如果在运行时条件很少改变,则使用 `v-if` 较好。

### ```v-if```与```v-for```一起使用

**注:不推荐同时使用```v-if```和```v-for```**

> 当```v-if```与```v-for```一起使用时,```v-for```具有比```v-if```更高的优先级
>
> 意味着循环几次判断几次

## 列表渲染

### 使用```v-for```遍历数组

- 使用```v-for```简单渲染列表

```html
<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' }
]
}
})

  • 使用索引和父作用域的属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<ul id="example-2">
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
</ul>

var example2 = new Vue({
el: '#example-2',
data: {
parentMessage: 'Parent',
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})

可以直接使用父作用域的属性
可以直接获取到索引
  • 可以使用
    1
    2
    3

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

- 简单遍历值

```html
<ul id="v-for-object" class="demo">
<li v-for="value in object">
{{ value }}
</li>
</ul>

new Vue({
el: '#v-for-object',
data: {
object: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
})

  • 遍历属性名和值
1
2
3
<div v-for="(value, name) in object">
{{ name }}: {{ value }}
</div>
  • 获取索引
1
2
3
<div v-for="(value, name, index) in object">
{{ index }}. {{ name }}: {{ value }}
</div>

**注:在遍历对象时,会按

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

### 维护状态

> 当 ```Vue``` 正在更新使用 `v-for` 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,```Vue``` 将不会移动 ```DOM``` 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。这个类似 ```Vue 1.x``` 的 `track-by="$index"`。
>
> 总结:只维护各个索引位置的值,不会调整顺序

> 这个默认的模式是高效的,但是**只适用于不依赖子组件状态或临时 ```DOM``` 状态 (例如:表单输入值) 的列表渲染输出**。

> 为了给 ```Vue``` 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 `key` 属性:

```html
<div v-for="item in items" v-bind:key="item.id">
<!-- 内容 -->
</div>

建议尽可能在使用 v-for 时提供 key attribute,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。

因为它是 Vue 识别节点的一个通用机制,key 并不仅与 v-for特别关联。

注:不要使用对象或数组之类的非基本类型值为v-forkey。请使用字符串或数值类型的值。

数组更新检测