文章目录
npm install vuex
npm install -g vue-router
when to use vuex?
multiple components depend on or affect one state
vuex flow
demos
import {createStore, useStore, mapState, mapGetters, mapActions, mapMutations} from 'vuex'
// store/index.js
import user from './modules/user'
export const store = createStore<RootState>({
modules: {
user,
}
})
// store/modules/user.js
export default { // put related actions,mutations,states,getters to one group
strict: process.env.NODE_ENV !== 'production',
namespaced: true, // mapState('enable_this_param', [...])
state: () => {
return {
state1: 0 // {{$store.state.state1}}
}
},
actions: { // 业务逻辑的前置处理,通常伴随着api调用
// warning: do not manipulate context.state.state1 directly!
action1(context, value){
context.commit('group1/ACTION1', value) // pass value to mutations directly
}
context.dispatch('group1/action1', value) // current logic is too complex, pass to other actions for further processing
},
mutations: { // this is the cheff; debugger is monitering these actions
setAction1(state, value){
state.state1 += value
}
},
getters: {
output1(state) { // {{$store.getters.output1}}; warning: this.$store.getters['group1/output1']
return state.state1 * 10
}
}
}
// views/user.js
setup(){
const store = useStore()
// map states/getters to computed methods(debugger name: vuex bindings)
computed:{
...mapState('group1',{state1: 'state1'}) // avoid writing '$store.state.group1.xxx' --> 'xxx'
...mapGetters(['group1','output1']) // if computed name is the same as getter's name, u can use array! '$store.getters.group1.output1' --> 'output1'
}
// map actions/mutations to methods; params are passed by template
methods:{
...mapActions('group1', ['action1']) // {{action1(n)}} == this.$store.dispatch('action1', n); warning: when lose the first param: '{{group1.action1(n)}}'
...mapMutations('group1',{myACTIONS1: 'ACTION1'}) // {{myACTION1(n)}} == this.$store.commit('ACTION1', n)
}
}
route
- 路由切换时,路由组件将被频繁的挂载+卸载!
- 除1级路由外无需加prefix:’/'!
- ‘#’: url中井号后面的都是vue路由,刷新页面切换等不会被发送到服务器!
<!-- 路由跳转(非<a>的页面跳转,不会刷新页面); 实际上最终还是转换到了<a>标签 -->
<router-link :to="{
name: 'routename', <!-- 与path二选一即可,不常用 -->
path: '/relative/path',
query: { <!-- {{$route.query.uid}} -->
uid: 1
},
params: { <!-- warning: 必须配合name,不能使用path! -->
id: 2 <!-- routes里面定义的path中的占位变量 -->
}
}"
tag='li'
event='mouseover'>
</router-link>
<!-- 路由变化的时候展示对应的组件; 保存状态(一般仅缓存有input交互的page,不指定会全缓存,多个可写成数组:include="['','']")! -->
<keep-alive include="component1"><router-view></router-view></<keep-alive>
import VueRouter from 'vue-router'
const routes = [
{ path: '/', redirect: '/home', name: 'routename' },
{ path: '/home', component: Home, props: true }, // 子组件通过prop访问动态路由的路径参数,也可以如下:
{ path: '/movie/:id', // 访问动态路由的路径参数(冒号只能出现在路由规则中): this.$route.params.id
component: Movie,
props: true, // component中props里也对应声明下'id',则template中{{id}}可以直接取到实参,省的写:'{{$route.params.id}}'!
props($route) { // 比上面更高端的写法. 路由跳转时回调该函数. 计算后会将uid暴露给component. component在props声明后,在template中用'{{uid}}'拿到这里的计算值!
return {uid: $route.query.uid}
},
meta:{
isAuth: false, // 路由守卫中使用
title: ''
},
beforeEnter: (to, from, next) => { // 局部路由守卫(无后置)
}
},
{ path: '/about', component: About,
redirect: '/about/tab1', // 默认跳转. 实际上把tab1的path置空,就变成了默认子路由(router-link也要为空).
children: [
{ path: 'tab1', component: Tab1 } // /about/tab1
]
},
]
const router = VueRoute.createRouter({
history: VueRouter.createWebHashHistory(), // url中没有'#'了(无#兼容性略差)
routes: routes,
})
// 每个组件不同
this.$route.fullPath; // /movie/2?name=zs&age=20
this.$route.path; // /movie/2
this.$route.params.query; // {name:'zs', age:'20'}
// 每个组件都是同一个router
this.$router.push('/home') // 会增加历史记录
this.$router.replace('/home') // 替换当前历史记录
this.$router.go(2) // 前进或后退几步(可以是负数,超过上线无任何效果)
this.$router.forward/back() // go(1) == forward(); go(-1) == back()
// 第一次'/'通常很多余
router.beforeEach((to, from, next) { // 前置路由守卫
if (to.path === '/main') { // to: 将要访问的路由信息对象; from: 将要离开的路由信息对象
const token = localStorage.getItem('token') // debug-Application标签有Storage
if (token) {
next() // 调用表示放行,允许此次路由导航
} else {
next('/login') // 强制跳转到指定路由; next(false):停留在from,哪都不许去
}
}
next()
})
router.afterEach((to, from){ // 后置路由守卫
document.title = to.meta.title || 'default title'
})
app.use(router)