vuex
Vuex 是一个专为 Vue应用程序开发的状态管理模式 ,它用来储存管理所有组件状态。
这个状态自管理应用包含以下几个部分:
- state,驱动应用的数据源;
- view,以声明方式将 state 映射到视图;
- actions,响应在 view 上的用户输入导致的状态变化。
定义好state(组件间的状态),view视图渲染这些数据,actions去请求数据,得到后在给state。 以下是一个表示“单向数据流”理念的简单示意:
核心概念
state:单一的自身状态,比如在一个页面中(由很多个组件组合而成),那么就可以为这个页面单独建立一个store,让这个页面的所有组件都共享这个状态。
state:{
count:0,
arr:[1, 2]
}
mutations:更改vuex的state只能通过mutations的方法去修改。回调函数接受第一个参数为state,也就是自身的状态。当更改简单类型的数据直接赋值就可以了,注意:更改复杂数据类型的时候就需要每次赋予一个新的地址。视图才会得到刷新。
mutations:{
increment(state){
state.count++
},
updateArr(state){
//这里通过Object.assign方法合并,也可以用其它方法
const arr = [3, 4];
Object.assign(state,{ arr });
//扩展数组
state.arr = [...arr];
}
}
getters:有时候会从state中衍生出来一些属性(可以认为是store的计算属性),就像计算属性一样,getter的返回值会更据它的依赖进行缓存,只有当它 的依赖值发生变化才会被重新计算。回调函数也接受state为第一个参数例如数组的长度。
getters:{
arrLen:state => {
return state.arr.length;
},
existence:state => index => {
return state.arr.indexOf(index)===-1?false:true;
}
}
actions:在actions中提交 mutation ,去改变状态,用来处理异步和事务性操作。回调函数接受一个参数context,通过context可以访问state、getters、commit 、dispatch(用来触发其它actions函数)。在接收到的时候可以直接结构.
actions:{
async getData({state, getters, commit ,dispatch}){
//组装好数据
let obj = { count:state.count, arrLen:getters.arrLen };
//异步请求数据
const { data } = await ajax(obj);
//成功过后在去触发
commit("increment");
//也可以在触发一个其它actions函数
dispatch("getStu");
},
async getStu(){
//...
}
}
modules:当你的应用变得相当复杂时,store就会变得十分臃肿,就会把一个个的store分离开,在通过modules组合在一起。namespaced命名空间的开启会让每个store独立的调用。
const moduleA = {
namespaced: true,//命名空间
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
namespaced: true,//命名空间
state: { ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
辅助函数
当一个组件需要获取多个状态或方法的时候,如果都声明出来会显得沉重多余,一般来说,使用辅助函数只声明需要的属性。
createNamespacedHelpers:创建基于某个命名空间辅助函数。它返回一个对象,对象里有新的绑定在给定命名空间值上的组件绑定辅助函数。通过解构的方式在组件的vue实例里声明出来。
mapState、mapGetters、mapMutations、mapActions分别对应的就是state、getters的状态,mutations、actions方法。直接this调用就好了。
const {
mapState,
mapGetters,
mapMutations,
mapActions } = createNamespacedHelpers("count");//count为module里的命名,需要开启命名空间
export default {
computed: {
// 在 `module==>count` 中查找
...mapState(["a","b"]),
...mapGetters(["arrLen","existence"]),
},
methods: {
// 在 `module==>count` 中查找
...mapActions([ 'getStu','getData']),
...mapMutations([ 'updateArr','increment']),
}
}
router
配置基本路由
配置一个基本路由path就是路径也就是地址栏上的,component表示组件当页面足够多,组件足够复杂时可以采用懒加载的方式,这样就能加高效了。name非必填项这里可以取一个组件名字,meta代表页面的teitle的配置。每一个路径就对应映射一个组件。
import Count from "./components/count.vue"
// 懒加载的方式
// const Count = () => import('./components/count.vue')
const routes =new VueRouter({
routers:[
{ path: '/count', component: Count, name:'count', meta: {title: '总数' }
]
})
一般来说使用vue做单页应用时在App.vue里使用router提供的组件,每当路径发生变化时,就能去渲染不同的页面,也就是说替换整个body。
<template>
<div id="app">
<router-view />
</div>
</template>
路由的嵌套
const routes =new VueRouter({
routers:[ { path: '/count',
component: () => import('./components/count.vue'),
children:[{
path: 'countList',
component: () => import('./components/countList.vue').
children:...//嵌套
}]
]
})
页面复杂一些的时候会有一级菜单,二级菜单,那么对应的会有一级路由二级路由,一级一级往下。此时使用嵌套的路由就能解决了。
动态路由跳转
路由配置好了,就能使用了。从一个页面跳转到另一个页面。
// 声明式
<router-link :to="/count"> </router-link>
// 点击这个组件时就能直接跳转更a标签一样的效果
// 编程式
this.$router.push('/count')
// 效果都一样
// 需要传递参数时
<router-link :to="{ name: '/count', params: { id: 123 }}" > </router-link>
//或者
this.$router.push({ name: '/count', params: { id: 123 }})
routes.js配置则需要配置一下接收的名称。
const routes =new VueRouter({
routers:[{ path: '/count/:id', component: () => import('./components/count.vue')
}]
})
//获取通过 id = this.$route.params
// 更加快捷的方式,跳转
this.$router.push('/count?id=123')
// 获取参数
this.$route.query.count
重定向和别名
重定向也是通过routers来完成的,下面这个例子就是从/a 重定向到 /b,当地址栏输入/a是也会跳转到/b
//
const router = new VueRouter({
routes: [
{ path: '/a', redirect: '/b' }
]
})
// 动态返回重定向
const router = new VueRouter({
routes: [
{ path: '/a', redirect:to=>{
// 方法接收 目标路由 作为参数
// return 重定向的 字符串路径/路径对象
return '/b'
} }
]
})
别名,与重定向类似,当访问/a,时URL会保持/a,当访问/b,时URL也会保持/b,访问这两个路径都是一样的,只是url不会变,重定向就会变。
const router = new VueRouter({
routes: [
{ path: '/a', component: A, alias: '/b' }
]
})
导航守卫
每一个守卫方法接收三个参数
- to: route:即将要进入的目标路由对象
- from:route:当前导航正要离开的路由
- next:function:一定要调用此方法来resolve这个钩子,next( true )或next( )直接进入下一个路由next( false)直接中断,路由不会该表。
全局前置守卫:当一个到导航触发时,会调用这个方法。
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})
全局后置守卫:路由完成之后会调用这个钩子,不会接收next函数作为参数。
router.afterEach((to, from) => {
// ...
})
路由独享的守卫:进入该路由前会调用,***next()***调用路由才会该表。
const router = new VueRouter({
routes: [
{
path: '/count',
component: () => import('./components/count.vue'),
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
组件内的守卫:当在组件内才会调用这些钩子。
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`
}
}