Vue2 的生命周期钩子有哪些?数据请求放在哪
- beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy、destroyed
- activated、deactivated、errorCaptured
- 数据请求一般放在 mounted 里面
- 如果放在created里,会在后端SSR(Server-Side Render)和前端都执行一次,不符合预期
- updated钩子触发太过频繁,一般数据请求只触发一次
Vue2 组件间通信方式
- 父子通信:使用props和事件进行通信
- 爷孙通信:
- 使用两次父子组件通信
- 使用provide和inject
- 任意组件:使用eventBus = new Vue()
- 主要API是eventBus.$on(监听) 和 eventBus.$emit(触发)
- 缺点:事件多了容易乱,难以维护
- 任意组件:使用Vuex通信(Vue3可用Pinia代替Vuex)
Vuex用过吗?如何理解
- 描述:Vuex是一个专为vuejs应用程序开发的 状态管理模式 + 库
- 核心概念:
1
2
3
4
5
6a. store是一个大容器,包含以下所有内容
b. State 用来读取状态,带有一个 mapState 辅助函数
c. Getter 用来读取派生(计算)状态,带有一个mapGetters 辅助函数
d. Mutation 用于同步提交状态变更(写),带有一个mapMutations 辅助函数
e. Action 用于异步变更状态(写),但它提交的是mutation,而不是直接变更状态
f. Module 用来给store划分模块,方便代码维护
VueRouter用过吗?如何理解
描述:官方推荐的路由,适用于做单页面应用
router-link
进行导航,传递to来指定链接,最终会呈现一个带有href属性的a标签
router-view
路由出口,路由匹配到的组件将在这里渲染
嵌套路由
在一个路由下还分有子路由,他们分别又对应不同的组件1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22const routes = [
{
path: '/',
redirect: '/account'
},
{
path: '/account',
component: account,
// 使用children属性,实现子路由
// 子路由的path前不带'/',否则永远以根路径开始请求
children: [
{
path: 'login',
component: Login
},
{
path: 'register',
component: Register
}
]
}
]
Hash模式 && History模式
前端路由:找到与地址相匹配的组件并将它渲染出来
本质:改变浏览器地址(更新视图)但不向服务器发出请求
有两种方法可以做到:
- hash模式 利用URL中的hash(“#”)
- history模式 利用 history.pushState() API来完成URL跳转而无须重新加载页面,但是需要后端将所有前端路由都渲染同一页面,且IE8以下的浏览器不支持
两种模式的对比:
- Hash模式只可以更改 # 后面的内容(也就是字符串),History模式可以通过 API 设置任意的同源 URL
- Hash模式无需后端配置且兼容性好,History模式在用户手动输入地址或者刷新页面的时候会发起URL请求,后端需要配置 index.html页面 用于匹配不到静态资源的时候
路由守卫实现:权限控制 & 加载进度
- 在系统路由跳转前做权限校验
- Vue-Router提供了两个钩子函数,前置守卫beforeEach 和 后置守卫afterEach,前者在路由跳转前触发,后者在路由跳转后触发
注册全局路由守卫。当路由跳转时,路由守卫按顺序异步解析执行,只有当所有守卫resolved才会进入resolved状态,否则处在pending状态中
1
2
3
4
5
6
7
8const router = new VueRouter({ ... })
router.beforeEach((to,from,next) => {
// ...
})
router.afterEach((to,from,next) => {
// ...
})守卫的回调函数接受三个参数
- to:即将进入的路由,一个Route对象
- from:正要离开的路由,一个Route对象
- next:一个Function,回调函数内部必须执行该方法,令守卫进入resolved状态
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24router.beforeEach((to,from,next) => {
// 鉴权操作
const token = getToken()
if(token) {
if(to.path === '/login'){
next('/')
} else {
// 其他鉴权操作,如资源是否可访问
let menus = store.getters['user/menus']
if(menus.includes(to.path)) {
next()
} else {
next({path: '/403', replace: true}) // replace 替换当前路由,避免用户后退操作导致重复跳转
}
}
} else {
if(whiteList.includes(to.path)){
next()
} else {
next(`/login?redirect =${to.path}`)
}
}
})
参考文章巧用Vue-Router路由守卫实现路由权限控制和加载进度
路由懒加载
将不同路由对应的不同组件分割成不同的代码块,然后当路由被访问时才加载对应的组件1
2
3// 用动态导入代替静态导入
// 将 import UserDetails from './views/UserDetails' 替换成
const UserDetails = () => import('./views/UserDetails')
Vue2 如何实现双向绑定?
- 一般使用 v-model/.sync 实现,
v-model
实际上是v-bind:value
和v-on:input
的语法糖
a. v-bind:value => 绑定value,当data改变就去更新UI
b. v-on:input => 监听input事件,当input被触发就去更新data - 上面两个单向绑定如何实现
a. 前者通过 Object.defineProperty API 给data的每个属性创建 getter 和 setter,用于监听data的改变。当data发生改变,就会安排UI变
b. 后者通过 template compiler 给DOM添加事件监听,当DOM input的值变了就会去修改data
参考文章vue的双向绑定原理及实现