[学习笔记 Day04]Vue语法进阶:Vuex的数据仓储和VueRouter路由导航

路由

定义:路径和组件的映射关系。

Vue 版本Vue Router版本Vuex版本
2.x3.x3.x
3.x4.x4.x

VueRouter

  • 作用:修改地址栏路径时,切换显示匹配的组件
  • 说明:Vue官方的一个路由插件,是一个第三方包
  • 使用:
    • 下载: #yarn add vue-router@3.6.5
    • 引入:import 组件名 from '组件名/路径(vue-router)'
    • 安装:Vue.use(VueRouter)
    • 创建路由对象:const 对象名(router) = new 组件名;
    • 注入,将路由对象注入到new Vue实例中:new Vue({ router:对象名}).$mount("#app");
    • 创建需要的组件(view目录),配置路由规则。
    • 配置导航,配置路由出口
//app.js

const router = new VueRouter({
      router:[
            {path:'网址路径',component:组件名},
            ...
      ]
});

//app.html

<script src="../../app.js">

<a href="#/find"></a>

//显示内容标签
<router-view></router-view>
  • 组件存放目录问题(组件分类)
    • 页面组件(src/views)
    • 复用组件(src/components)
  • 路由的封装抽离:将路由相关的东西抽离到 src/router/index.js 中(@表示绝对路径中的 src 文件夹)
  • 声明式导航和导航高亮
    • vue-router 提供了一个全局组件 router-link (取代 a 标签)
      • 能跳转,配置 to 属性指定路径(必须),to 属性无需“#”号
      • 能高亮,默认就会提供高亮类名,可以直接设置其样式
    • 两个高亮类名
      • router-link-active 模糊匹配:to=”/my/”,能匹配 /my、/my/a
      • router-link-exact-active 精确匹配:to=”my/”,只可以匹配到/my
    • 自定义高亮类名
const router = new VueRouter({
      router:[
            {path:'网址路径',component:组件名},
            ...
      ],
      linkActiveClass:"类名1",     //模糊匹配类名
      linkExactActiveClass:"类名2" //精确匹配类名
});
  • 跳转传参(声明式导航)
    • 目的:在跳转路由时,进行传值
    • 查询参数传参
      • 语法格式:to="/path?参数名=值"
      • 对应页面组件接收传递过来的值 $router.query.参数名
    • 动态路由传参
      • 配置动态路由
      • 配置导航链接
      • 对应页面组件接收传递过来的值
    • 动态路由参数可选符
      • 原因: /path/:参数名 表示,必须传参
      • 解决:如果不传参,也希望匹配到,可以加一个可选符 ?
//app.vue
<script>
const router = new VueRouter({
      routes:[
            {path:'/path/:参数名',component:组件名},
            ...
      ]
});
</script>
<template>
<div>
      <router-voew to="/path/参数值"></router-voew>
</div>
</template>

//c.vue
<script>
const params=$route.params.参数名;
</script>
  • 重定向
    • 问题:网页打开 url 默认是 / 路径,未匹配到组件时,会出现空白
    • 说明:重定向 => 匹配 path 后,强制跳转 path 路径
    • 语法:{path:匹配路径,redirect:重定向到的路径}
  • 404路由:
    • 作用:当路径找不到匹配时,给一个提示页面。
    • 位置:配置在所有路由的最后面
    • 语法:{path:'*',component:NotFound}
      • *:任意路径
  • 路由模式:
    • 模式设置:
      • hash路由(默认):http://xxx/#/home
      • history路由(常用):http://xx/home(需要服务端支持)
    • 语法:
const router = new VueRouter({
      routes:[
            {path:'/path/:参数名',component:组件名},
            ...
      ],
      mode:"history"
});
  • 编程式导航(用 JS 代码进行跳转)
    • 基本跳转语法
      • path 路径跳转:this.router.push('路由路径')this.router.push({ path:'路由路径'})
      • name命名路由跳转(适合 path 路径长)this.$router.path({name:'路由名'}){ name:'路由名',path:'/path/xx',component:xxx }
    • 路由传参:
      • path 路径传参(query传参)
      • 动态路由传参(path路径)
      • name 命名路由传参
        • query传参
          • 被缓存的组件会多2个声明周期【actived(看到页面)和deactived(离开页面)】,就不会执行 created、mounted和destroyed
        • 动态路由传参
//path 路径传参(query传参)

this.$router.push('/path?参数名=值')
//或
this.$router.push({
      path:'路径',
      query:{
            参数名1:值1,
            参数名2:值2,
            参数名n:值n,
      }
})

//动态路由传参(path路径)

this.$router.push('/path/参数值')
//或
this.$router.push({
      path:'/path/参数值'
})

//name命名路由传参(query传参)
this.$router.push({
      name:路由名字,
      query:{
            参数名1:值1,
            参数名2:值2,
            参数名n:值n,
      }
})

//name命名路由传参(动态路由传参)
this.$router.push({
      name:路由名字,
      params:{
            参数名1:值1,
            参数名2:值2,
            参数名n:值n,
      }
})

  • 组件缓存 keep-ative
    • 属性(二选一):
      • include:组件名数组:只有匹配的组件才会被缓存
      • exclude:组件名数组:匹配任何的组件不会被缓存(配合 max 属性使用)
      • max:最多可以缓存多少组件实例
    • 返回上一页:$route.back()
//写法:
<keeo-alive>
      <router-view></router-view> //本级以下的所有组件会被缓存
</keeo-alive>

//属性写法示例
<keeo-alive :include="['Layout','Home']">
      <router-view></router-view> //本级以下的所有组件会被缓存
</keeo-alive>

//子路由
//...
routes:[{
      path:'/',
      component:组件名,
      children:[{              //嵌套子路由,需要配套路由出口
            path:'xxx',
            component:子组件名
            //...
      }]
}]
//...
  • 自定义创建项目
    • 目的:基于 VueCli 自定义创建项目架子
    • 步骤:
      • Babel / Router / CSS / Linter
      • Vue x2.x
      • VueRouter hash模式
      • CSS预处理器 less
      • ESLint:Standard&Lint on Save
      • 配置文件dedicated config files
    • ESLint代码规范
  • 补充:在单引号内拼接字符串:'xxx${变量名}'

Vuex

  • 基本认知:
    • 概念:
      • vuex 是一个 vue 的状态管理工具,状态就是数据
      • vuex 是一个插件,可以帮助我们管理 vue 通用数据(多组件共享的数据)
    • 场景:
      • 某个状态在很多组件中使用(个人信息)
      • 多组件共同维护一份数据
    • 优势:
      • 共同维护一份数据
      • 响应式变化
      • 操作简洁

构建 vuex 多组件数据共享环境

  • 步骤:
    • 创建项目: vue create 项目名
    • 创建三个组件,目录如下:
|-components
|--son1.vue
|--son2.vue
|-App.vue
  • 创建一个空仓库
    • 步骤:
      • 安装 vuex: yarn add vuex@3
      • 新建 vuex 模块文件:新建 store/index.js 专门存放 vuex
      • 创建仓库:Vue.use(Vuex); new Vuex.Store()
      • main.js导入挂载
    • 校验:this.$store

核心概念

  • state 状态
    • 提供数据:其提供唯一的公共数据源,所有共享的数据都要统一放大 Store 中的 State 中存储,在 state 对象中可以添加我们要共享的数据。
    • 使用数据:
      • 通过 store 直接访问:
        • 获取 store:this.$store import导入store
        • 模板中:{{$store.state.xxx}}
        • 组件逻辑中:this.$store.state.xxx
        • JS模块中:store.state.xxx
      • 通过辅助函数
        • mapState 是辅助函数,帮助我们把 store 中的数据自动映射到组件的计算属性上
        • 使用步骤:
          1. 导入 mapState:import {mapState} from 'vuex'
          2. 数组方式引入 state:mapState(['xxx'])
          3. 展开运算符映射:computed:{...mapState(['xxx'])}
//state提供数据
const store = new Vuex.Store({
      state:{
            xxx:值
      }
})
  • mutations
    • 补充:开启严格模式 strict:true
    • 使用:
      • 定义 mutations 对象,对象中存放修改 state 的方法
      • 组件中提交调用 mutations:this.$store.commit('xxx')
    • 提交带参数
      • 提供 mutstions 函数(带参数,提交载荷 payload)
      • 页面中提交调用 mutations:this.$store.commit(‘xxx’,值)
      • 注意:mutations 参数有且只能有一个,如果需要多个参数,可以包装成一个对象
//store.js
const store = new Vuex.Store({
      state:{变量名1:值1},
      mutations:{
            函数名1(state,参数1){
                  state.变量1 = 参数1;
                  //函数块
                  //...
            }
      }
})

//页面
this.$store.commit('函数名1',参数1的值)
  • 辅助函数 mapMutations
    • 其是把位于 mutations 中的方法提取了出来,映射到组件 methods 中。
    • 例如:
//store.js
mutations:{
      subCount(state,n){}
}

//app.vue
import {mapMutations} from 'vuex'

mrthods:{
      ...mapMutations(['subCount'])
}

//调用
this.subCount(0);
  • actions(处理异步操作)
    • 使用:
      1. 提供 actions 方法
      2. 页面中 dispatch 调用
  • mapActions 辅助函数
    • 作用:mapActions 是把位于 actions 中的方法提取了出来,映射到组件 methods 中。
//store.js
actions:{
      //setAsyncCount:actions中的名字
      //context:上下文(此次未分类,可以将其当成 store 仓库)
      setAsyncCount(context,num){
            setTimeout(() => {
                  //changeCount:mutations中的方法
                  context.commit('changeCount',num);
            },1000)
      }
}

//app.vue
methods:{
      changeCountActions(n){
            this.$store.dispatch('setAsyncCount',n);
      }
      //或
      ...mapActions(['setAsyncCount']);
      //调用
      //this.setAsyncCount(1);
}
  • getters:
    • 说明:除了 state 之外,有时我们还需要从 state 中派生出一些状态,这些状态是依赖 state 的,此时会用到 getters。
    • 使用:state:{ list:[1,2,3,4,5,6,7,8,9,10] }
      • 定义getters:getters:{ 函数名(state){ return xxx; } }
      • 访问getters:
        • 通过 store 访问getters:{{ $store.getters.函数名 }}
        • 通过辅助函数 mapGetters 映射:computed:{ ...mapGetters('函数名') }; {{函数名}}
    • 注意:
      • 形参第一个参数,就是 state
      • 必须有返回值,返回值就是 getters 的值
  • 模块 module
    • 模块拆分:将拆分的模块放到 store/modules/ 文件中
    • 访问模块中的数据
      • 尽管已经分模块了,但其实模块的状态还是会挂载到跟级别的 state 中,属性名就是模块名
      • 使用数据:
        • 直接通过模块名访问 $store.state.模块名.xxx
        • 通过 mapState 映射
          • 默认根级别的映射 ...mapState(['xxx'])
          • 子模块的映射 ...mapState('模块名',['xxx']),需要开启命名空间!
        • 使用模块中的 getters 中的数据
          • 直接通过模块名访问 $store.getters['模块名/xxx']
          • 通过 mapGetters 映射
            • 默认根级别的映射:...mapGetters(['xxx'])
            • 子模块的映射:...mapGetters('模块名',['xxx']),需要开启命名空间!
        • 调用 mutations 函数
          • 注意:默认模块中的 mutations 和 actions 会被挂载到全局,需要开启命名空间,才会挂载到子模块
          • 直接 store 调用:$store.commit('模块名/xxx',额外的参数)
          • 通过 mapMutions 映射
            • 默认根级别的映射:...mapMutations(['xxx'])
            • 子模块的映射:...mapMutations('模块名',['xxx']),需要开启命名空间!
        • 调用 Actions 函数
          • 直接通过 store 调用:$store.dispatch('模块名/xxx',额外的参数)
          • 通过 mapActions 映射
          • 默认根级别的映射:...mapActions(['xxx'])
          • 子模块的映射:...mapActions('模块名',['xxx']),需要开启命名空间!
    • 例如:
//某个module模块store.js文件
const state = {name:'',xxx}
const xxx = {...}

export default {
      namespaced:true,//子模块的映射,需要开启命名空间
      state,
      ...
}

//app.js
import xxx from './modules/xxx'
//导入到全局中
const store = new Vuex.Store({
      modules:{xxx:xxx}
})

扩展:临时后端服务工具

  • 安装全局工具 json-server(只需要安装一次)
yarn global add json-server
//或
npm i json-server -g
  • 创建服务
    • 在代码目录下新建一个 db 目录
    • 在 db 目录中新建 index.json 文件并写入数据
    • 进入到 db 目录中,执行命令,启动后端接口服务
json-server --watch 文件名.json
  • 访问测试

项目打包发布

  • 命令: #yarn build
  • 结果:在项目的根目录中会自动创建一个文件夹(dist),dist 文件夹就是打包后的文件,只需要放到服务器中即可
  • 配置:默认情况下,需要放到服务器的根目录中在打开,如果希望双击运行,需要配置 publicPath,配成相对路径即可
//vue.config.js

modeule.export = defineConfig({
      publicPath:'./',
      transpileDependencies:true
})

路由懒加载

  • 将不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件
  • 步骤:
    • 异步组件改造
    • 路由中应用
//异步组件改造
const ProDetail = () => import('@/views/prodetail')
const Pay = () => import('@/views/pay')

//路由中应用
const router = new VueRouter({
      routes:[
            {path:'/prodetail/:id',component:ProDetail},
            {path:'/pay',component:Pay}
      ]
})
© 版权声明
THE END
喜欢就支持一下吧
点赞10 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容