项目一(Vue3 - TypeScript - element-plus)

项目一:Vue3-TypeScript 电商后台管理

一、技术栈涉及

  • Vue3
  • TypeScript
  • axios
  • vue-router
  • element-plus
  • node.js

二、项目概述

界面展示

  • 登陆页面
    登陆页面
  • 商品管理
    商品管理
  • 用户列表
    用户列表
  • 员工信息编辑
    员工信息编辑
  • 职位编辑
    员工职位编辑
  • 修改权限界面(隐藏路由)
    修改权限界面(隐藏路由)
  • 本地接口数据
    本地接口数据

功能

* 实现登陆路由拦截,获取token后才能实现动态路由增加
* 实现商品的管理,可搜索关键字过滤,分页
* 实现公司人员的信息,职位的编辑
* 实现职位的树状权限编辑

重难点功能

动态路由和路由拦截

功能介绍:

在路由的 json 数据中添加路由信息,可以动态的在主界面左侧渲染出对应的标题
当用户还没有登陆时,localStorage没有token,这些路由不进行渲染,保证信息安全,同时重定向回到login路由。

image

实现思路:

  • 菜单栏的item渲染:
          <el-menu router active-text-color="#ffd04b" background-color="#545c64" class="el-menu-vertical-demo"
            :default-active="active" text-color="#fff">
            <el-menu-item v-for="i in list" :key="i.path" :index="i.path">
              <el-icon>
                <icon-menu />
              </el-icon>
              <span>{{i.meta.title}}</span>
            </el-menu-item>
          </el-menu>
代码中的item标签对list数据使用了v-for,调取了每一项的meta.title填充标题
这里的active是当前的路由,实现第一次登陆时,组件默认选中的item样式变化
list数据由useRouter中的getRoutes获取,路由在其他地方动态添加
  • 获取router路由列表和当前路由
  setup(){
    const router = useRouter()
    const route = useRoute()
    const list = router.getRoutes().filter(v => v.meta.isShow)
  return{
    list,
    active: route.path    // 获取当前路由
  }
  
  }
  • 路由拦截和动态添加路由
//路由拦截,动态路由在router这里做文章
router.beforeEach(async (to) => {//参数:去哪里,从哪来
  //如果没有登陆,进去登陆页面
  const token: string | null = localStorage.getItem('token') //联合类型,不一定拿得到token
  if (!token && to.path != "/login") {
    return '/login'
  } else if (to.path != '/login' && token) { //已登陆
    if (router.getRoutes().length == 2) {
      routerData.data.forEach((i: any) => {
        const routerObj: RouteRecordRaw = {
          path: i.path,
          name: i.name,
          meta: i.meta,
          //路径中的注释是方便webpack打包的,request保证引入什么名字文件就打包成什么名字的文件
          component: () => import(/*webpackChunkName: "[request]"*/ `../views/${i.name}.vue`)
        }
        router.addRoute("home", routerObj)
      })
      router.replace(to.path)
    }
  } else if (to.path == '/login' && token) {
    return '/'
  }
})
router的beforeEach有3个参数,to到哪去,from从哪来,next参数控制。to.path获取当前路径
所有路由动作都先经过这个beforeEach,所以可以在这里做登陆拦截。
- 注意:在确认用户成功登陆前,数据管理的路由是不可以添加进routes里的

* 如果没有token且当前路径不是/login的话,就return "/login",返回登录页
* 如果有token且且路径不是/login,就对路由进行渲染。
* 用router.getRoutes()获取当前已载入的路由数量,如果还是只有login和home两个,就使用router.addRoute给home添加子路由(实际路由数据从接口获取),实现动态路由。
* 添加完路由后,重新进入当前路径,使用router的replace方法
* 最后,如果已有token,但是用户到了/login下,直接跳转进入/home路径

数据筛选搜索

主要是使用filter函数对组件的数据源list进行操作
  • 对商品列表的筛选搜索
if (data.selectData.title) {
   arr = data.datalist.filter(v => (v.title.indexOf(data.selectData.title) != -1)
         || (v.body.indexOf(data.selectData.title) != -1)
   )
}
这里的selectData中的title和搜索输入框v-model双向绑定,
遍历所有数据datalist中的title或者body是否和输入框的title数据匹配,这里使用indexOf匹配string类型
然后将匹配到的项返回给arr新数组,再将其赋值给数据源list
  • 使用名字和职位两个搜索框进行双重筛选
            if (data.selectData.nickName || data.selectData.role) {
                if (data.selectData.nickName) {
                    arr = data.listData.filter((v:any) => v.nickName.indexOf(data.selectData.nickName) != -1)
                }
                if (data.selectData.role) { //在写回调函数时要注意花括号,有花括号记得return
                    arr = (data.selectData.nickName ? arr : data.listData).filter((v:any) =>
                        v.role.find((i:any) => i.role == data.selectData.role)
                    )
                }
            }
如果名字输入框不为空则使用上一个筛选过的arr继续筛选,否则直接对全部listData筛选
这里的role是数组,需要再调用find方法来判断筛选出的人的职位中是否含有限定输入框中的职位(一个职员可能有多职位)

数据分页

  • 对商品表格的分页处理
        const paging = (arr:ListInt[]) => {
            data.list = []
            for(let i = 0; i < arr.length; i++) {
                let ctn = arr.slice(i * 10, (i + 1) * 10)
                data.list.push(ctn)
            }
        }
对传入的数据进行切割摘取,每十条数据作为一项压入list数组中,
所以在定义ts类型时要把list设置为ListInt类型的二维数组
  • 获取当前页码
        const currentChange = (page:number) => {
            data.selectData.page = page -1
        }
element-plus组件中,分页的onclick触发事件默认带一个当前页码的参数
将页码赋值到data中,然后可以作为数组下标,来对之前创建的二维数组进行数据调用
  • 得到当前页码的数据
:data="list[selectData.page]"

职位信息的权限编辑

  • 获取当前选中的职位信息
            <template #default="scope">
                <el-button @click="authorityChange(scope.row)" type="text" size="small">
                    修改权限
                </el-button>
            </template>
这里的每行信息可以用element-plus提供的scope.row获取,传递给点击事件。
  • 编辑路由跳转
        const authorityChange = (row: ListInt) => {
            router.push({
                path: 'authority',
                query: {
                    id: row.roleId,
                    authority: row.authority.join('') 
                }
            })
        }
编辑页面是一个非显式的路由,点击编辑时才能进入,
进入到路由的同时,将参数给到router,可以在跳转路由后从router获取row的相关参数
  • 注意,这里相当于不同组件之间通过router路由进行传值,没有用到父子组件或者vuex
  • 编辑页面的组件获取router中的数据
        //获取router传过来的数据
        const route = useRoute()
        const query:any = route.query
        //reactive是让页面更新的
        const data = reactive(new InitData(query.id, query.authority))
这里使用了route直接获取路由中的query(之前设定的)
然后在InitData类中定义了一个构造器接收两个参数,便于new时接收参数
再使用reactive来初始化当前组件需要用到的所有data,这些数据都是定义在InitData中的
然后可以提交勾选好的权限信息给服务器,使用的组件信息是ref="XX",XX.getCheckedKeys()可以查看相关官方api
  • 个人理解:有点像数据的动态绑定,data中的属性,函数可以直接在js中操作,组件中调用

人员信息的权限编辑

使用弹框组件编辑,data中添加一个flag绑定组件的显示与否
获取选中信息的方法同上
双向绑定输入编辑框后可以直接获取弹框中需要修改的数据
  • 修改数据
        const userChange = () => {
            // obj是浅拷贝,可以直接操作list里面的对象
            const obj:any = data.list.find((v:any) => v.id == data.active.id)
            obj.nickName = data.active.nickName
            obj.role = data.roleList.filter((v:any) => 
			data.active.role.indexOf(v.roleId) != -1)
            data.isShow = false
        }
  • 这里的修改直接使用浅拷贝对list中对应id项修改
    role职位可多选,是一个数组,使用filter让对应的roleId代号进行匹配
posted @   一个斯帕纳  阅读(516)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示