四、Vuex
使用流程
:A组件
想要调用State
的值
- 正常流程:组件A内部调用
this.$store.dispatch
传入方法名,数据来到Actions
,Actions
发现方法名匹配,进行下一步操作
- 对数据进行筛选提交
commit
匹配Mutations
,未传入数据,可以向服务器
请求数据
Mutations
匹配方法,对State
的数据根据要求直接修改(可以DevTools
被检测到)
Mutate
不需要我们调用,重新渲染
- 快速流程:提交
commit
匹配Mutations
(不需要筛选数据的请求)顾客=>厨师
语义化
:
dispatch
:客人点菜Actions
:服务员记录数据,通过commit交给厨师MutationsMutations
:开始做菜,返给顾客食用getters
:阿姨对菜进行清洗、削皮啥的
概述
: 在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写
),也是一种组件间通信的方式,且适用于任意组件间通信
范围
:多个组件要共享数据
4.1 搭建vuex环境
- 创建文件:
src/store/index.js
//引入Vue核心库importVuefrom'vue'//引入VueximportVuexfrom'vuex'//应用Vuex插件Vue.use(Vuex) //准备actions对象——响应组件中用户的动作constactions= {} //准备mutations对象——修改state中的数据constmutations= {} //准备state对象——保存具体的数据conststate= {} //创建并暴露storeexportdefaultnewVuex.Store({ actions, mutations, state})
- 在
main.js
中创建vm时传入store
配置项
//引入storeimportstorefrom'./store'//创建vmnewVue({ el:'#app', render: h=>h(App), store})
4.2 基本使用
- 初始化数据、配置
actions
、配置mutations
,操作文件store.js
//引入vue核心库importvuefrom'vue'//引入vueximportvuexfrom'vuex'//一般处理路径// dispatch => actions => commit => mutations =>state// 快速处理// commit => mutations =>state//全局使用vuexvue.use(vuex) //处理事件constactions= { jia (context, value) { // console.log('actions',context);context.commit('JIA',value) }, jiaOdd (context, value) { if (context.state.sum%2) { context.commit('JIA',value) } }, jiaWait (context, value) { setTimeout(() => { context.commit('JIA',value) },500) } } //处理数据constmutations= { JIA (state,value) { state.sum+=value// console.log('mutations',state); }, JIAN (state,value) { state.sum-=value }, ADD_PERSON (state, value) { state.personList.unshift(value) } } //存储数据conststate= { sum: 0, name:'尚硅谷', subject: 'VUE', personList: [ {id:'001',name:'张三'}, {id:'002',name:'李四'}, ] } //数据加工constgetters= { bigSum (state) { returnstate.sum*10 } } exportdefaultnewvuex.Store({ actions, mutations, state, getters})
- 组件中读取vuex中的数据:
$store.state.sum
- 组件中修改vuex中的数据:
$store.dispatch('action中的方法名',数据)
或$store.commit('mutations中的方法名',数据)
备注:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写
dispatch
,直接编写commit
4.3 getters的使用
- 概念:当state中的数据需要经过加工后再使用时,可以使用getters加工。
- 在
store.js
中追加getters
配置
constgetters= { bigSum(state){ returnstate.sum*10 } } //创建并暴露storeexportdefaultnewVuex.Store({ getters})
- 组件中读取数据:
$store.getters.bigSum
4.4 四个map方法的使用
- mapState方法:用于帮助我们映射
state
中的数据为计算属性
computed: { //借助mapState生成计算属性:sum、school、subject(对象写法)mapState({sum:'sum',school:'school',subject:'subject'}), //借助mapState生成计算属性:sum、school、subject(数组写法)mapState(['sum','school','subject']), },
- mapGetters方法:用于帮助我们映射
getters
中的数据为计算属性
computed: { //借助mapGetters生成计算属性:bigSum(对象写法)mapGetters({bigSum:'bigSum'}), //借助mapGetters生成计算属性:bigSum(数组写法)mapGetters(['bigSum']) },
- mapActions方法:用于帮助我们生成与
actions
对话的方法,即:包含$store.dispatch(xxx)
的函数
methods:{ //靠mapActions生成:incrementOdd、incrementWait(对象形式)mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'}) //靠mapActions生成:incrementOdd、incrementWait(数组形式)mapActions(['jiaOdd','jiaWait']) }
- mapMutations方法:用于帮助我们生成与
mutations
对话的方法,即:包含$store.commit(xxx)
的函数
methods:{ //靠mapActions生成:increment、decrement(对象形式)mapMutations({increment:'JIA',decrement:'JIAN'}), //靠mapMutations生成:JIA、JIAN(对象形式)mapMutations(['JIA','JIAN']), }
备注:mapActions与mapMutations使用时,若需要传递参数需要:在模板中绑定事件时传递好参数,否则参数是事件对象。
4.5 模块化+命名空间
- 目的:让代码更好维护,让多种数据分类更加明确。
- 修改
store.js
constcountAbout= { namespaced:true,//开启命名空间state:{x:1}, mutations: { }, actions: { }, getters: { bigSum(state){ returnstate.sum*10 } } } constpersonAbout= { namespaced:true,//开启命名空间state:{ }, mutations: { }, actions: { } } conststore=newVuex.Store({ modules: { countAbout, personAbout } })
- 开启命名空间后,组件中读取state数据:
//方式一:自己直接读取this.$store.state.personAbout.list//方式二:借助mapState读取:mapState('countAbout',['sum','school','subject']),
- 开启命名空间后,组件中读取getters数据:
//方式一:自己直接读取this.$store.getters['personAbout/firstPersonName'] //方式二:借助mapGetters读取:mapGetters('countAbout',['bigSum'])
- 开启命名空间后,组件中调用dispatch
//方式一:自己直接dispatchthis.$store.dispatch('personAbout/addPersonWang',person) //方式二:借助mapActions:mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
- 开启命名空间后,组件中调用commit
//方式一:自己直接committhis.$store.commit('personAbout/ADD_PERSON',person) //方式二:借助mapMutations:mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),
五、路由
官方概述:一个路由(route)就是一组映射关系(key - value),多个路由需要路由器(router)进行管理
概述
:根据你的路径
由路由管理器(router
)来匹配相应的组件
5.1 基本使用
5.1.1 安装vue-router
npmivue-router//版本号更新问题vue3=>vue-router4vue2=>vue-router3
5.1.2 编写router脚本
//引入VueRouterimportVueRouterfrom'vue-router'//引入Luyou 组件importAboutfrom'../components/About'importHomefrom'../components/Home'//创建router实例对象,去管理一组一组的路由规则constrouter=newVueRouter({ routes:[ { path:'/about', component:About, //多级路由children: [ { path: 'news', component:News }, }, { path:'/home', component:Home } ] }) //暴露routerexportdefaultrouter
5.1.3 main.js引入
import Vue from "vue"; import App from './App' import VueRouter from "vue-router"; //引入路由 import router from './router/index' Vue.config.productionTip = false Vue.use(VueRouter) new Vue({ el: '#app', render: h => h(App), router })
5.1.4 实现切换
<router-linkactive-class="active"to="/about">About</router-link>
5.1.5 实现展示
<router-view></router-view>
5.1.6 注意点
- 路由组件通常存放在
pages
文件夹,一般组件通常存放在components
文件夹。 - 通过切换,“隐藏”了的路由组件,默认是被销毁掉的,需要的时候再去挂载。
- 每个组件都有自己的
$route
属性,里面存储着自己的路由信息。 - 整个应用只有一个router,可以通过组件的
$router
属性获取到。
5.2 数据传输
概述
:通过query
或者params
传输信息
5.2.1 query
- 传递参数
<!--跳转并携带query参数,to的字符串写法--><router-link :to="/home/message/detail?id=666&title=你好">跳转</router-link><!--跳转并携带query参数,to的对象写法--><router-link :to="{path:'/home/message/detail', query:{ id:666, title:'你好' } }">跳转</router-link>
- 接收参数:
$route.query.id $route.query.title
5.2.2 params
- 配置路由,声明接收params参数
{ path:'/home', component:Home, children:[ { path:'news', component:News }, { component:Message, children:[ { name:'xiangqing', path:'detail/:id/:title', //使用占位符声明接收params参数component:Detail } ] } ] }
- 传递参数
<!--跳转并携带params参数,to的字符串写法--><router-link :to="/home/message/detail/666/你好">跳转</router-link><!--跳转并携带params参数,to的对象写法--><router-link :to="{name:'xiangqing', params:{ id:666, title:'你好' } }">跳转</router-link>
特别注意:路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置!
- 接收参数:
$route.params.id $route.params.title
5.2.3 props
概述
:让路由组件更方便的收到参数
{ name:'xiangqing', path:'detail/:id', component:Detail, //第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件// props:{a:900}//第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Detail组件// props:true//第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件props(route){ return { id:route.query.id, title:route.query.title } } }
5.3 路由跳转
5.3.1 的replace属性
- 作用:控制路由跳转时操作浏览器历史记录的模式
- 浏览器的历史记录有两种写入方式:分别为
push
和replace
,push
是追加历史记录,replace
是替换当前记录。路由跳转时候默认为push
- 如何开启
replace
模式:News
5.3.2 编程式路由导航
- 作用:不借助
- 具体编码:
//$router的两个APIthis.$router.push({ name:'xiangqing', params:{ id:xxx, title:xxx } }) this.$router.replace({ name:'xiangqing', params:{ id:xxx, title:xxx } }) this.$router.forward() //前进this.$router.back() //后退this.$router.go() //可前进也可后退
5.4 拓展
5.4.1 缓存路由组件
作用
:让不展示的路由组件保持挂载,不被销毁(数据残留)。- 具体编码:
<keep-aliveinclude="News"><router-view></router-view></keep-alive>
这里包含的内容写组件名称,多个组件使用数组**[‘’,‘’]**
5.4.2 两个新的生命周期钩子
- 作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
- 具体名字:
activated
路由组件被激活时触发(显示到页面、使用一部分功能)deactivated
路由组件失活时触发
5.5 带刀侍卫
全局前置路由=>独享路由守卫=>组件进入守卫=>全局后置路由=>组件离开守卫
概述
:组件是皇宫里面的一个个房子,全局前置守卫是门前巡逻的一大批禁军、独享路由守卫门前=>房子
路径上的巡逻卫士、组件进入守卫是门前带刀侍卫、全局后置守卫房子里的太监、组件离开守卫是门后带刀侍卫
5.5.1 全局守卫
概述
:一个在大门(是否放行),一个在家里(已退休)
//全局前置守卫:初始化时执行、每次路由切换前执行router.beforeEach((to,from,next)=>{ console.log('beforeEach',to,from) if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制if(localStorage.getItem('school') ==='atguigu'){ //权限控制的具体规则next() //放行 }else{ alert('暂无权限查看') // next({name:'guanyu'}) } }else{ next() //放行 } }) //全局后置守卫:初始化时执行、每次路由切换后执行router.afterEach((to,from)=>{ console.log('afterEach',to,from) if(to.meta.title){ document.title=to.meta.title//修改网页的title }else{ document.title='vue_test' } })
5.5.2 独享守卫
beforeEnter(to,from,next){ console.log('beforeEnter',to,from) if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制if(localStorage.getItem('school') ==='atguigu'){ next() }else{ alert('暂无权限查看') // next({name:'guanyu'}) } }else{ next() } }
5.5.3 组件内守卫
//进入守卫:通过路由规则,进入该组件时被调用beforeRouteEnter (to, from, next) { }, //离开守卫:通过路由规则,离开该组件时被调用beforeRouteLeave (to, from, next) { }
六、组件化工具
7.1 移动端常用 UI 组件库
- Vant https://youzan.github.io/vant
- Cube UI https://didi.github.io/cube-ui
- Mint UI http://mint-ui.github.io
7.2 PC 端常用 UI 组件库
- Element UI https://element.eleme.cn
- IView UI https://www.iviewui.com