基础
组件化和mvvm
MVVM
Model
模型,JavaScript对象
View
视图,文档模型Dom,即UI界面
ViewModel
Vue实例对象

视图当中的Dom是可以监听到模型当中属性的变化, 反之,模型当中的属性更新也会对绑定到视图中的Dom做一个更新。
生命周期
- 钩子函数(Hook)在Vue中是一种事件劫持机制。
- 它会比定义的事件更早进行执行出来,而且还可以自定义去配置。
钩子 | 描述 |
---|---|
beforeCreate | 实例创建前状态,el和data均为undefined |
created | 实例创建完成,el为undefined,data有数据 |
beforeMount | 挂载前状态,el为undefined,data有数据 |
mounted | 挂载完成,el和data均有对应数据 |
beforeUpdate | 数据更新前,data里面属性值改变(更新后的数据) |
updated | 数据更新后,data里面属性值改变(更新后的数据) |
beforeDestroy | 销毁前 |
destroyed | 销毁完成 |

图片来自vue官网
嵌套组件的生命周期
子组件先插入,先完成patch及insert,父组件后插入
father
beforeCreate father created father beforeMount child beforeCreatechild createdchild beforeMountchild mounted father mounted
watch和computed的区别
自动调用相关的函数去实现数据的变动。
- watch
类似于监听机制 + 事件机制
watch: {
fullName: function (val) {
this.firstName + val
}
}
watch: {
fullName: function (val) {
this.firstName + val
}
}
- computed
计算属性,是data对象里的数据属性使用方式是一致的。
computed: {
fullName: function () {
return this.firstName + this.lastName
}
}
computed: {
fullName: function () {
return this.firstName + this.lastName
}
}
watch和computed的使用
- watch
用于观察和监听页面上的Vue实例。
如果说要在数据变化时,去进行异步操作,或者是进行大开销数据操作,就可以使用watch操作。
- computed
当页面中某些数据依赖其他数据进行变动的时候,可以使用计算属性。
存在缓存问题,当computed
里面不依赖其他数据的时候,computed
里面的数据只会记录第一次记录的值。
组件
创建组件
组件注册
组件传值
- props
- $emit,$on
- provide,inject
- $children,$parent,$refs
- $attrs,$listeners
- slot
- eventBus
- Vuex
修饰符
事件修饰符
修饰符 | 用法 |
---|---|
.stop | 阻止事件冒泡 |
.capture | 捕获型事件执行 |
.once | 只出发一次 |
.self | 只在该元素本身执行(并非子元素)触发时触发回调 |
.prevent | 阻止默认事件,比如表单提交的页面重载 |
<!-- 阻止单击事件继续传播 -->
<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>
<!-- 点击事件将只会触发一次 -->
<a v-on:click.once="doThis"></a>
<!-- 阻止单击事件继续传播 -->
<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>
<!-- 点击事件将只会触发一次 -->
<a v-on:click.once="doThis"></a>
对于项目中,嵌套事件出现同时触发的情况,可以通过下面两种方式来解决:
- 1.给父元素添加
.self
修饰符,也就是说只有自己触发的才有效: - 2.给子元素添加
.stop
修饰符,阻止事件冒泡,也就不会触发父元素的事件回调。
按键修饰符
在监听键盘事件时,我们经常需要检查详细的按键。
Vue 允许为v-on
在监听键盘事件时添加按键修饰符:
<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input v-on:keyup.enter="submit">
<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input v-on:keyup.enter="submit">
使用 keyCode
attribute 也是允许的:
<input v-on:keyup.13="submit">
<input v-on:keyup.13="submit">
为了在必要的情况下支持旧浏览器,Vue 提供了绝大多数常用的按键码的别名:
.enter
.tab
.delete
(捕获“删除”和“退格”键).esc
.space
.up
.down
.left
.right
v-model修饰符
<!-- 在“change”时而非“input”时更新 -->
<input v-model.lazy="msg">
<!-- 输入值转为数值类型 -->
<input v-model.number="age" type="number">
<!-- 过滤用户输入的首尾空白字符 -->
<input v-model.trim="msg">
<!-- 在“change”时而非“input”时更新 -->
<input v-model.lazy="msg">
<!-- 输入值转为数值类型 -->
<input v-model.number="age" type="number">
<!-- 过滤用户输入的首尾空白字符 -->
<input v-model.trim="msg">
Vue过度动画
Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果。包括以下工具:
在 CSS 过渡和动画中自动应用 class
可以配合使用第三方 CSS 动画库,如 Animate.css
在过渡钩子函数中使用 JavaScript 直接操作 DOM
可以配合使用第三方 JavaScript 动画库,如 Velocity.js
Vue在插入、更新或者删除Dom时,提供多种不同方式的应用过度效果。
Vue提供了内置的过度封装组件,该组件用于包裹要实现过度效果的组件。
过度的类名
在进入/离开的过渡中,会有 6 个 class 切换。
1、v-enter
:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。
2、v-enter-active
:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。
这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。
3、v-enter-to
:2.1.8 版及以上定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter 被移除),在过渡/动画完成之后移除。
4、v-leave
:定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。
5、v-leave-active
:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。
这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
5、v-leave-to
:2.1.8 版及以上定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除。
钩子函数
<transition
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:after-enter="afterEnter"
v-on:enter-cancelled="enterCancelled"
v-on:before-leave="beforeLeave"
v-on:leave="leave"
v-on:after-leave="afterLeave"
v-on:leave-cancelled="leaveCancelled"
>
<!-- ... -->
</transition>
<transition
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:after-enter="afterEnter"
v-on:enter-cancelled="enterCancelled"
v-on:before-leave="beforeLeave"
v-on:leave="leave"
v-on:after-leave="afterLeave"
v-on:leave-cancelled="leaveCancelled"
>
<!-- ... -->
</transition>
这些钩子函数可以结合 CSS transitions/animations
使用,也可以单独使用。
当只用 JavaScript 过渡的时候,在 enter
和 leave
中必须使用 done
进行回调。否则,它们将被同步调用,过渡会立即完成。
推荐对于仅使用 JavaScript 过渡的元素添加 v-bind:css="false"
,Vue 会跳过 CSS 的检测。这也可以避免过渡过程中 CSS 的影响。
路由
Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。包含的功能有:
- 嵌套的路由/视图表
- 模块化的、基于组件的路由配置
- 路由参数、查询、通配符
- 基于 Vue.js 过渡系统的视图过渡效果
- 细粒度的导航控制
- 带有自动激活的 CSS class 的链接
- HTML5 历史模式或 hash 模式,在 IE9 中自动降级
- 自定义的滚动条行为
const User = {
// 获取参数
template: '<div>User {{$route.params.id}}</div>'
}
const router = new VueRouter({
routes: [
// 动态路径参数 以冒号开头
{path: '/user/:id', component: User}
]
})
const User = {
// 获取参数
template: '<div>User {{$route.params.id}}</div>'
}
const router = new VueRouter({
routes: [
// 动态路径参数 以冒号开头
{path: '/user/:id', component: User}
]
})
路由传参
- $route.params
{ path: '/user/:id', component: User }
{ path: '/user/:id', component: User }
- $route.query
router.push({ path: 'register', query: { plan: 'private' }})
router.push({ path: 'register', query: { plan: 'private' }})
模式
const router = new VueRouter({
mode: 'hash', // history
routes: [
// ...
]
})
const router = new VueRouter({
mode: 'hash', // history
routes: [
// ...
]
})
- hash
vue-router
默认 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。
- history
如果不想要很丑的 hash,我们可以用路由的 history 模式,这种模式充分利用 history.pushState
API 来完成 URL 跳转而无须重新加载页面。
需要服务端配置
location / {
try_files $uri $uri/ /index.html;
}
location / {
try_files $uri $uri/ /index.html;
}
编程式导航
除了使用 <router-link>
创建 a 标签来定义导航链接,我们还可以借助 router 的实例方法,通过编写代码来实现。
router.push(location, onComplete?, onAbort?)
声明式 | 编程式 |
---|---|
<router-link :to="..."> | router.replace(...) |
// 字符串
router.push('home')
// 对象
router.push({ path: 'home' })
// 命名的路由
router.push({ name: 'user', params: { userId: '123' }})
// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
// 字符串
router.push('home')
// 对象
router.push({ path: 'home' })
// 命名的路由
router.push({ name: 'user', params: { userId: '123' }})
// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
router.replace(location, onComplete?, onAbort?)
声明式 | 编程式 |
---|---|
<router-link :to="..." replace> | router.replace(...) |
// 跟 router.push 很像,唯一的不同就是,它不会向 history 添加新记录,
// 而是跟它的方法名一样 —— 替换掉当前的 history 记录。
router.replace(location, onComplete?, onAbort?)
// 在浏览器记录中前进一步,等同于 history.forward()
router.go(1)
// 后退一步记录,等同于 history.back()
router.go(-1)
// 跟 router.push 很像,唯一的不同就是,它不会向 history 添加新记录,
// 而是跟它的方法名一样 —— 替换掉当前的 history 记录。
router.replace(location, onComplete?, onAbort?)
// 在浏览器记录中前进一步,等同于 history.forward()
router.go(1)
// 后退一步记录,等同于 history.back()
router.go(-1)
router.go(n)
// 前进 3 步记录
router.go(3)
// 前进 3 步记录
router.go(3)
路由守卫
全局守卫
前置守卫
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
else next()
})
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
else next()
})
后置守卫
router.afterEach((to, from) => {
// ...
})
router.afterEach((to, from) => {
// ...
})
路由独享的守卫
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
这些守卫与全局前置守卫的方法参数是一样的。
组件内的守卫
最后,你可以在路由组件内直接定义以下路由导航守卫:
beforeRouteEnter
beforeRouteUpdate
(2.2 新增)beforeRouteLeave
const Foo = {
template: `...`,
beforeRouteEnter(to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate(to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave(to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}
const Foo = {
template: `...`,
beforeRouteEnter(to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate(to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave(to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}
Vuex介绍
提供状态管理
提供组件通信
使用
Module
Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:
const moduleA = {
namespaced: true, // 命名空间
state: {...},
mutations: {...},
actions: {...},
getters: {...}
}
const moduleB = {
state: {...},
mutations: {...},
actions: {...}
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
const moduleA = {
namespaced: true, // 命名空间
state: {...},
mutations: {...},
actions: {...},
getters: {...}
}
const moduleB = {
state: {...},
mutations: {...},
actions: {...}
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
mapState
import { mapState } from 'vuex';
computed: {
...mapState('router', [
'routers'
])
},
import { mapState } from 'vuex';
computed: {
...mapState('router', [
'routers'
])
},
mapActions
import { mapActions } from "vuex";
methods: {
...mapActions('router', [
'setRouters'
]),
},
import { mapActions } from "vuex";
methods: {
...mapActions('router', [
'setRouters'
]),
},