Front-end Dev Engineer

0%

Vue官方文档笔记1——基础

Vue官方文档笔记1——基础

Vue官方文档笔记1——基础

Vue官方文档网址

1. 介绍

2. Vue 实例

2.1 创建一个Vue实例

每个Vue应用都是通过vue函数传建一个新的实例开始:

1
2
3
var vm= new Vue({
...
});

一个 Vue 应用由一个通过 new Vue 创建的根Vue实例,以及可选的嵌套的、可复用的组件树组成;

2.2 数据与方法

当一个 Vue 实例被创建后,它向 Vue 的响应式系统中加入其 data 对象中能找到的所有属性,当这些属性的值变化时,视图将会产生“相应”,即匹配新的值;

若使用 Object.freeze() ,则会阻止修改现有的属性,意味着响应式系统无法追踪变化;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var obj = {
foo: 'bar'
}
Object.freeze(obj)
new Vue({
el: '#app',
data: obj
})

<div id="app">
<p>{{ foo }}</p>
<!-- 这里的 `foo` 不会更新! -->
<button v-on:click="foo = 'baz'">Change it</button>
</div>

Vue 实例还暴露了一些有用的实例属性和方法,加以前缀 $ ,以便与用户定义的属性区分开;

1
2
3
4
5
6
7
8
9
10
11
12
13
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` 改变后调用
})

2.3 实例生命周期钩子

每个Vue实例在被创建的时候要经过一系列的初始化过程,这个过程中会运行一些叫做 生命周期钩子 的函数,给用户在不同阶段加入自己代码的机会;

生命周期钩子的 this 上下文指向调用它的 Vue实例
注:不要在选项属性或回调上使用箭头函数;
例如:

1
2
3
created: () => console.log(this.a)

vm.$watch('a', newValue => this.myMethod())

这是因为箭头函数是和父级上下文绑定在一起的,this 不会是如你所预期的 Vue 实例,系统会报错;

2.4 生命周期图示

生命周期图:

生命周期图片

3. 模板语法

Vue.js 使用了基于HTML 的模板语法,允许开发者声明式地将 DOM 绑定到底层Vue实例的数据;

在底层实现上,Vue将模板编译成虚拟 DOM 渲染函数;若你熟悉虚拟DOM且偏爱JavaScript原生力量,可以直接写渲染函数(render函数),使用JSX 的语法;

3.1 插值

  • 文本:数据绑定的形式就是使用“Mustache语法”,采用双括号的文本插值;
    或是通过 v-once 指令,执行一次性插值,若数据改变,插值处的内容不会更新;
  • 原生 HTML:双大括号将数据解释为普通文本,非 HTML 代码,若要输出真正的 HTML, 则使用 v-html 指令;

特性Mustache 语法不能作用在HTML特性上,则需要使用 v-bind 指令进行属性绑定,如title、src、disabled 等属性;

使用 JavaScript 表达式:对于所有的数据绑定,Vue.js 都提供了完全的 JavaScript 表达式支持;

3.2 指令

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

  • 参数:位于指令名称之后以冒号表示;例:
    • v-on 指令:参数是监听的事件名;
    • v-if 指令:根据表达式值的真假来插入/移除元素;
    • v-bind 指令:用于绑定 HTML 标签的属性,如href、img、title等;
  • 修饰符:以半角句号(.)指明的特殊后缀,用于指出一个指令应该以特殊方式绑定;

例如: .prevent 修饰符告诉 v-on 指令对于触发的事件调用 event.preventDefault(),阻止默认事件:

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

3.3 缩写

v-bind 指令缩写为(:);

1
2
3
4
<!-- 完整语法 -->
<a v-bind:href="url">...</a>
<!-- 缩写 -->
<a :href="url">...</a>

v-on指令缩写为(@):

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

4.计算属性和侦听器

4.1 计算属性

基础例子:从该实例中,可以看出,计算属性用于复杂的逻辑中,只要 computed 钩子函数中声明的计算属性所依赖的值发生变化,那么该属性就会更新,而所有依赖该计算属性的绑定也会更新;

现在我们已经以声明的方式创建这种依赖关系:计算属性的 getter 函数是没有副作用的,使得它更易于测试和理解;

  • 计算属性 Vs methods方法
    • 将一个函数定义为一个方法或是一个计算属性,两种方式结构是完全相同的;
    • 区别是:计算属性是基于他们的依赖进行缓存的;计算属性只有在它依赖发生变化时才会重新求值;而 methods则是通过触发事件来调用的;
  • 计算属性 Vs 侦听属性:
    • 侦听属性(watch)用于监测某个数据变化而触发,而计算属性原理是其数据依赖发生变化时才触发;
  • 计算属性的 setter ,例全名的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// ...
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]
}
}
}
// ..

4.2 侦听器

Vue 通过 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
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>

5. Class与Style绑定

5.1 绑定 HTML class

  1. 对象语法:给 v-bind:class 传一个对象,可动态切换class,是由于数据属性的 truthiness;也可以在对象中传入更多属性来动态切换多个 class;
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
// 1.可以在对象中传入更多属性来动态切换多个 class
<div v-bind:class="{ active: isActive, 'text-danger': hasError }"></div>

// 2.绑定的数据对象不必内联定义在模板里:
<div v-bind:class="classObject"></div>

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

// 3.也可以在这里绑定一个返回对象的计算属性:
<div v-bind:class="classObject"></div>

data: {
isActive: true,
error: null
},
computed: {
classObject: function () {
return {
active: this.isActive && !this.error,
'text-danger': this.error && this.error.type === 'fatal'
}
}
}
  1. 数组语法:
1
2
3
4
5
6
7
8
9
10
11
12
13
// 1.可以把一个数组传给 `v-bind:class`
<div v-bind:class="[activeClass, errorClass]"></div>

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

// 2. 也可以用三元表达式:
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>

// 3. 当有多个条件 class 时,数组语法中也可以使用对象语法:
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
  1. 用在组件上:
    当在一个自定义组件上使用 class 属性时,这些类将被添加到该组件的根元素上面。这个元素上已经存在的类不会被覆盖,用法和上面的用法一致;

5.2 绑定内联样式

  • v-bind:style 的对象语法其实是一个 JavaScript 对象。CSS 属性名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用单引号括起来) 来命名,如下:
1
2
3
4
5
6
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>

data: {
activeColor: 'red',
fontSize: 30
}
  • 或直接绑定到一个样式对象:
1
2
3
4
5
6
7
8
<div v-bind:style="styleObject"></div>

data: {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
  • 数组语法:v-bind:style 的数组语法可以将多个样式对象应用到同一个元素上:
1
2
<!-- baseStyles, overridingStyles 为样式对象,参考上面的styleObject -->
<div v-bind:style="[baseStyles, overridingStyles]"></div>
  • 自动添加浏览器引擎前缀的 CSS 属性时,如 transform-webkit- -moz- -o- -ms-前缀;
  • 多重值:可从 2.3.0 起,可以为 style 绑定中的属性提供一个包含多个值的数组,常用于提供多个带前缀的值,例如:<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>

6. 条件渲染

6.1 v-if 指令:

  • <template>元素上使用 v-if 条件渲染分组;
  • v-else :v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别;
  • v-else-if:充当 v-if 的“else-if 块”,可以连续使用;
  • key 管理可复用的元素: Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染;而添加一个具有唯一值的 key 属性,使得复用的元素是完全独立的,不要复用它们,

6.2 v-show 指令:根据条件展示元素的选项

v-show 的元素始终会被渲染并保留在 DOM 中, v-show 只是简单地切换元素的 CSS 属性 display: none/block;;

6.3 v-if 对比 v-show:

  • v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建;
  • v-show 元素总是会被渲染,并且只是简单地基于 CSS 进行切换;

6.4 v-if 与 v-for 一起使用

v-ifv-for一起使用时,v-for 具有比 v-if 更高的优先级;尽量不一起使用

7. 列表渲染

7.1 用 v-for 把一个数组对应为一组元素

  • v-for 指令需要使用 item in items 形式的特殊语法,items 是源数据数组并且 item 是数组元素迭代的别名;
  • v-for 块中,拥有对父作用域属性的完全访问权限;
  • v-for 还支持一个可选的第二个参数为当前项的索引;
  • 可以用 of 替代 in 作为分隔符,因为它是最接近 JavaScript 迭代器的语法;

7.2 一个对象的 v-for

v-for 通过一个对象的属性来迭代,也可以提供第二个的参数为键名,第三个参数为索引;

1
2
3
<div v-for="(value, key) in object">
{{ key }}: {{ value }}
</div>
1
2
3
4
5
6
7
8
9
10
new Vue({
el: '#v-for-object',
data: {
object: {
firstName: 'John',
lastName: 'Doe',
age: 30
}
}
})

7.3 key

尽可能在使用 v-for 时提供 key,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升; 因为它是 Vue 识别节点的一个通用机制;

1
2
3
<div v-for="item in items" :key="item.id">
<!-- 内容 -->
</div>

7.4 数组更新检测

  • 变异方法:Vue 包含一组观察数组的变异方法,所以它们也将会触发视图更新。这些方法如下:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
  • 替换数组:
    • 变异方法:会改变被这些方法调用的原始数组;
    • 非变异 (non-mutating method) 方法,例如:filter(), concat() 和 slice()这些不会改变原始数组,但总是返回一个新数组,可以用新数组替换旧数组:

注意事项:由于 JavaScript 的限制,Vue 不能检测以下变动的数组:

  • 当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue;
  • 当你修改数组的长度时,例如:vm.items.length = newLength;

解决上面第一类问题,以下两种方式都可以解决:

1
2
3
4
5
// Vue.set
Vue.set(vm.items, indexOfItem, newValue)

// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)

解决上面第二类问题,你可以使用 splice:

1
vm.items.splice(newLength)

7.5 对象更改检测注意事项

由于 JavaScript 的限制,Vue 不能检测对象属性的添加或删除;对于已经创建的实例,Vue 不能动态添加根级别的响应式属性。但是,可以使用 Vue.set(object, key, value) 方法向嵌套对象添加响应式属性:

1
Vue.set(vm.userProfile, 'age', 27)//或者使用 vm.$set 实例方法,它只是全局 Vue.set 的别名,格式一致

7.6 显示过滤/排序结果

有时我们想要显示一个数组的过滤或排序副本,而不实际改变或重置原始数据。在这种情况下,可以创建返回过滤或排序数组的计算属性,可以通过 filter 函数进行过滤,例如:

1
<li v-for="n in evenNumbers">{{ n }}</li>
1
2
3
4
5
6
7
8
9
10
data: {
numbers: [ 1, 2, 3, 4, 5 ]
},
computed: {
evenNumbers: function () {
return this.numbers.filter(function (number) {
return number % 2 === 0
})
}
}

计算属性不适用的情况下 (例如,在嵌套 v-for 循环中) 你可以使用一个 method 方法进行数据过滤;

1
<li v-for="n in even(numbers)">{{ n }}</li>
1
2
3
4
5
6
7
8
9
10
data: {
numbers: [ 1, 2, 3, 4, 5 ]
},
methods: {
even: function (numbers) {
return numbers.filter(function (number) {
return number % 2 === 0
})
}
}

7.7 一段取值范围的 v-for

v-for 也可以取整数。在这种情况下,它将重复多次模板:

1
2
3
<div>
<span v-for= "n in 10">{{ n }}</span>
</div>

7.8 v-for on a <template>

利用带有 v-for<template> 渲染多个元素;

7.9 v-for with v-if

当它们处于同一节点,v-for 的优先级比 v-if 更高,这意味着 v-if 将分别重复运行于每个 v-for 循环中;

7.10 一个组件的 v-for

自定义组件里可以像任何普通元素一样用 v-for ;然而,任何数据都不会被自动传递到组件里,因为组件有自己独立的作用域,为了把迭代数据传递到组件里,我们要用 props,例:

1
2
3
4
5
6
<my-component
v-for="(item, index) in items"
v-bind:item="item"
v-bind:index="index"
v-bind:key="item.id"
></my-component>

不自动将 item 注入到组件里的原因是,这会使得组件与 v-for 的运作紧密耦合。明确组件数据的来源能够使组件在其他场合重复使用;

7.11 todo list 的完整例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<div id="todo-list-example">
<form v-on:submit.prevent="addNewTodo">
<label for="new-todo">Add a todo</label>
<input
v-model="newTodoText"
id="new-todo"
placeholder="E.g. Feed the cat"
>
<button>Add</button>
</form>
<ul>
<li
is="todo-item"
v-for="(todo, index) in todos"
v-bind:key="todo.id"
v-bind:title="todo.title"
v-on:remove="todos.splice(index, 1)"
></li>
</ul>
</div>
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
Vue.component('todo-item', {
template: '\
<li>\
{{ title }}\
<button v-on:click="$emit(\'remove\')">Remove</button>\
</li>\
',
props: ['title']
})

new Vue({
el: '#todo-list-example',
data: {
newTodoText: '',
todos: [
{
id: 1,
title: 'Do the dishes',
},
{
id: 2,
title: 'Take out the trash',
},
{
id: 3,
title: 'Mow the lawn'
}
],
nextTodoId: 4
},
methods: {
addNewTodo: function () {
this.todos.push({
id: this.nextTodoId++,
title: this.newTodoText
})
this.newTodoText = ''
}
}
})

8.事件处理

8.1 监听事件

v-on 指令:监听 DOM 事件,并在触发时运行一些 JavaScript 代码;

8.2 事件处理方法

v-on 可以接收一个需要调用的方法名称 ;(方法在 methods 中定义 );

8.3 内联处理器中的方法

v-on 还可以在内联 JavaScript 语句中调用方法;

1
2
3
4
<div id="example-3">
<button v-on:click="say('hi')">Say hi</button>
<button v-on:click="say('what')">Say what</button>
</div>
1
2
3
4
5
6
7
8
new Vue({
el: '#example-3',
methods: {
say: function (message) {
alert(message)
}
}
})

若需要在内联语句处理器中访问原始的 DOM 事件,用特殊变量 $event 把它传入方法:

1
2
3
<button v-on:click="warn('Form cannot be submitted yet.', $event)">
Submit
</button>
1
2
3
4
5
6
7
8
// ...
methods: {
warn: function (message, event) {
// 现在我们可以访问原生事件对象
if (event) event.preventDefault()
alert(message)
}
}

8.4 事件修饰符

在事件处理程序中调用 event.preventDefault()event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节;

Vue.js 为 v-on 提供了事件修饰符,包括:.stop .prevent .capture .self .once .passive事件修饰符;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- 阻止单击事件继续传播(冒泡事件传播) -->
<a v-on:click.stop="doThis"></a>

<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>

<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>

<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>

<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即元素自身触发的事件先在此处处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>

<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>

注意:使用修饰符时,顺序很重要;例如用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击;

Vue 2.1.4 新增:

1
2
<!-- 点击事件将只会触发一次 -->
<a v-on:click.once="doThis"></a>

Vue 2.3.0 新增: Vue 还对应 addEventListener 中的 passive 选项提供了.passive 修饰符:

1
2
3
4
<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
<!-- 而不会等待 `onScroll` 完成 -->
<!-- 这其中包含 `event.preventDefault()` 的情况 -->
<div v-on:scroll.passive="onScroll">...</div>

注:不要把 .passive 和 .prevent 一起使用,因为 .prevent 将会被忽略,同时浏览器可能会向你展示一个警告;

8.5 按键修饰符

Vue 允许为 v-on 在监听键盘事件时添加按键修饰符,例如:

1
2
3
4
<!-- 只有在 `keyCode` 是 13 / enter 时调用 `vm.submit()` -->
<input v-on:keyup.enter="submit">
<!-- 缩写语法 -->
<input @keyup.enter="submit">

全部的按键别名:.enter .tab .delete (捕获“删除”和“退格”键) .esc .space .up .down .left .right

可以通过全局 config.keyCodes 对象自定义按键修饰符别名:

1
2
// 可以使用 `v-on:keyup.f1`
Vue.config.keyCodes.f1 = 112

8.6 系统修饰键

可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器:.ctrl .alt .shift .meta

注意:在 Mac 系统键盘上,meta 对应 command 键 (⌘)。在 Windows 系统键盘 meta 对应 Windows 徽标键 (⊞)。

1
2
3
4
<!-- Alt + C -->
<input @keyup.alt.67="clear">
<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>

注意:修饰键与常规按键不同,在和 keyup 事件一起用时,事件触发时修饰键必须处于按下状态。换句话说,只有在按住 ctrl 的情况下释放其它按键,才能触发 keyup.ctrl。而单单释放 ctrl 也不会触发事件。如果你想要这样的行为,请为 ctrl 换用 keyCode: keyup.17

8.7 .exact 修饰符

允许你控制由精确的系统修饰符组合触发的事件;例如:

1
2
3
4
5
6
7
<!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
<button @click.ctrl="onClick">A</button>
<!-- 有且只有 Ctrl 被按下的时候才触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>

<!-- 没有任何系统修饰符被按下的时候才触发 -->
<button @click.exact="onClick">A</button>

8.8 鼠标按钮修饰符: .left、.right、.middle

这些修饰符会限制处理函数仅响应特定的鼠标按钮;

8.9 为什么在 HTML 中监听事件?

使用 v-on 有几个好处:

  • 扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。
  • 因为你无须在 JavaScript 里手动绑定事件,你的 ViewModel 代码可以是非常纯粹的逻辑,和 DOM 完全解耦,更易于测试。
  • 当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除。你无须担心如何清理它们。

9. 表单输入绑定

9.1 基础用法

v-model 指令可以在表单 <input> <textarea> <select> 元素上创建双向数据绑定,它会根据控件类型自动选取正确的方法来更新元素:

注意:v-model 会忽略所有表单元素的 value、checked、selected 特性的初始值,而总是将 Vue 实例 的数据作为数据来源。你应该通过 JavaScript 在组件的 data 选项中声明初始值;

9.2 文本示例:

1
2
<input v-model="message" placeholder="edit me">
<p>Message is: {{ message }}</p>

9.3 多行文本示例:

1
2
3
4
<span>Multiline message is:</span>
<p style="white-space: pre-line;">{{ message }}</p>
<br>
<textarea v-model="message" placeholder="add multiple lines"></textarea>

9.4 复选框示例:单个复选框,绑定到布尔值;

1
2
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked }}</label>

9.5 文本示例:多个复选框,绑定到同一个数组;

1
2
3
4
5
6
7
8
9
10
<div id='example-3'>
<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 }}</span>
</div>
1
2
3
4
5
6
new Vue({
el: '#example-3',
data: {
checkedNames: []
}
})

9.6 单选按钮示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div id="example-4">
<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>
</div>

new Vue({
el: '#example-4',
data: {
picked: ''
}
})

9.7 选择框示例:

单选时:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div id="example-5">
<select v-model="selected">
<option disabled value="">请选择</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>Selected: {{ selected }}</span>
</div>

new Vue({
el: '...',
data: {
selected: ''
}
})

多选时 (绑定到一个数组):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div id="example-6">
<select v-model="selected" multiple style="width: 50px;">
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<br>
<span>Selected: {{ selected }}</span>
</div>
new Vue({
el: '#example-6',
data: {
selected: []
}
})

9.8 值绑定

对于单选按钮,复选框及选择框的选项,v-model绑定的值通常是静态字符串 (对于复选框也可以是布尔值);如下所示:

1
2
3
4
5
6
7
8
9
10
<!-- 当选中时,`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>

我们可以用 v-bind 实现把值绑定到 Vue 实例的一个动态属性上,这个属性的值可以不是字符串;

1
2
3
<!-- 单选按钮 -->
<input type="radio" v-model="pick" v-bind:value="a">
<!-- 当选中时:vm.pick === vm.a -->
1
2
3
4
5
<!-- 选择框的选项 -->
<select v-model="selected">
<!-- 内联对象字面量 -->
<option v-bind:value="{ number: 123 }">123</option>
</select>
1
2
3
// 当选中时:
typeof vm.selected // => 'object'
vm.selected.number // => 123

9.9 修饰符:

  • .lazy:默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 (除了上述输入法组合文字时)。你可以添加 lazy 修饰符,从而转变为使用 change 事件进行同步;

    1
    2
    <!-- 在“change”时而非“input”时更新 -->
    <input v-model.lazy="msg" >
  • .number:自动将用户的输入值转为数值类型,给 v-model 添加 number 修饰符:

    1
    <input v-model.number="age" type="number">
  • .trim:自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符:

    1
    <input v-model.trim="msg">

9.10 在组件上使用 v-model

Vue 的组件系统允许你创建具有完全自定义行为且可复用的输入组件。这些输入组件甚至可以和 v-model 一起使用;

10. 组件基础

10.1 基本实例

组件是可复用的 Vue 实例,可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用;

1
2
3
4
5
6
7
8
9
// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
1
2
3
4
5
//在根实例中使用
<div id="components-demo">
<button-counter></button-counter>
</div>
new Vue({ el: '#components-demo' })

10.2 组件的复用

组件可以任意次数复用,因为你每用一次组件,就会有一个它的新实例被创建;

注意:组件定义时, data 必须是一个函数,而不是一个对象,若 Vue 没有这条规则,点击一个组件的实例就可能会影响到该组件其它所有实例;

1
2
3
4
5
data: function () {
return {
...
}
}

10.3 组件的组织及组件注册

组件是以一棵嵌套的组件树的形式来组织;为了能在模板中使用,组件必须先注册以便 Vue 能够识别;

组件有两种组件的注册类型:全局注册和局部注册;

  • 全局注册:通过 Vue.component 全局注册例:
    1
    2
    3
    Vue.component('my-component-name', {
    // ... options ...
    })
  • 局部注册:通过对象的形式创建组件,引入组件后在 component 属性中进行注册;

全局注册的组件可以用在其被注册之后的任何 (通过 new Vue) 新创建的 Vue 根实例,也包括其组件树中的所有子组件的模板中;

10.4 通过 Prop 向子组件传递数据

Prop 是在组件上注册的一些自定义特性,当一个值传递给一个 prop 特性的时候,它就变成了那个组件实例的一个属性;

例如通过父组件向子组件传递数据:

1
2
3
4
<-- 在父组件中的创建的该子组件的实例上加入 title 属性 -->
<blog-post title="My journey with Vue"></blog-post>
<blog-post title="Blogging with Vue"></blog-post>
<blog-post title="Why Vue is so fun"></blog-post>
1
2
3
4
5
//子组件在通过 Vue.componen 全局创建的时候,props属性中包含 title 属性,用于父组件的传值
Vue.component('blog-post', {
props: ['title'],
template: '<h3>{{ title }}</h3>'
})

一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop,在子组件的 props属性中接收父组件传递的数据;

10.5 单个根元素

每个组件<template>必须只有一个根元素,将模板的内容包裹在一个父元素内,来修复这个问题;

10.6 通过事件向父级组件发送消息

  • 方法1:父组件中加一个 postFontSize 数据属性(暂时不了解)
  • 方法2:调用内建的 $emit 方法并传入事件的名字,来向父级组件触发一个事件;例:在子组件中通过点击事件添加一个事件名,再在父组件中监听这个事件,来实现子组件向父组件数据传递:
1
2
3
4
<!-- 子组件通过 $emit() 方法加入一个事件名 -->
<button v-on:click="$emit('enlarge-text')">
Enlarge text
</button>
1
2
3
4
5
//父组件上通过 v-on 指令来监听这个事件
<blog-post
...
v-on:enlarge-text="postFontSize += 0.1"
></blog-post>

同时$emit()方法还可以给事件传递一个值,父组件中使用 $event 访问到这个值:

1
2
3
4
<!-- 子组件通过 $emit() 方法加入一个事件名,并传一个值 -->
<button v-on:click="$emit('enlarge-text', 0.1)">
Enlarge text
</button>
1
2
3
4
5
//父组件上通过 v-on 指令来监听这个事件,并通过 $event 访问到被抛出的这个值;如果这个事件处理函数是一个方法,可以将该值作为参数传入方法中使用
<blog-post
...
v-on:enlarge-text="postFontSize += $event"
></blog-post>
  • 方法3:在组件上使用 v-model传值,在输入控件中调用 v-model 的原理如下:(此处没有弄懂)
1
2
3
4
5
6
<input v-model="searchText" />
<!-- 等价于 -->
<input
v-bind:value="searchText"
v-on:input="searchText = $event.target.value"
/>

当用在组件上时,v-model 则会这样:

1
2
3
4
<custom-input
v-bind:value="searchText"
v-on:input="searchText = $event"
></custom-input>

因而在组件内的 input 标签必须:将其 value 特性绑定到一个名叫 value 的 prop 上;在其 input 事件被触发时,将新的值通过自定义的 input 事件抛出;

组件中使用的代码如下:

1
2
3
4
5
6
7
8
9
10
//组件全局创建时
Vue.component('custom-input', {
props: ['value'],
template: `
<input
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
`
})
1
2
<custom-input v-model="searchText"></custom-input>
/>

10.7 通过插槽分发内容

Vue 自定义的 <slot> 元素,只要在需要的地方加入插槽就行了;

1
2
3
4
5
6
7
8
Vue.component('alert-box', {
template: `
<div class="demo-alert-box">
<strong>Error!</strong>
<slot></slot>
</div>
`
})
1
2
3
<alert-box>
Something bad happened.
</alert-box>

10.8 动态组件:

官方范例程序

通过 Vue 的 component 元素加一个特殊的 is 特性来实现:

1
2
<!-- 组件会在 `currentTabComponent` 改变时改变 -->
<component v-bind:is="currentTabComponent"></component>

上述示例中,currentTabComponent 可以包括: 已注册组件的名字 或 一个组件的选项对象;

10.9 解析 DOM 模板时的注意事项

有些 HTML 元素,诸如 <ul> <ol> <table> <select>,对于哪些元素可以出现在其内部是有严格限制的。而有些元素,诸如 <li> <tr> <option>,只能出现在其它某些特定的元素内部; Vue 中特殊的 is 特性给了我们一个变通的办法,例如:

1
2
3
4
<!-- blog 为一个自定义组件 -->
<table>
<tr is="blog"></tr>
</table>

注意: 如果我们从以下来源使用模板的话,这条限制是不存在的:

  • 字符串 (例如:template: '...');
  • 单文件组件 (.vue);
  • <script type="text/x-template">
-------------    本文结束  感谢您的阅读    -------------

赞赏一下吧~ 还可以关注公众号订阅最新内容