一篇入门Vue2
一、基础概念
1.1 MVC和MVVM
MVC
模型:
MVC
代表模型-视图-控制器,是一种将应用程序分成三个部分的软件架构模式:模型、视图和控制器。模型负责处理应用程序的数据和业务逻辑,视图负责呈现数据,控制器负责处理用户的输入和对模型和视图的更新。
MVVM
模型(Vue所使用的模型):
MVVM
代表模型-视图-视图模型,是一种将应用程序分成三个部分的软件架构模式:模型、视图和视图模型。模型和视图在MVVM
中的角色与MVC
中的角色相同,但视图模型则是一个新的组件,负责将模型中的数据转换为视图所需的格式,同时处理用户的输入并更新模型。
MVC
和MVVM
的区别:
MVC
和MVVM
都是软件架构模式,它们的目标都是将应用程序分成不同的部分,以提高应用程序的可维护性、可扩展性和可测试性。它们之间的主要区别在于以下几个方面:
- 视图和视图模型的关系不同:在
MVC
中,视图和控制器是紧密耦合的,控制器通常直接操作视图。而在MVVM
中,视图和视图模型是分离的,视图模型将数据和业务逻辑从视图中分离出来,因此视图可以更加独立地开发和测试。- 数据绑定方式不同:在
MVC
中,控制器负责将模型和视图连接起来,通常使用手动编写的代码来实现。而在MVVM
中,视图和视图模型之间通常使用双向数据绑定技术进行通信,这意味着视图中的数据可以直接绑定到视图模型中的数据属性,使得开发更加快速、简单和高效。- 数据流动方向不同:在
MVC
中,控制器负责处理用户的输入并更新模型和视图。而在MVVM
中,视图模型负责处理用户的输入,并更新模型和视图。这意味着视图模型具有更多的责任和控制权,可以更好地管理应用程序中的数据流动。
1.2 初识Vue
1.2.1 Vue是什么
Vue
是一套用于构建用户界面的渐进式框架。- 与其它大型框架不同的是,
Vue
被设计为可以自底向上逐层应用。Vue
的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue
也完全能够为复杂的单页应用提供驱动。
1.2.2 数据绑定的方式
Vue
中有2种数据绑定的方式:
- 单向绑定(v-bind):数据只能从
data
流向页面。- 双向绑定(v-model):数据不仅能从
data
流向页面,还可以从页面流向data
。
el
的2种写法
new Vue
时候配置el
属性。- 先创建
Vue
实例,随后再通过vm.$mount('#root')
指定el
的值。
1.3 数据代理
1.3.1 什么是数据代理
数据代理是一种编程模式,它通过将某个对象的属性访问代理到另一个对象上,从而实现对该对象的属性访问和修改。在
JavaScript
中,数据代理通常使用Object.defineProperty
或Proxy
对象实现。数据代理可以使代码更加简洁和易读,尤其是当需要频繁地访问某个对象的属性时。通过数据代理,我们可以将该对象的属性访问和修改都代理到另一个对象上,从而避免了频繁的属性访问和修改操作,提高了代码的可读性和可维护性。
1.3.2 Vue中的数据代理
Vue
中的数据代理是指在Vue
实例中通过$data
和$props
属性将组件实例的数据和属性代理到组件实例本身,从而可以在组件实例中直接访问和修改这些数据和属性。具体来说,当创建一个
Vue
组件实例时,Vue
会将组件实例的$data
和$props
属性分别代理到组件实例本身。通过$data
属性,我们可以访问组件实例中定义的响应式数据,通过$props
属性,我们可以访问组件实例中传递的属性。例如,我们可以在组件实例中通过
this.$data
来访问组件实例中定义的响应式数据对象,通过this.$props
来访问组件实例中传递的属性对象。而当我们在组件实例中直接访问某个数据属性时,Vue
会将这个访问操作代理到组件实例的$data
属性上,从而实现了对组件实例中定义的响应式数据的访问和修改。需要注意的是,由于
Vue
的响应式数据只能在组件实例中使用,因此在组件实例中定义的数据和方法都需要通过data
和methods
属性进行声明和初始化。在声明和初始化后,这些数据和方法就会被代理到组件实例中,可以在组件实例中通过$data
和$methods
属性进行访问和修改。
二、事件
2.1 事件处理
2.1.1 事件监听器
JavaScript
:通过获取DOM
对象再往DOM
对象上使用addEventListener
注册监听事件const btn = document.querySelector('#my-button') btn.addEventListener('click', function() { alert('点击事件!') })
jQuery
:通过$
选择器绑定对象再使用on
进行注册监听事件$('#my-button').on('click', function() { alert('点击事件!') })
Vue
:监听事件和数据绑定结合得更加紧密,可以通过事件处理函数直接访问组件实例中的数据,通过v-on
或@
进行注册监听事件<template> <button @click="handleClick1">点击!</button> <button v-on="handleClick2">点击!</button> </template> <script> export default { methods: { handleClick1() { alert('点击事件1') }, handleClick2() { alert('点击事件2') }, } } </script>
2.1.2 键盘属性
JavaScript
获取方式:
在
JavaScript
中,键盘事件相关的属性有key
、keyCode
和code
,它们分别表示不同的含义。
key
属性:表示键盘按键的字符串值,是一个标准的字符串,比如a
、b
、Enter
、ArrowDown
等等,可以区分大小写。这个属性在处理文本输入的时候非常有用。keyCode
属性:表示键盘按键的数字码,是一个整数值,每个键都有一个唯一的数字码,比如65
表示字母A
。这个属性在处理非文本输入的时候非常有用,比如控制游戏角色的移动方向等。code
属性:表示键盘按键的物理码,是一个字符串,与键盘布局相关,而不是与字符编码相关。不同的键盘布局可能会有不同的code
值,比如在QWERTY
键盘布局下,字母a
和q
的code
值是不同的。这个属性在处理键盘布局相关的情况下非常有用。需要注意的是,虽然这些属性的用途有所区别,但在不同的浏览器和操作系统下,它们的行为可能会有所不同。
Vue
获取方式:
在Vue中除了可以使用原生
JavaScript
的方式获取键盘属性,还可以使用@keyup
或@keydown
直接通过 . 进行对键盘事件的监听。<template> <div> <input type="text" @keyup.enter="handleEnter"> </div> </template> <script> export default { methods: { handleEnter(event) { alert('回车事件') } } } </script>
2.2 绑定样式
在Vue
中,绑定样式可以通过 v-bind:class
和 v-bind:style
指令来实现。
2.2.1 绑定class
- 可以通过
v-bind:class
指令来动态绑定元素的class
属性
<template>
<div :class="{ active: isActive, 'text-bold': isBold }"></div>
</template>
<script>
export default {
data() {
return {
isActive: true,
isBold: false
}
}
}
</script>
在这个例子中,<div>
元素的 class
属性会根据 isActive
和 isBold
数据属性的值动态变化。当 isActive
为 true
时,元素会添加 active
类;当 isBold
为 true
时,元素会添加 text-bold
类。
- 如果需要绑定多个类名,可以通过对象语法和数组语法来实现
<template>
<div :class="[{ active: isActive }, classList]"></div>
</template>
<script>
export default {
data() {
return {
isActive: true,
classList: ['text-bold', 'bg-red']
}
}
}
</script>
在这个例子中,<div>
元素的 class
属性会根据 isActive
和 classList
数据属性的值动态变化。classList
是一个数组,包含了元素需要添加的其他类名。
2.2.2 绑定style
- 可以通过
v-bind:style
指令来动态绑定元素的style
属性
<template>
<div :style="{ color: textColor, fontSize: textSize + 'px' }"></div>
</template>
<script>
export default {
data() {
return {
textColor: 'red',
textSize: 14
}
}
}
</script>
在这个例子中,<div>
元素的 style
属性会根据 textColor
和 textSize
数据属性的值动态变化。textColor
表示文本颜色,textSize
表示文本大小。
- 如果需要绑定多个样式,可以通过对象语法和数组语法来实现
<template>
<div :style="[baseStyles, additionalStyles]"></div>
</template>
<script>
export default {
data() {
return {
baseStyles: {
color: 'red',
fontSize: '14px'
},
additionalStyles: {
backgroundColor: 'blue',
fontWeight: 'bold'
}
}
}
}
</script>
在这个例子中,<div>
元素的 style
属性会根据 baseStyles
和 additionalStyles
数据属性的值动态变化。baseStyles
和 additionalStyles
都是对象,包含了需要添加的样式。如果有相同的样式属性,后面的样式会覆盖前面的样式。
2.3 Vue的事件修饰符
在Vue
中,事件修饰符是指用来简化事件监听的一些特殊指令。事件修饰符可以通过在事件后面加上特殊的符号来实现,例如 .stop
、.prevent
等。下面介绍一些常用的事件修饰符及其作用:
.stop
:阻止事件冒泡。
例如:
<button @click.stop="onClick">点击</button>
在这个例子中,当点击 <button>
元素时,不会触发其父元素的 click 事件。
2. .prevent
:阻止事件默认行为。
例如:
<form @submit.prevent="onSubmit">
<!-- ... -->
</form>
在这个例子中,当表单提交时,不会重新加载页面。
3. .capture
:添加事件监听器时使用事件捕获模式。
例如:
<div @click.capture="onClick">点击</div>
在这个例子中,当点击 <div>
元素时,先触发它的祖先元素的 click 事件,再触发自身>的 click 事件。
4. .self
:只当事件在该元素本身触发时才会触发回调。
例如:
<div @click.self="onClick">点击</div>
在这个例子中,当点击 <div>
元素本身时,才会触发 click 事件,如果点击 <div>
>的子元素,则不会触发。
.once
:只触发一次回调。
例如:
<button @click.once="onClick">点击</button>
在这个例子中,当点击 <button>
元素时,只会触发一次 click 事件。
.passive
:指定事件监听器不会调用preventDefault()
。
例如:
<div @touchmove.passive="onTouchMove">滑动</div>
在这个例子中,当触摸屏幕滑动时,不会阻止页面滚动。
三、内置属性
3.1 计算属性和监视属性
3.1.1 计算属性
计算属性是一种计算值的方式,可以根据其他属性的值来动态地计算新的属性值。计算属性可以缓存计算结果,当依赖的属性发生改变时,才会重新计算。在Vue
中,可以使用computed
选项来定义计算属性,例如:
<template>
<div>{{ fullName }}</div>
</template>
<script>
export default {
data() {
return {
firstName: '张',
lastName: '三'
}
},
computed: {
fullName() {
return this.firstName + '-' + this.lastName
}
}
}
</script>
3.1.2 监视属性
监视属性用于监听一个属性的变化,并在变化时执行相应的操作。在Vue
中,可以使用watch
选项来定义监视属性,例如:
<template>
<div>{{ message }}</div>
</template>
<script>
export default {
data() {
return {
count: 0,
message: ''
}
},
watch: {
count(newValue, oldValue) {
this.message = 'Count changed from ' + oldValue + ' to ' + newValue
}
}
}
</script>
3.1.3 两个属性的异同
相同点:
- 都是处理响应式数据的方法,可以实时监控数据变化并做出相应的响应。
- 都可以依赖于其他数据(data 中的属性、计算属性、甚至是其他监视属性),当这些数据变化时,计算属性和监视属性都会重新计算/执行。
不同点:
- 计算属性是根据它的依赖属性(data 中的属性、计算属性)动态计算而来,它会根据依赖属性的变化自动重新计算;而监视属性是在某个属性变化时执行一段特定的代码,可以用来处理一些复杂的业务逻辑。
- 计算属性可以缓存计算结果,当依赖的属性没有发生变化时,会直接返回之前缓存的计算结果,提高了性能;而监视属性不能缓存计算结果,每次依赖属性变化时都会重新计算。
- 计算属性可以直接在模板中使用,不需要手动调用;而监视属性只能通过代码来触发执行。
3.1.4 使用场景
计算属性的使用场景:
- 需要根据多个依赖属性计算得出一个属性值的场景,如一个购物车的总价。
- 需要对某个属性进行复杂的逻辑计算,如对一个列表进行排序、筛选等操作。
- 需要对模板中的数据进行格式化,如将时间戳转化为日期格式。
- 需要对数据进行缓存,避免频繁计算,如根据条件过滤后的结果。
监视属性的使用场景:
- 当需要在某个属性发生变化时执行一些操作,如发送 Ajax 请求、更新本地存储、修改其他数据等。
- 当需要监听一个复杂对象或数组的变化时,如监听一个表单对象的变化,可以使用深度监视。
- 当需要在组件加载时或销毁时执行一些操作时,如在组件加载时获取数据、在组件销毁时清除定时器。
总的来说,计算属性适合处理复杂的属性计算和数据格式化等场景,而监视属性适合监听数据的变化和执行一些特定的操作等场景,需要根据具体的业务需求来选择使用哪个特性。
3.2 v-show和v-if
3.2.1 作用
v-show
和v-if
是 Vue.js 框架中的指令,都用于控制元素的显示与隐藏。使用 v-show
或v-if
指令,将其添加到需要控制显示与隐藏的元素上,例如:
<div v-show="isVisible">Hello, World!</div>
<div v-if="isVisible">Hello, World!</div>
isVisible
是一个布尔类型元素,当 isVisible
的值为 true
时,元素会显示出来,当 isVisible
的值为 false
时,元素会隐藏起来。
3.2.2 区别
v-show
通过CSS
样式的控制来显示或隐藏元素。当v-show
的值为true
时,元素会被设置为display: block
,显示出来;当v-show
的值为false
时,元素会被设置为display: none
,隐藏起来。这种方式虽然不需要重新渲染DOM
,但是元素依然存在于页面中,可能会影响页面布局和性能。v-if
是基于条件判断的动态组件,它会根据条件动态地添加或删除元素,以实现显示或隐藏的效果。当v-if
的值为true
时,元素会被添加到DOM
中,显示出来;当v-if
的值为false
时,元素会从DOM
中移除,隐藏起来。这种方式虽然需要重新渲染 DOM,但是可以更好地控制页面的布局和性能。
3.2.3 使用场景
v-show
适用于需要频繁切换显示与隐藏的元素,因为它的切换速度比v-if
快,不需要重新渲染 DOM。但是,如果需要在初始渲染时就确定元素是否需要显示,应该优先考虑使用v-if
指令,因为它可以在元素的添加和删除之间切换,可以更好地控制 DOM 的渲染和销毁。v-if
适用于需要根据条件动态地添加或删除元素的场景,例如当数据满足一定条件时才需要显示某个元素。但是,如果需要频繁切换元素的显示与隐藏,应该优先考虑使用v-show
指令,因为它的切换速度更快,不需要重新渲染DOM
。
3.3 过滤器
Vue
中的过滤器(filters)是一种用于格式化文本输出的工具,可以在模板中使用 {{ }}
插值表达式和 v-bind
指令中使用。它可以将原始数据进行处理和转换,生成一个新的值,然后输出到视图中显示给用户。
Vue
中的过滤器可以通过全局过滤器和局部过滤器两种方式来定义。全局过滤器可以在任何Vue
实例中使用,而局部过滤器只能在定义它的组件实例中使用。
下面是使用全局过滤器的例子:
<!-- 定义全局过滤器 -->
<script>
Vue.filter('uppercase', function(value) {
return value.toUpperCase();
});
</script>
<!-- 在模板中使用过滤器 -->
<div>{{ message | uppercase }}</div>
上面的例子中,我们定义了一个名为 uppercase
的全局过滤器,用于将字符串转换为大写格式。在模板中,我们使用 |
管道符将需要过滤的数据 message
与过滤器名称 uppercase
进行连接,输出的结果将是 message
中的字符串全部大写。
除了字符串转换,过滤器还可以进行格式化日期、数字、货币等各种类型的数据。Vue
内置了一些常用的过滤器,如 capitalize
(将首字母转换为大写)、currency
(将数字格式化为货币格式)等,也可以通过自定义过滤器来满足特定的需求。
五、指令
5.1 常用内置指令
5.1.1 v-text
v-text
是Vue.js中常用的内置指令之一,用于将数据绑定到DOM
元素的文本内容。与双花括号({{ }}
)类似,v-text
指令也可以将Vue实例中的数据渲染到页面上。
使用v-text
指令时,Vue会将指定的数据绑定到指令所在的元素的文本内容上,覆盖掉原来的文本内容。例如,如果要在一个<p>
元素中显示Vue实例中的message
数据,可以使用以下代码:
<template>
<div id="app">
<p v-text="message"></p>
</div>
</template>
<script>
export default {
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
});
}
</script>
当Vue实例被创建时,v-text
指令会将实例中的message
数据绑定到<p>
元素的文本内容中,页面会显示Hello Vue!
。
与使用双花括号渲染文本内容的方式相比,v-text
指令的优势在于可以避免在页面加载时出现短暂的闪烁效果。这是因为当使用双花括号渲染文本内容时,页面会先显示双花括号内的原始字符串,然后再替换为绑定的数据。而使用v-text
指令时,页面会直接显示绑定的数据,不会出现闪烁效果。
5.1.2 v-html
v-html
是Vue
框架中的一个指令,用于将一个包含HTML标记的字符串解析并渲染为HTML
,并将其动态地插入到指定元素的innerHtml
属性中。使用v-html
指令可以方便地将从后台获取的富文本内容渲染到页面上。
使用v-html
指令时,需要将需要渲染的HTML
字符串绑定到指令的值上,例如:
<template>
<div id="app">
<p v-html="message"></p>
</div>
</template>
<script>
export default {
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
});
}
</script>
htmlString
是一个包含HTML
标记的字符串,Vue
会将其解析并插入到div元素的innerHtml
属性中。需要注意的是,使用v-html
指令存在一定的安全风险,因为任何可执行的脚本都可以在被插入的HTML
中执行。因此,需要确保从后台获取的HTML
内容是可信的,并对其进行适当的处理和过滤,以避免潜在的安全问题。
5.1.3 v-text和v-html区别
v-html
和v-text
都是Vue
框架中的指令,用于动态绑定元素的文本内容。但是它们之间有以下几个区别:
v-text
指令会将绑定的数据作为纯文本输出到元素中,不会将HTML标签进行解析。而v-html指令会将绑定的数据解析为HTML标记,并将其插入到元素中。因此,v-html
指令可以用于渲染包含HTML标记的富文本内容。v-text
指令的性能比v-html
指令要高,因为v-html
指令需要将绑定的数据进行解析和处理,而v-text指令只需要将数据作为纯文本输出。- 使用
v-html
指令需要谨慎,因为任何可执行的脚本都可以在被插入的HTML中执行,存在一定的安全风险。而使用v-text
指令则不需要担心这种安全问题。
因此,一般情况下,如果要输出纯文本内容,应该使用v-text
指令;如果要输出包含HTML标记的富文本内容,则应该使用v-html
指令。同时,需要注意在使用v-html
指令时,需要确保从后台获取的HTML
内容是可信的,并对其进行适当的处理和过滤,以避免潜在的安全问题。
5.1.4 v-pre
v-pre
是Vue
框架中的一个指令,用于跳过指定元素及其子元素的编译过程。使用v-pre
指令可以提高页面的渲染性能,特别是当页面中存在大量静态的模板代码时,可以通过使用v-pre
指令跳过这些模板的编译过程,减少页面渲染的时间和消耗的资源。
使用v-pre指令时,只需要在需要跳过编译的元素上添加v-pre
指令即可,例如:
<div v-pre>
<!-- msg不会被渲染 -->
{{msg}}
</div>
在上面的例子中,使用了v-pre
指令的div元素及其子元素都不会被编译,直接输出原始的模板代码,不会执行任何计算或绑定数据的操作。
需要注意的是,使用
v-pre
指令会影响到指令和插值表达式的处理,因为它会跳过指定元素及其子元素的编译过程。因此,在使用v-pre
指令时,需要确保跳过编译的元素及其子元素不包含任何指令或插值表达式,否则这些指令或插值表达式将不会被解析和执行。同时,需要避免在跳过编译的元素及其子元素中使用v-if
、v-for
等需要动态渲染的指令,否则会导致这些指令失效。
5.1.5 v-cloak
v-cloak
是Vue
框架中的一个指令,用于解决页面加载时显示{{ }}
表达式的问题。当Vue实例在挂载到元素上时,由于需要进行编译和渲染,因此在加载时会出现一段时间的{{ }}
表达式的原始显示,这通常会对用户产生不好的体验。使用v-cloak
指令可以避免这个问题的出现。
使用v-cloak
指令时,只需要在需要隐藏的元素上添加v-cloak
指令,并且在CSS样式中定义v-cloak
的样式即可,例如:
<template>
<div id="app">
<div v-cloak>
{{我是内容}}
</div>
</div>
</template>
<style>
[v-cloak] {
display: none;
}
</style>
在上面的例子中,当Vue
实例进行编译和渲染时,由于添加了v-cloak
指令,并且定义了对应的样式,因此在加载时该元素会被隐藏起来,直到Vue实例完成编译和渲染后才会被显示出来,这样可以避免{{ }}
表达式的原始显示。
需要注意的是,使用
v-cloak
指令需要同时添加对应的CSS
样式才能生效,否则无法达到隐藏元素的效果。同时,v-cloak
指令需要在Vue
实例完成编译和渲染后才会生效,因此在使用v-cloak
指令时需要确保Vue
实例已经被正确挂载到了对应的元素上。
5.1.6 v-once
v-once
是Vue
框架中的一个指令,用于只渲染元素和组件一次,不会随着数据的变化而重新渲染。使用v-once
指令可以优化页面的性能,减少不必要的重新渲染和重绘,特别是当页面中存在静态内容时,可以通过使用v-once
指令提高页面的渲染效率。
使用v-once
指令时,只需要在需要只渲染一次的元素或组件上添加v-once
指令即可,例如:
<template>
<div id="app">
<p v-once="message"></p>
</div>
</template>
<script>
export default {
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
});
}
</script>
在上面的例子中,使用了v-once
指令的div
元素及其子元素只会被渲染一次,不会随着数据的变化而重新渲染。当Vue实例完成渲染后,使用v-once
指令的元素及其子元素会被设置为静态内容,不会再参与任何数据的绑定和渲染。
需要注意的是,使用
v-once
指令会影响到元素或组件的响应性,因为它只会在首次渲染时进行绑定和渲染,不会随着数据的变化而更新。因此,在使用v-once
指令时,需要确保元素或组件的内容确实是静态的,不会随着数据的变化而改变。同时,需要注意v-once
指令只会渲染元素或组件本身,不会影响到其子元素或组件的渲染。
5.2 自定义指令
Vue
的自定义指令可以用于在元素上添加特定的行为或功能,例如设置样式、绑定事件、操作DOM
等。自定义指令可以通过Vue.directive()
方法进行注册,具体步骤如下:
- 使用
Vue.directive()
方法注册自定义指令,该方法接受两个参数,第一个参数是指令的名称,第二个参数是一个对象,包含指令的相关配置。
Vue.directive('my-directive', {
// 指令配置
})
- 在指令的配置对象中定义指令的生命周期函数,如
bind
、inserted
、update
、componentUpdated
、unbind
等。这些函数会在指令绑定到元素、插入到DOM、更新元素、更新组件等不同阶段被调用,可以用于执行具体的逻辑。
Vue.directive('my-directive', {
bind: function (el, binding, vnode) {
// 指令绑定时执行的逻辑
},
inserted: function (el, binding, vnode) {
// 指令插入到DOM时执行的逻辑
},
update: function (el, binding, vnode) {
// 指令更新时执行的逻辑
},
componentUpdated: function (el, binding, vnode) {
// 指令所在的组件更新时执行的逻辑
},
unbind: function (el, binding, vnode) {
// 指令解绑时执行的逻辑
}
})
- 在模板中使用自定义指令,可以通过在元素上使用v-指令名称的方式进行绑定,并在指令参数中传递一些值或表达式。
<div v-my-directive="{ arg: 'value', value: 123 }">自定义指令示例</div>
在上面的例子中,使用了v-my-directive
指令,并传递了一个包含arg
和value
属性的对象作为指令参数。
需要注意的是,自定义指令的命名应该遵循
Vue
的命名规范,即只包含小写字母、数字、中划线和下划线,并以字母开头。同时,自定义指令可以接收指令参数、修饰符等内容,具体可以参考Vue
的官方文档。
六、Vue的生命周期
在Vue
应用程序中,每个Vue
实例都会经历一系列的生命周期钩子函数,用于在不同的阶段执行特定的逻辑。这些生命周期钩子函数可以帮助我们在不同的时刻处理应用程序的状态,例如初始化数据、渲染组件、监听事件、销毁组件等。Vue
的生命周期可以分为8个阶段,分别是:
- beforeCreate:实例创建之前,此时数据和事件都未初始化,无法访问
this
和$el
等实例属性。- created:实例创建完成,此时可以访问
this
,但是$el
还未挂载。- beforeMount:模板编译完成,但还未挂载到页面上,此时
$el
属性已经存在。- mounted:模板编译完成,并已经将实例挂载到页面上,此时可以访问到渲染后的
DOM
元素。- beforeUpdate:数据发生变化,更新前执行的钩子函数,此时
DOM
还未重新渲染。- updated:数据发生变化,更新后执行的钩子函数,此时
DOM
已经更新完成。- beforeDestroy:实例销毁之前执行的钩子函数,此时实例仍然可以访问。
- destroyed:实例销毁之后执行的钩子函数,此时实例已经被完全销毁,无法再访问。
这些生命周期钩子函数可以通过在Vue
实例中定义相应的方法来使用,例如:
new Vue({
data: {
message: 'Hello, Vue.js!'
},
beforeCreate: function () {
console.log('beforeCreate')
},
created: function () {
console.log('created')
},
beforeMount: function () {
console.log('beforeMount')
},
mounted: function () {
console.log('mounted')
},
beforeUpdate: function () {
console.log('beforeUpdate')
},
updated: function () {
console.log('updated')
},
beforeDestroy: function () {
console.log('beforeDestroy')
},
destroyed: function () {
console.log('destroyed')
}
})
在实例化Vue
对象后,可以通过控制台查看相应的输出,以了解Vue
生命周期的具体执行过程。需要注意的是,在使用Vue
时,生命周期钩子函数是非常重要的,可以帮助我们更好地掌握Vue
的使用和优化技巧。同时,Vue
也提供了一些全局钩子函数,例如errorCaptured
等,用于捕获全局错误并进行处理。详细的生命周期钩子函数和用法可以参考Vue
的官方文档。
七、插件和组件
7.1 插件
Vue
插件是指可在Vue
应用程序中安装和使用的可重用组件、指令、过滤器、混入等功能性扩展。Vue
插件通过扩展Vue
实例来添加全局功能,从而使得多个组件可以共享相同的功能。
Vue
插件通常以npm
包的形式发布,并提供相应的文档和示例代码。Vue
官方提供了许多常用的插件,如Vue Router
、Vuex
、Vue CLI
等,也有许多社区开发的第三方插件,如Vue Material
、Vue-Chartjs
等。
安装Vue
插件通常需要使用Vue.js
的全局API Vue.use()
。在使用Vue.use()
时,需要传入一个插件对象,该对象可以包含一个install
方法,用于安装插件。例如:
// 安装一个名为 myPlugin 的插件
const myPlugin = {
install(Vue, options) {
// 在Vue实例上添加一个全局方法或属性
Vue.prototype.$myMethod = function () {
// ...
}
}
}
// 在Vue.js应用程序中使用插件
import Vue from 'vue'
import App from './App.vue'
Vue.use(myPlugin, { someOption: true })
new Vue({
render: h => h(App)
}).$mount('#app')
在上面的例子中,我们定义了一个名为myPlugin
的插件,并在Vue
应用程序中使用它。在安装插件时,我们还可以传递一些选项作为第二个参数。
使用插件后,我们可以在Vue
应用程序中的任何组件中使用Vue.prototype.$myMethod()
方法。
7.2 什么是组件
Vue
的组件是可复用的Vue
实例,它可以封装HTML
元素和 CSS
样式以及与之相关的JavaScript
行为。每个组件都有自己的作用域,因此它可以避免全局作用域中的命名冲突,并且可以方便地在不同的Vue
实例中重复使用。组件的结构包含模板、脚本和样式,这些可以分别定义在单独的文件中或在同一个文件中。
通过使用组件,可以将页面分解成多个独立的部分,每个部分都有自己的功能和状态,这样可以方便地组合和重用这些部分,从而提高开发效率和代码可维护性。在Vue.js
中,组件是构建大型应用程序的重要组成部分,它使开发人员可以将复杂的应用程序分解成更小的、可重用的组件。
Vue
的组件分为单文件组件和非单文件组件两种。
7.3 单文件组件
在Vue
中,单文件组件是一种将组件的 HTML
模板、JavaScript
代码和CSS
样式写在同一个文件中的方式。这种方式将组件的不同部分分离到不同的文件中,使得组件更易于管理、维护和阅读。
单文件组件通常以 .vue
扩展名的文件存在,包含三个部分:<template>
、<script>
和<style>
。<template>
部分定义组件的HTML
模板,<script>
部分定义组件的 JavaScript
代码,<style>
部分定义组件的CSS
样式。
单文件组件可以通过模块化的方式进行引用和导出,使得组件更容易组合和重用。此外,单文件组件还支持使用构建工具进行编译和打包,从而可以使用现代的开发工具和技术来提高开发效率和代码质量。
单文件组件是Vue
开发中的推荐方式,它可以使组件的开发和维护更加高效和可靠。当应用程序规模变大时,单文件组件也能更好地扩展和组织代码。
7.4 非单文件组件
在Vue
中,非单文件组件是一种将组件的HTML
模板、JavaScript
代码和CSS
样式写在同一个文件中的方式。这种方式不像单文件组件那样,将组件的不同部分分离到不同的文件中。
非单文件组件通常以.vue
扩展名的文件存在,并使用一个包含组件选项的JavaScript
对象来描述组件的行为和状态。这个对象可以包括一个 template
属性,用于定义组件的HTML
模板,一个script
属性,用于定义组件的JavaScript
代码,以及一个style
属性,用于定义组件的CSS
样式。
与单文件组件相比,非单文件组件的缺点是难以管理和维护,因为所有组件的不同部分都写在同一个文件中,这会导致代码变得更加复杂,不易于阅读和理解。此外,非单文件组件也不支持像单文件组件那样的构建工具的优化和开发体验。
虽然非单文件组件不是推荐的开发方式,但它仍然是一种有效的组件开发方式,尤其是在小型项目中。当应用程序规模变大时,应该考虑使用单文件组件来更好地管理和组织代码。
7.5 mixin混入
在Vue
中,mixin
是一种用于复用组件逻辑的机制。它允许将一些常见的逻辑和功能封装在一个mixin
对象中,并在多个组件中重复使用。
一个mixin
对象可以包含任何组件选项,例如data
、methods
、computed
、watch
等,这些选项将与组件自身的选项合并。如果mixin
对象和组件自身的选项中有同名的选项,将以组件自身的选项为准。例如,如果一个mixin
对象和一个组件都有一个名为created
的生命周期钩子函数,那么在组件实例化时,将先执行mixin
对象中的created
钩子函数,然后再执行组件自身的created
钩子函数。
使用mixin
非常简单,只需在组件中使用mixins
选项来声明要使用的mixin
对象即可,例如:
<template>
<div>{{ message }}</div>
</template>
<script>
const myMixin = {
data() {
return {
message: 'Hello from mixin!'
}
}
}
export default {
mixins: [myMixin],
// 组件自身的选项
}
</script>
在上面的例子中,我们定义了一个名为myMixin
的mixin
对象,它包含一个data
选项,用于向组件中注入一个message
属性。在组件中,通过mixins
选项将myMixin
对象添加到组件中,这样组件就可以使用myMixin
中定义的数据和方法。
需要注意的是,
mixin
的使用需要谨慎,因为它可以在多个组件中重复使用相同的代码逻辑,但同时也可能导致命名冲突、选项覆盖等问题。因此,建议在使用mixin
时,尽量将其用于封装通用的逻辑和功能,以减少对组件自身的影响。此外,如果需要对mixin
中的选项进行定制,可以通过组件自身的选项来覆盖mixin
中的选项。
7.6 scoped样式
在Vue
中,scoped
样式是一种在组件中使用的CSS
样式,可以确保只有该组件中的元素受到该样式的影响,而不会影响其他组件中的元素。
在Vue
组件中,可以通过在style
标签中添加scoped
属性来声明scoped
样式。例如:
<template>
<div class="my-component">
<h1>My Component</h1>
<p>This is a paragraph.</p>
</div>
</template>
<style scoped>
.my-component h1 {
color: red;
}
.my-component p {
font-size: 18px;
}
</style>
在上面的例子中,我们为组件的根元素.my-component
添加了scoped
样式,这意味着只有该组件中的h1
和p
元素会受到样式的影响。
当Vue
编译组件时,它会在样式的类名前添加一个唯一的标识符,以确保该样式只应用于该组件中的元素,而不会影响其他组件。
7.7 两个新的生命周期钩子
activated
和deactivated
是Vue 2.0
新增的生命周期钩子函数,用于组件被激活和失活时的处理。
当组件被切换为激活状态时(例如从一个包含该组件的父组件切换到另一个父组件),activated
钩子函数会被调用。这可以让开发者在组件激活时执行一些逻辑,比如向后端发送请求获取数据。
当组件被切换为非激活状态时(例如从该组件所在的父组件切换到其他页面),deactivated
钩子函数会被调用。这可以让开发者在组件失活时执行一些清理逻辑,比如取消当前组件的一些请求或动画效果。
需要注意的是,activated
和deactivated
钩子函数只在使用<keep-alive>
包裹的组件中才会生效。这是因为<keep-alive>
可以让Vue
在组件切换时将组件实例缓存下来,以便下次快速恢复组件状态,而activated
和deactivated
钩子函数就是用来处理组件被缓存和恢复时的逻辑。
八、脚手架
8.1 什么是脚手架
Vue CLI(Vue Command Line Interface)
是一个官方提供的Vue
脚手架工具,可以快速搭建Vue
项目的基础结构,并提供丰富的插件和功能来增强开发效率。
Vue CLI
基于Node.js
和Webpack
构建,支持生成包括单文件组件、路由、状态管理等在内的完整的Vue
项目骨架,同时还提供了开箱即用的开发服务器、热重载、代码分割、压缩、测试和构建等功能。此外,Vue CLI
还支持自定义配置和插件,可以根据不同项目的需求进行扩展和定制。
使用Vue CLI
可以大大加快Vue
项目的开发速度和提高代码质量,同时还可以提供一致性和标准化的项目结构和开发流程,方便多人协作和维护。总之,Vue CLI
是Vue
生态中非常重要的一个工具,也是学习和使用Vue
的必备工具之一。
8.2 脚手架安装步骤
方法一:
安装Vue CLI
需要先安装Node.js
,因为Vue CLI
是基于Node.js
构建的。
以下是安装Vue CLI
的步骤:
- 下载和安装
Node.js
(如果没有安装过):访问Node.js
官网 https://nodejs.org/en/download/,选择适合自己系统的版本下载并安装。 - 打开终端或命令行界面:在
Windows
上,可以使用PowerShell
或命令提示符;在macOS
和Linux
上,可以使用终端或控制台。 - 使用
npm
安装Vue CLI
:在终端或命令行界面中输入以下命令:
npm install -g @vue/cli
这会安装Vue CLI
最新的稳定版本。如果要安装特定的版本,可以使用以下命令:
npm install -g @vue/cli@<version>
- 等待安装完成:这可能需要一些时间,具体取决于你的网络速度和电脑性能。
- 验证安装结果:在终端或命令行界面中输入以下命令:
vue --version
如果看到类似 @vue/cli x.y.z
的版本号,说明安装成功。
方法二:
命令行界面中输入以下命令:
vue ui
进入图形化界面进行手动构建脚手架工具:
8.3 脚手架属性
8.3.1 ref属性
Vue
的 ref
属性是用来在Vue
组件中给元素或子组件注册一个引用标识符的属性。通过ref
属性,我们可以在Vue
组件中直接访问到被注册元素或子组件的实例,从而可以直接调用它们的属性或方法。
ref
属性可以用在以下场景中:
- 获取元素或组件的
DOM
节点,以便进行原生DOM
操作或使用第三方库。- 在父组件中直接调用子组件的方法或访问子组件的属性。
- 在父组件中通过
$refs
访问子组件实例。
示例:
<!-- 获取元素的引用 -->
<template>
<div>
<input type="text" ref="input">
</div>
</template>
<script>
export default {
mounted() {
const inputElement = this.$refs.input;
inputElement.focus();
},
};
</script>
需要注意的是,使用ref
属性来访问子组件实例的方式是不推荐的。因为这种方式会使父组件和子组件之间紧密耦合,违背了组件化开发的原则。正确的方式应该是通过props
和事件来进行父子组件之间的通信。
8.3.2 props属性
在Vue
中,props
属性是一种用于从父组件向子组件传递数据的方式。它允许父组件将数据作为props
属性传递给子组件,并在子组件中使用这些数据。在Vue
中,props
属性可以是任何JavaScript
原始值、对象或数组。
在父组件中,可以使用v-bind
指令来将数据绑定到子组件的props
属性上,例如:
<template>
<child-component :prop-name="parentData"></child-component>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
data() {
return {
parentData: 'data from parent component'
}
}
}
</script>
在子组件中,可以通过props
选项来声明接收哪些props
属性,并在模板或JavaScript
代码中使用它们,例如:
<template>
<div>{{ propName }}</div>
</template>
<script>
export default {
props: {
propName: {
type: String,
required: true
}
}
}
</script>
在上面的例子中,子组件声明了一个名为propName
的props
属性,它的类型为字符串,并且必须从父组件中传递。在子组件的模板中,可以使用propName
属性来显示从父组件传递过来的数据。
需要注意的是,
props
属性是单向数据流的,即父组件可以向子组件传递数据,但是子组件不能直接修改props
属性的值。如果需要修改props
属性的值,需要在父组件中进行修改,并通过事件机制通知子组件。
另外,在子组件中使用
props
属性时,不应该直接修改它的值,而是应该使用它的副本。这是因为在Vue
中,props
属性是响应式的,如果直接修改它的值,会触发警告并可能导致不可预期的行为。
九、组件通信
9.1 组件自定义事件
在Vue
中,组件可以通过自定义事件来实现组件之间的通信。自定义事件可以让一个组件触发一个事件,并向其他组件传递数据。以下是自定义事件的实现步骤:
- 在组件中定义一个事件名:可以在组件中使用
$emit
方法来触发一个自定义事件,并传递数据。例如:
// 在组件中定义一个事件名
<button @click="$emit('my-event', data)">Click me</button>
上面的代码定义了一个名为my-event
的自定义事件,并将data
数据传递给其他组件。
- 在父组件中监听该事件:可以在父组件中使用
v-on
或@
来监听一个自定义事件。例如:
// 在父组件中监听自定义事件
<my-component @my-event="handleEvent"></my-component>
上面的代码监听了my-event
事件,并将事件处理函数handleEvent
与该事件绑定。
- 在父组件中实现事件处理函数:当监听到自定义事件时,父组件会自动调用绑定的事件处理函数,并传递事件数据。例如:
// 在父组件中实现事件处理函数
methods: {
handleEvent(data) {
console.log(data)
}
}
上面的代码实现了handleEvent
事件处理函数,并在控制台中输出事件数据。
通过以上步骤,就可以在Vue
中实现组件之间的自定义事件。自定义事件可以让组件之间的通信更加灵活,方便数据传递和状态管理。
9.2 全局事件总线
在Vue
中,可以使用全局事件总线实现组件之间的通信。全局事件总线是一个Vue
实例,它充当一个中央事件处理器,可以让不同组件之间传递数据和通知。
以下是在Vue
中实现全局事件总线的步骤:
- 创建全局事件总线实例:在
Vue
实例化之前,可以先创建一个全局事件总线实例,并将其挂载到Vue
的原型上。例如:
import Vue from 'vue'
// 创建全局事件总线实例
const eventBus = new Vue()
// 将事件总线实例挂载到 Vue 的原型上
Vue.prototype.$eventBus = eventBus
- 在组件中使用事件总线:可以在组件中使用
$emit
方法来触发事件,并在事件总线上监听该事件。例如:
// 在组件中使用事件总线
this.$eventBus.$emit('my-event', data)
上面的代码触发了一个名为my-event
的事件,并将data
数据传递给事件总线。
- 在其他组件中监听事件:可以在其他组件中使用
$on
方法来监听事件总线上的事件。例如:
// 在其他组件中监听事件总线
this.$eventBus.$on('my-event', handleEvent)
上面的代码监听了my-event
事件,并将事件处理函数handleEvent
与该事件绑定。
- 在事件处理函数中处理数据:当事件触发时,事件总线会自动调用事件处理函数,并传递事件数据。例如:
// 在事件处理函数中处理数据
handleEvent(data) {
console.log(data)
}
上面的代码实现了handleEvent
事件处理函数,并在控制台中输出事件数据。
通过以上步骤,就可以在Vue
中实现全局事件总线,并实现组件之间的通信。全局事件总线可以让组件之间的通信更加灵活,方便数据传递和状态管理。需要注意的是,使用全局事件总线时要注意避免事件命名冲突和事件泄漏。
9.3 消息订阅与发布
在Vue
中,可以使用消息订阅与发布模式来实现组件之间的通信。这种模式是一种松耦合的通信方式,可以让组件之间不直接依赖彼此,通过中间件来进行通信。
以下是在Vue
中实现消息订阅与发布的步骤:
- 创建消息中心:可以使用一个空的
Vue
实例作为消息中心,也可以使用第三方库如mitt
来实现。例如:
import Vue from 'vue'
// 创建消息中心实例
export const eventBus = new Vue()
- 在组件中订阅消息:可以使用
eventBus.$on
方法来订阅消息,当消息被发布时,事件中心会自动调用相应的回调函数。例如:
// 在组件中订阅消息
eventBus.$on('my-event', handleEvent)
- 在组件中发布消息:可以使用
eventBus.$emit
方法来发布消息,将消息发送给订阅者。例如:
// 在组件中发布消息
eventBus.$emit('my-event', data)
上面的代码发布了一个名为my-event
的消息,并将data
数据传递给订阅者。
- 在事件处理函数中处理数据:当消息被发布时,事件中心会自动调用订阅该消息的回调函数,并传递消息数据。例如:
// 在事件处理函数中处理数据
function handleEvent(data) {
console.log(data)
}
上面的代码实现了handleEvent
事件处理函数,并在控制台中输出消息数据。
通过以上步骤,就可以在Vue
中实现消息订阅与发布,并实现组件之间的通信。消息订阅与发布模式可以让组件之间的通信更加灵活,方便数据传递和状态管理。需要注意的是,使用消息订阅与发布时要注意避免消息命名冲突和消息泄漏。
十、过渡与动画
在Vue
中,可以使用过渡和动画来实现页面元素的动态效果,如淡入淡出、滑动、旋转等。过渡是指在元素插入、更新或删除时添加动画效果,而动画是指在元素不断变化时持续添加动画效果。
以下是在Vue
中实现过渡和动画的步骤:
- 创建过渡或动画组件:可以使用
<transition>
或<transition-group>
组件来创建过渡效果,使用<transition>
或<animate>
标签来创建动画效果。例如:
<transition name="fade">
<!-- 插入或更新元素的内容 -->
</transition>
上面的代码使用了名为fade
的过渡效果来在元素插入或更新时添加动画效果。
<animate attributeName="opacity" from="0" to="1" dur="1s" repeatCount="indefinite"/>
上面的代码使用了一个简单的动画效果,将元素的不透明度从0到1变化,并在1秒内重复该变化。
- 定义过渡或动画的
CSS
样式:可以使用CSS
样式来定义过渡或动画效果的具体样式。例如:
/* 定义 fade 过渡效果的 CSS 样式 */
.fade-enter-active,
.fade-leave-active {
transition: opacity .5s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
上面的代码定义了fade
过渡效果的CSS
样式,包括元素插入和更新时的过渡效果(.fade-enter-active
),元素删除时的过渡效果(.fade-leave-active
),元素插入和更新时的开始状态(.fade-enter
)和元素删除时的结束状态(.fade-leave-to
)。
/* 定义动画效果的 CSS 样式 */
@keyframes slidein {
from {
transform: translateX(-100%);
}
to {
transform: translateX(0);
}
}
上面的代码定义了一个名为slidein
的动画效果,将元素从左侧滑入。
- 应用过渡或动画:要在
Vue
中应用过渡或动画效果,需要在组件中使用<transition>
或<transition-group>
组件来包裹需要添加动画的元素,并通过name
或type
属性来指定过渡或动画的名称。例如:
<template>
<div>
<transition name="fade">
<p v-if="show">Hello, Vue!</p>
</transition>
</div>
</template>
上面的代码使用了名为fade
的过渡效果来实现元素的淡入淡出效果<transition>
组件的name
属性指定了过渡的名称,而包裹在其中的<p>
元素则使用v-if
指令来控制其显示与隐藏。
如果要应用动画效果,则可以使用<animate>
标签,将需要添加动画的元素的动画效果直接定义在标签内,如下所示:
<template>
<div>
<h1>Vue Animation Example</h1>
<animate attributeName="opacity" from="0" to="1" dur="1s" repeatCount="indefinite">
<circle cx="50" cy="50" r="40" fill="blue" />
</animate>
</div>
</template>
上面的代码定义了一个简单的动画效果,将 <circle>
元素的不透明度从 0 到 1 变化,并在 1 秒内重复该变化。
- 定义过渡或动画的 CSS 样式
要实现过渡或动画效果,需要定义相应的 CSS 样式,以指定元素在过渡或动画中的状态。对于过渡效果,通常需要定义以下四个样式类:
v-enter
: 元素进入过渡的起始状态。v-enter-active
: 元素进入过渡的结束状态。v-leave
: 元素离开过渡的起始状态。v-leave-active
: 元素离开过渡的结束状态。
例如,下面的 CSS 样式定义了一个渐变的过渡效果:
.fade-enter-from, .fade-leave-to {
opacity: 0;
}
.fade-enter-active, .fade-leave-active {
transition: opacity 0.5s;
}
.fade-enter-to, .fade-leave-from {
opacity: 1;
}
对于动画效果,需要定义动画的关键帧和动画属性:
@keyframes slidein {
from {
margin-left: 100%;
width: 300%;
}
to {
margin-left: 0%;
width: 100%;
}
}
.circle {
animation: slidein 1s infinite;
}
上面的代码定义了一个滑动动画效果,通过@keyframes
定义了动画的关键帧,通过animation
属性将其绑定到了.circle
元素上。
-
绑定
CSS
样式:在Vue
中,我们可以通过以下方式将定义好的CSS
样式与组件绑定起来:- 对于过渡效果,在
<transition>
或<transition-group>
组件上使用name
属性来指定过渡效果的名称,并使用CSS
类名来绑定不同阶段的样式,例如:
<transition name="fade"> <p v-if="show">Hello, Vue!</p> </transition>
- 对于动画效果,可以在需要添加动画的元素上使用
class
或:class
属性来绑定CSS
类名,例如:
<circle class="circle" cx="50" cy="50" r="40" fill="blue" />
上面的代码将
circle
类名绑定到了<circle>
元素上,从而实现了滑动动画效果。 - 对于过渡效果,在
-
结束过渡或动画:在过渡或动画结束时,通常需要执行一些操作,例如将过渡或动画元素从
DOM
中移除或者将其样式重置为默认值等。Vue
提供了多种方式来监听过渡或动画结束事件,包括:
- 在
<transition>
或<transition-group>
组件上使用@enter
,@enter-to
,@leave
和@leave-to
等事件来监听过渡的不同阶段,例如:<transition @enter="onEnter" @leave="onLeave"> <p v-if="show">Hello, Vue!</p> </transition>
在上面的代码中,
@enter
和@leave
分别表示过渡进入和离开的阶段,我们可以在组件中定义对应的方法onEnter
和onLeave
来处理相应的操作。
- 在动画元素上使用
animationend
或transitionend
事件来监听动画或过渡结束事件,例如:<circle class="circle" cx="50" cy="50" r="40" fill="blue" @animationend="onAnimationEnd" />
在上面的代码中,@animationend
事件表示动画结束事件,我们可以在组件中定义onAnimationEnd
方法来处理相应的操作。
在处理过渡或动画结束事件时,我们通常需要使用this
关键字来访问组件实例,例如:
methods: {
onEnter() {
console.log('enter')
console.log(this) // 访问组件实例
},
onLeave() {
console.log('leave')
console.log(this) // 访问组件实例
},
onAnimationEnd() {
console.log('animation end')
console.log(this) // 访问组件实例
}
}
通过以上的方法,我们就可以很方便地实现过渡和动画的效果,并在相应的事件中处理结束时的操作。
十一、 axios
11.1 概述
Axios
是一个流行的基于Promise
的HTTP
客户端,用于在浏览器和Node
中发送HTTP
请求。它可以用于处理各种请求类型,例如GET
,POST
等。Axios
可以很容易地与现代前端框架和库集成,例如React
,Vue
等。
Axios的特点:
- 支持
Promise API
- 支持请求取消
- 支持客户端防止
CSRF
- 支持浏览器和
Node
- 自动转换
JSON
数据- 支持拦截器,在请求或响应被处理前拦截和修改它们
- 支持设置默认的请求配置
11.2 axios语法
Axios
提供了一个简单的API
,用于发送各种类型的HTTP
请求,Axios
的语法相对简单,可以通过创建一个Axios
实例并使用其方法来发送HTTP
请求。
首先需要在项目中引入Axios
库:
import axios from 'axios';
axios
请求示例:
不携带参数的示例:
axios.get('/api/data').then(response => { console.log(response.data); }).catch(error => { console.log(error); });
携带参数的示例:
axios.post('/api/data', { name: 'John Doe', email: 'john.doe@example.com' }).then(response => { console.log(response.data); }).catch(error => { console.log(error); });
Axios
支持的HTTP
请求类型有以下几种:
- GET:一般用于获取数据;
- POST:一般用于提交数据;
- PUT:一般用于更新数据;
- DELETE:一般用于删除数据;
- HEAD:一般用于获取资源的头部信息;
- OPTIONS:一般用于获取资源支持的请求方式;
- PATCH:一般用于更新部分数据;
11.3 并发请求和请求拦截器:
Axios
提供了axios.all
和axios.spread
方法来支持并发请求。我们可以使用axios.all
方法一次性发送多个请求,返回一个包含所有响应结果的数组,也可以使用axios.spread
方法将多个响应结果解构为多个参数,方便使用。
例如:
axios.all([
axios.get('/api/user'),
axios.get('/api/posts')
]).then(axios.spread((userRes, postsRes) => {
console.log(userRes.data);
console.log(postsRes.data);
})).catch(error => {
console.log(error);
});
Axios
提供了axios.interceptors.request
属性来实现请求拦截器。我们可以使用这个属性来注册一个拦截器,在请求发送前对请求进行拦截和修改。
例如,我们可以在请求头中添加Token
来进行身份认证,代码如下:
axios.interceptors.request.use(config => {
const token = localStorage.getItem('token');
if (token) {
config.headers['Authorization'] = `Bearer ${token}`;
}
return config;
}, error => {
return Promise.reject(error);
});
11.4 axios的参数
Axios
的各种方法中,具体的参数数量和类型会根据不同的请求类型和需要传递的数据而有所不同,但通常包括以下参数:
- URL:请求的URL地址,可以是相对路径或者绝对路径。
- Data:请求体中的数据,用于POST、PUT等请求。
- Config:用于设置请求的一些配置,如请求头、超时时间、认证等。
- CancelToken:用于取消请求。
- OnUploadProgress:用于监听上传进度的回调函数。
- OnDownloadProgress:用于监听下载进度的回调函数。
这些参数都是可选的,具体是否需要取决于我们发送请求的需求。例如,发送一个简单的GET
请求只需要URL
参数,而POST
请求还需要Data
参数,另外还可以设置Config
参数来控制请求的一些细节。
需要注意的是,在使用Axios
发送请求时,一些参数是可以通过默认配置来设置的,如baseURL
、headers
等。如果请求中需要的参数在默认配置中已经设置,我们不需要在每个请求中都重复设置,可以直接使用默认配置。
十二、配置代理服务器
12.1 为什么配置代理服务器
Vue
项目中配置代理服务器是为了解决跨域请求的问题。
- 当
Vue
应用程序向不同的域名或端口发出请求时,由于浏览器的安全限制,会导致请求失败,这就是跨域请求问题。例如,在开发阶段,我们可能会将Vue
应用程序部署在本地的开发服务器上,而API
服务则部署在远程的服务器上,这就可能导致跨域请求问题。 - 配置代理服务器可以解决这个问题,代理服务器可以将
Vue
应用程序发出的请求转发到目标服务器上,然后将目标服务器返回的响应转发回Vue
应用程序。在这个过程中,代理服务器会伪装成目标服务器,浏览器会认为请求是发给同一域名和端口的服务器,因此不会出现跨域请求问题。 - 配置代理服务器也有助于开发和调试,我们可以在代理服务器中添加一些拦截和转换逻辑,方便在开发过程中调试和测试。同时,代理服务器还可以用于在测试环境中模拟目标服务器的行为,方便测试和验收。
12.2 如何配置
在Vue
项目中配置代理服务器可以使用vue.config.js
文件来实现。下面是具体的步骤:
- 在
Vue
项目的根目录下创建一个名为vue.config.js
的文件。 - 在
vue.config.js
文件中添加如下代码:
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:3000', // 设置代理目标
changeOrigin: true, // 开启跨域
pathRewrite: {
'^/api': '' // 重写路径,去掉/api前缀
}
}
}
}
};
在上面的代码中,我们使用module.exports
导出了一个对象,其中包含了devServer
属性,这个属性表示开发服务器的配置。在devServer
中,我们又添加了一个名为proxy
的属性,它是一个对象,用于配置代理服务器。我们使用'/api'
作为键,表示需要代理的路径,target
属性表示代理的目标服务器,changeOrigin
属性开启跨域,pathRewrite
属性用于重写路径,将路径中的'/api'
前缀去掉。
- 在完成以上配置后,我们可以使用如下代码来发送请求:
axios.get('/api/data').then(response => {
console.log(response.data);
}).catch(error => {
console.log(error);
});
在上面的代码中,我们发送了一个GET
请求,请求的URL
为/api/data
,由于/api
前缀被重写去掉了,因此实际发送的请求URL
为http://localhost:3000/data
,这个请求会被代理到目标服务器上。
十三、插槽
Vue
中的插槽是一种高级组件技术,用于将父组件的内容插入到子组件中,实现组件间的灵活组合。插槽可以用来代替Vue
中的传递props
属性和使用emit
事件,使得组件之间的关系更加简洁和易于维护。
13.1 默认插槽
默认插槽是Vue
中插槽的一种类型,用于将父组件中的内容插入到子组件中。默认插槽是最简单的一种插槽,它不需要任何名称或参数,只需要在子组件中使用<slot>
元素即可。
使用默认插槽的方式非常简单,只需要在父组件中使用子组件标签包含需要插入到子组件中的内容,就可以将这些内容插入到子组件的默认插槽中。例如,下面是一个使用默认插槽的示例:
<!-- 父组件中的模板 -->
<template>
<div>
<h2>{{title}}</h2>
<slot></slot>
</div>
</template>
在上面的代码中,父组件中包含一个默认插槽,使用<slot>
元素表示。在父组件中,我们可以使用子组件标签包含需要插入到子组件中的内容,例如:
<my-component title="Title">
<p>Content</p>
</my-component>
在上面的代码中,父组件使用<my-component>
标签包含一个<p>
标签,在子组件中,这个<p>
标签将被插入到默认插槽中。
在子组件中,可以像访问普通插槽一样访问默认插槽中的内容,例如:
<!-- 子组件中的模板 -->
<template>
<div>
<h3>{{subtitle}}</h3>
<slot></slot>
</div>
</template>
在上面的代码中,子组件中也包含一个默认插槽,使用<slot>
元素表示。子组件中的这个默认插槽将包含父组件传递进来的内容。在子组件中,我们可以通过<slot>
元素来访问这个默认插槽,例如使用v-for
指令对插入的内容进行遍历:
<my-component title="Title">
<p v-for="(item, index) in items" :key="index">{{item}}</p>
</my-component>
在上面的代码中,父组件使用v-for
指令生成了多个<p>
标签,这些标签将被插入到子组件的默认插槽中,然后在子组件中使用<slot>
元素和v-for
指令对这些标签进行遍历。这样就可以方便地将父组件中的内容插入到子组件中,并进行灵活的组合和处理。
13.2 具名插槽
除了默认插槽外,Vue
中还支持一种叫做具名插槽的插槽类型。具名插槽可以给插槽命名,允许父组件向子组件中的不同插槽插入不同的内容,从而更灵活地组合和使用组件。
使用具名插槽需要在子组件中使用<slot>
元素并添加name
属性,表示这是一个具名插槽。例如,下面是一个使用具名插槽的示例:
<!-- 父组件中的模板 -->
<template>
<div>
<h2>{{title}}</h2>
<slot name="content"></slot>
<slot name="footer"></slot>
</div>
</template>
在上面的代码中,父组件中包含两个具名插槽,分别命名为content
和footer
,使用<slot>
元素和name
属性表示。在父组件中,我们可以使用<template>
元素来包含需要插入到这些具名插槽中的内容,例如:
<my-component title="Title">
<template v-slot:content>
<p>Content</p>
</template>
<template v-slot:footer>
<button>OK</button>
<button>Cancel</button>
</template>
</my-component>
在上面的代码中,我们使用<template>
元素来包含需要插入到具名插槽中的内容,并使用v-slot
指令来指定插入到哪个具名插槽中。在上面的示例中,<p>
标签将被插入到名为content
的具名插槽中,而两个<button>
标签将被插入到名为footer
的具名插槽中。
在子组件中,可以通过<slot>
元素的name
属性来访问具名插槽中的内容,例如:
<!-- 子组件中的模板 -->
<template>
<div>
<h3>{{subtitle}}</h3>
<slot name="content"></slot>
<hr>
<slot name="footer"></slot>
</div>
</template>
在上面的代码中,子组件中也包含两个具名插槽,分别命名为content
和footer
。在子组件中,我们可以使用<slot>
元素的name
属性来访问这些具名插槽,例如<slot name="content"></slot>
表示访问名为content
的具名插槽。
使用具名插槽可以让组件更加灵活和可重用,通过将不同的内容插入到不同的具名插槽中,可以轻松组合和定制不同的UI效果。
13.3 作用域插槽
作用域插槽是Vue
中一种特殊的插槽类型,它可以让父组件向子组件中传递数据,从而实现更灵活的组件组合。
作用域插槽通过将数据传递给子组件来工作。在父组件中,我们可以使用<template>
元素和v-slot
指令来定义作用域插槽,例如:
<!-- 父组件中的模板 -->
<template>
<div>
<my-component>
<template v-slot:default="slotProps">
<p>{{slotProps.text}}</p>
</template>
</my-component>
</div>
</template>
在上面的代码中,我们使用<template>
元素和v-slot
指令来定义一个名为default
的作用域插槽,并将其传递给名为my-component
的子组件。在作用域插槽中,我们可以使用slotProps
参数来访问父组件传递过来的数据。
在子组件中,我们可以通过<slot>
元素的name
属性来定义作用域插槽,并通过v-bind
指令将数据传递给插槽。例如:
<!-- 子组件中的模板 -->
<template>
<div>
<slot :text="message"></slot>
</div>
</template>
<script>
export default {
data() {
return {
message: 'Hello world!'
};
}
}
</script>
在上面的代码中,我们使用<slot>
元素的name
属性来定义一个名为default
的作用域插槽,并通过v-bind
指令将数据传递给插槽。在子组件中,我们可以通过this.$slots.default({text: this.message})
来访问作用域插槽,并将message
属性的值传递给父组件。
通过使用作用域插槽,我们可以轻松地向子组件中传递数据,并在子组件中使用这些数据来定制UI
效果。这种方法可以让组件更加灵活和可重用,让父组件和子组件之间的通信变得更加简单和直接。
十四、VueX
14.1 什么是vuex
Vuex
是一个专门为Vue
应用程序设计的状态管理库。在Vue
应用程序中,通常会有多个组件共享同一个状态,而Vuex
可以帮助你管理这些状态,并且使得状态的管理变得更加简单、高效。
Vuex
采用了集中式存储管理的方式,将应用程序的状态存储在一个全局的存储器中。这个存储器可以被所有组件访问,并且提供了一些用于操作状态的API
。通过这些API
,我们可以对状态进行读取、修改、监听等操作。
在Vuex
中,状态是响应式的,也就是说,当状态发生变化时,所有依赖于这个状态的组件都会自动更新。因此,Vuex
可以很好地帮助我们实现组件之间的通信和协作。
14.2 vuex的属性
Vuex
是一个状态管理库,它为Vue
应用程序提供了集中式存储管理。Vuex
的核心是store
对象,store
对象包含着应用程序的状态和状态变更的方法。
store
对象具有以下属性:
state
:存储状态数据的对象,类似于组件中的data
属性。state
的属性值可以通过store.state.xxx
访问。getters
:类似于计算属性,从store
的state
中派生出一些状态,供组件使用。getters
的属性值可以通过store.getters.xxx
访问。mutations
:修改 state 中数据的方法,不支持异步操作。mutations
的属性值可以通过store.commit('mutationName', payload)
触发。actions
:类似于mutations
,但支持异步操作,通过提交mutations
来修改state
。actions
的属性值可以通过store.dispatch('actionName', payload)
触发。modules
:允许将store
拆分成模块化的代码结构,每个模块拥有自己的state
、mutations
、getters
、actions
。每个模块可以通过命名空间来隔离自己的状态和操作。
除了上述属性,还有一些辅助属性和方法,如:
strict
:用于开启严格模式,禁止直接修改state
。启用严格模式后,只能通过mutations
来修改state
。replaceState
:用于替换store
中的state
。subscribe
:用于订阅store
中的mutation
。当mutation
被触发时,订阅函数会被调用。watch
:用于监听store
中的state
或getters
的变化。当监听的值发生变化时,回调函数会被调用。
Vuex
的属性提供了一种集中式的状态管理方式,能够方便地管理应用程序的状态,提高开发效率。
14.3 如何安装并使用vuex
安装Vuex
的步骤如下:
- 在项目中安装
Vuex
:npm install vuex --save
- 在
Vue
应用程序中引入Vuex
:import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex)
- 创建一个
Vuex
的store
对象:const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment(state) { state.count++ } }, actions: { increment(context) { context.commit('increment') } }, getters: { doubleCount(state) { return state.count * 2 } } })
以上代码创建了一个简单的
Vuex store
对象,其中包含了一个state
对象、一个mutation
和一个action
方法以及一个getter
方法。
- 将
store
对象注入到Vue
应用程序中:new Vue({ el: '#app', store, // ... 其他选项 })
现在,
Vuex
已经成功安装并配置完成。您可以在Vue
应用程序中通过以下方式使用Vuex
:
- 通过
this.$store.state.xxx
访问state
中的数据;- 通过
this.$store.commit('mutationName', payload)
触发mutation
;- 通过
this.$store.dispatch('actionName', payload)
触发action
;- 通过
this.$store.getters.xxx
访问getter
中的数据。例如,在
Vue
组件中使用Vuex
:<template> <div> <p>Count: {{ count }}</p> <p>Double Count: {{ doubleCount }}</p> <button @click="incrementCount">Increment</button> </div> </template> <script> export default { computed: { count() { return this.$store.state.count }, doubleCount() { return this.$store.getters.doubleCount } }, methods: { incrementCount() { this.$store.dispatch('increment') } } } </script>
以上示例代码展示了如何在 Vue 组件中访问 Vuex 中的数据和方法。
十五、路由(router)
15.1 什么是路由
在Vue.js
中,路由(router)是用于构建单页应用程序的核心功能之一,它通过管理应用程序中的不同URL
地址来使用户界面变得动态和交互性。Vue
路由可以帮助您构建具有多个页面的单页应用程序,并且可以使用浏览器的前进和后退按钮来更改URL
路径而不刷新页面。
Vue
路由是通过Vue Router
插件来实现的。Vue Router
是一个官方支持的插件,它提供了一组API
来定义路由、配置路由参数以及导航路由等功能。
15.2 Vue Router的基本使用
Vue Router
的基本使用步骤:
- 安装
Vue Router
:可以使用npm
或yarn
等包管理器来安装Vue Router
。
例如,使用npm
安装:
npm install vue-router --save
- 定义路由:在定义路由时,您需要创建一个
Vue Router
实例并定义应用程序的不同页面和相应的URL
路径。
例如:
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: About
}
]
const router = new VueRouter({
routes
})
export default router
在这个例子中,我们定义了两个路由,一个是首页(/
),另一个是关于页面(/about
)。每个路由都有一个name
和一个component
,name
用于在导航中标识路由,component
是与该路由对应的组件。
- 挂载路由:接下来,需要将路由实例挂载到
Vue
实例中。
例如:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
new Vue({
el: '#app',
router,
render: h => h(App)
})
在这个例子中,我们将路由实例router
传递给Vue
实例的router
选项,使Vue
能够使用它来管理页面和导航。
- 使用路由:可以在组件中使用路由
例如使用router-link
组件来创建导航链接:
<router-link to="/">Home</router-link>
<router-link to="/about">About</router-link>
或者使用编程式导航来实现在组件之间进行导航:
// 通过 $router.push() 进行编程式导航
this.$router.push('/')
通过这些基本的步骤,可以使用Vue Router
来实现单页应用程序的路由功能,并创建动态和交互式的用户界面。
15.3 参数和属性
Vue Router
在定义路由时支持多个参数和属性,下面是一些常用的参数和属性:
- path:指定路由的 URL 路径。
- name:用于在导航中标识路由的名称。
- component:指定与该路由对应的组件。
- redirect:重定向路由。
- alias:为路由设置别名。
- meta:用于存储路由的元信息,例如页面标题、是否需要鉴权等。
- children:定义嵌套的子路由。
下面是一个示例代码,演示了如何使用这些参数和属性来定义路由:
const routes = [
{
path: '/',
name: 'home',
component: Home,
meta: {
title: '首页'
}
},
{
path: '/about',
name: 'about',
component: About,
meta: {
title: '关于我们'
}
},
{
path: '/user/:id',
name: 'user',
component: User,
props: true
},
{
path: '/dashboard',
name: 'dashboard',
component: Dashboard,
meta: {
requiresAuth: true
}
},
{
path: '/redirect',
redirect: '/'
},
{
path: '/alias',
component: Alias,
alias: '/alias-page'
},
{
path: '/parent',
component: Parent,
children: [
{
path: 'child',
component: Child
}
]
}
]
在上面的代码中,我们定义了多个路由,其中:
/
路由指定了路由名称、组件和元信息;/about
路由指定了路由名称、组件和元信息;/user/:id
路由使用了动态路由参数:id
并且启用了路由参数传递到组件中;/dashboard
路由指定了需要进行鉴权,即需要登录才能访问的元信息;/redirect
路由指定了重定向到根路由/
;/alias
路由使用了别名/alias-page
;/parent
路由定义了嵌套的子路由/parent/child
。
这些参数和属性可以让您定义更加灵活和复杂的路由,从而实现更加丰富的单页应用程序。
15.4 参数传递
在Vue Router
中,有三种主要的参数传递方式:query
、params
和props
。
- Query 参数
query
参数是一种将数据添加到URL
中的方式,以?key=value
的形式添加到 URL 的末尾。query
参数可以通过$route.query
访问,在组件中使用时,可以通过$route
对象来访问,例如:
<template>
<div>
<p>ID: {{ $route.query.id }}</p>
</div>
</template>
- Params 参数
params
参数是一种将数据添加到 URL 路径中的方式,以 /key/value
的形式添加到 URL 的末尾。params
参数可以通过 $route.params
访问,在组件中使用时,可以通过 $route
对象来访问,例如:
<template>
<div>
<p>ID: {{ $route.params.id }}</p>
</div>
</template>
注意,要在路由定义中使用 params
参数,需要在路由路径中使用冒号 :
来标识参数名,例如:
const routes = [
{
path: '/user/:id',
name: 'User',
component: User
}
]
- Props 参数
props
参数是一种将数据从父组件传递到子组件的方式。在路由定义中,可以使用 props
参数来将 $route
对象中的数据传递给组件的 props
属性;
使用props
的方式有两种:
- 布尔模式:设置为
true
,该路由组件会将路由参数作为属性传递给组件,例如:const router = new VueRouter({ routes: [ { path: '/user/:id', component: User, props: true } ] })
在这种情况下,当你访问
/user/123
时,User
组件会接收到一个props
对象,其中包含了id
属性,即{ id: 123 }
。
- 对象模式:在
props
中指定具体的属性和值,例如:const router = new VueRouter({ routes: [ { path: '/user/:id', component: User, props: { default: true, color: 'red' } } ] })
在这种情况下,当你访问
/user/123
时,User
组件会接收到一个props
对象,其中包含了id
属性和color
属性,即{ id: 123, color: 'red' }
。
15.5 路由守卫
Vue
路由守卫是指在Vue Router
路由切换过程中执行的一系列钩子函数,用于控制路由跳转、执行异步操作、检查用户权限等等。
Vue Router
提供了全局守卫和路由独享守卫两种类型的路由守卫:
- 全局守卫:应用于整个应用程序的路由切换过程,可以用来控制所有路由跳转。全局守卫包括:
beforeEach(to, from, next)
:在路由切换之前执行,可以用来检查用户权限、执行异步操作等。如果需要进入下一个路由,则需要调用next()
方法,否则可以传递一个参数,如next(false)
,阻止路由跳转。afterEach(to, from)
:在路由切换之后执行,可以用来记录路由历史、统计页面访问量等。beforeResolve(to, from, next)
:在所有异步路由组件被解析之后执行,可以用来确保异步组件已经被加载并准备好渲染。
路由独享守卫:只应用于某个具体的路由或路由组件。路由独享守卫包括:
beforeEnter(to, from, next)
:在某个路由被匹配到之前执行,可以用来检查用户权限、执行异步操作等。如果需要进入该路由,则需要调用next()
方法,否则可以传递一个参数,如next(false)
,阻止路由跳转。- 组件内的守卫:在组件内部通过
beforeRouteEnter
、beforeRouteUpdate
和beforeRouteLeave
来定义。这些钩子函数可以用来控制组件内部的路由跳转、执行异步操作等。
需要注意的是,路由守卫是通过链式调用来实现的,如果其中一个守卫阻止了路由跳转,则后面的守卫将不再执行。另外,路由守卫可以通过next()
方法传递一个路径对象,实现路由跳转到其他路径。
Vue Router
允许在组件内部使用路由守卫来控制组件的路由跳转、执行异步操作等。组件内路由守卫包括:
beforeRouteEnter(to, from, next)
:在组件路由被激活之前执行,此时组件实例还未被创建,因此无法通过this
访问组件实例。可以通过next(vm => {})
传递一个回调函数,在组件实例创建之后执行一些逻辑,如获取组件数据。beforeRouteUpdate(to, from, next)
:在组件路由更新时执行,可以用来检查路由参数的变化,执行一些异步操作等。beforeRouteLeave(to, from, next)
:在组件路由被离开时执行,可以用来询问用户是否要保存未保存的数据、执行一些清理操作等。
这些组件内路由守卫可以在组件的生命周期钩子函数中定义,如下所示:
export default {
beforeRouteEnter(to, from, next) {
// 在组件实例创建之前执行
next(vm => {
// 在组件实例创建之后执行
})
},
beforeRouteUpdate(to, from, next) {
// 在组件路由更新时执行
next()
},
beforeRouteLeave(to, from, next) {
// 在组件路由被离开时执行
next()
}
}
需要注意的是,组件内路由守卫只在路由跳转到该组件时才会执行,如果是通过该组件内部的代码调用router.push()
、router.replace()
等方法进行路由跳转,则不会触发组件内的路由守卫。
15.6 路由管理方式
Vue提供了两种主要的路由管理方式:history模式和hash模式。
- hash模式
在
Vue
的hash
模式下,应用程序的URL
包含一个#
符号,后面跟着一个路径。在这种模式下,前端路由器使用浏览器的锚点来管理应用程序的URL
。当用户在应用程序中导航时,页面会自动更新,但URL
路径不会随之改变。这种模式不需要服务器端配置,因为hash
符号后面的路径不会发送给服务器端。
- history模式
在
Vue
的history
模式下,应用程序的URL
看起来像普通的网站链接,不包含#
符号。在这种模式下,前端路由器使用HTML5 History API
来管理应用程序的URL
。当用户在应用程序中导航时,页面会自动更新,并且URL
路径也会随之改变。然而,需要服务器端配置支持,以确保用户可以在浏览器中输入URL
直接访问应用程序的页面。