vue3+te项目正式开发

vue3+te项目正式开发

1.样式初始化

1.1  normalize.css 对项目样式进行初始化

npm i normalize.css
import 'normalize.css'(main.js)

1.2 自定义样式文件

./assets/css/index.less 定义自定义的样式

body {
  padding: 0;
  margin: 0;
}

html, body, #app {
  width: 100%;
  height: 100%;
}

本项目用到的公共组件-components

所有项目的公共组件-base-ui 

2.封装公共模块

2.1 网络请求模块

解决刷新页面vuex中数据丢失的问题

在/store/index.ts 中导出一个函数setupStore,函数中执行各个模块自定义的从localStorage中加载数据的函数,判断当localStorage有值时,则保存到store中,在main.ts中导入setupStore并调用

2.2 utils公共工具模块

2.3 路由模块

2.3.1 导航守卫

        通过导航守卫,每次进行路由跳转前,判断如果要跳转去的路由不是登录界面,则去localStorage中读取token,如果token没有值,则跳转去login页面

2.3.2 setupStore() 刷新页面vuex数据不丢失

/store/index.ts 导出setupStore(),从localStorage中读取数据,如果数据不为空,则赋值给store.state,main.ts导入setupStore()并执行,则可以解决页面刷新vuex中数据丢失的问题。

注意:setupStore()需要在use(store)之前执行,否则页面刷新导航会出错

原因:刷新页面时,会重新加载页面执行main.ts,从上往下执行,执行use(store),会执行store中的install()函数,该函数会读取当前url,并从路由配置对象中进行匹配,若当前url对应的路由对象是动态加载的,则动态加载路由的操作是在执行setupStore(),从缓存中读取userMenu后,执行setMenu()之后进行的,因此setupStore()必须先执行,将动态路由加载好之后,在执行use(store)

2.4 vuex模块

在页面中使用useStore()对TS的支持不好,得到的store的类型是any,无法对store中的数据做类型检测,可以在./store.index.ts中自己定义一个useStore(),规定返回值的类型是IRootState&IModuleState,在函数内部返回vuex的useState()

3.登录模块

3.1 将账号登录-获取用户信息-获取用户菜单权限封装在vuex中login模块

3.2 登录成功后的处理流程

3.2.1 用户登录成功后,后端会返回token用于验证用户身份

  • 将token保存到store中
  • 并且保存到localStorage(避免页面刷新store中的数据丢失)
  • 在service封装的网络模块中,在interceptors.request.use的请求拦截中当存在token时,为每一个请求头添加token config.header.authorization = window.localStorage.getItem('token')

3.2.2 根据userId请求用户详细信息 

将获取的用户信息保存到vuex和localStorage

3.2.3 根据用户角色信息获取用户菜单权限

将获取的用户菜单保存到vuex和localStorage

3.2.4 跳转到首页

路由根路径redirect->登录界面 

4.首页 main/main.vue

4.1 结构设计

  • /main/main.vue:放各个组件的首页根组件
  • /main/xx/xx: 放首页的各模块组件
  • components/nav-nenu/src:侧边导航的组件
  • components/nav-header/src:头部的内容
  • components/nav-header/index.ts:对nav-header中的组件统一导出

4.2 动态路由

4.2.1 提前写好不同角色对应的路由数组,根据用户角色加载对应的数组

缺点:新增角色或者修改角色对应的权限时,只能修改前端代码

3.2.2 根据菜单动态生成路由映射

  • npm i coderwhy  --coderwhy老师自己写的库
  • coderwhy add3page user -d src/views/main/system/user --自动生成页面和router中的路由映射
  • 在src/views/main/system/user下生成user.vue文件,并且router/main/system/user/user.ts中生成映射关系
  • /utils/map-menu.ts 定义根据menu生成对应的路由配置对象的函数MenuToRouteMap()并导出
import { RouteRecordRaw } from 'vue-router'
export default function (menu: any[]): RouteRecordRaw[] {
  const routes: RouteRecordRaw[] = []

  // 1.获取所有已经定义过的路由映射对象
  const allRoutes: RouteRecordRaw[] = []
  const routeFiles = require.context('../router/main', true, /\.ts/)
  routeFiles.keys().forEach((item) => {
    const route = require(`../router/main${item.split('.')[1]}`)
    allRoutes.push(route.default)
  })

  // 2.根据菜单获取需要添加的routes
  // userMenus:
  // type === 1 -> children -> type === 1
  // type === 2 -> url -> route
  const _recurseGetRoute = (menu: any[]) => {
    for (const menuItem of menu) {
      if (menuItem.type === 2) {
        const route = allRoutes.find((routeItem) => {
          return routeItem.path === menuItem.url
        })
        if (route) {
          routes.push(route)
        }
      } else {
        _recurseGetRoute(menuItem.children)
      }
    }
  }
  _recurseGetRoute(menu)
  return routes
}
  • /store/login 的setMenus()中,调用MenuToRouteMap(state)获取该用户对应的路由映射对象,通过addRoute()添加到/main的children
 setMenus(state, payload: any) {
      console.log(payload)
      state.userMenus = payload
      const route = MenuToRouteMap(payload)
      route.forEach((item) => {
        router.addRoute('main', item)
      })
    }

4.3 侧边栏折叠

折叠按钮,icon,用户点击控制是否折叠-》main(控制宽度)->nav-nenu是否折叠()

nav-menu-index.ts 统一导出

在template中使用别名:~@

4.4 刷新页面定位到原来选中的目录

4.4.1 根据路径定位菜单

刷新页面时,定位到刷新之前的菜单

获取当前route->path,用path匹配userMenu中的url,匹配的那个menu的id赋值给default-active

同时可以获取当前页面的breadcrumb

匹配的函数封装在utils/pathMapToMenu.ts

export function pathMapToMenu(
  userMenus: any[],
  currentPath: string,
  breadcrumb?: IBreadcrumb[]
): any {
  for (const menu of userMenus) {
    if (menu.type === 1) {
      const findMenu = pathMapToMenu(menu.children ?? [], currentPath)
      if (findMenu) {
        breadcrumb?.push({ name: menu.name })
        breadcrumb?.push({ name: findMenu.name })
        return findMenu
      }
    } else if (menu.type === 2 && menu.url === currentPath) {
      return menu
    }
  }

4.4.2 /main重定向

根路径/:redirect:/home

/home->home.vue只显示侧边栏导航和头部,内容是由路由匹配到的子组件展示的,但是当用户第一次进入页面,或者在/main刷新页面时,main的内容部分就是空的,这就需要把/main重定向到第一个侧边导航,但是Home的子路由是动态生成的,要怎么实现/main的重定向呢?

setUserMenus()中根据导航生成路由时,保存第一个有路由页面的导航firstMenu,并导出

在路由守卫中判断,如果to='home',则读取firstMenu.url,跳转到该页面

5.搜索框封装

5.1 样式

  • 定义IForm,IFormItem类型
  • /base-ui/form/src/form中使用props接受IForm,并设置默认值
  • /base-ui/types/index.ts 声明所以类型
  • /base-ui/form/index.ts 对该组件所有内容进行统一导出,导入/types/index.ts和/src/form,并导出
  • 其他组件导入/base-ui/form,根据IForm定义搜索框数据

5.2 数据传递

5.2.1 form-item通过v-model直接修改父组件数据

父组件通过传递一个对象给form组件,form组件通过IFormItem.field属性绑定数据

缺点:子组件修改了父组件传递的数据,违背了单向数据流传递

5.2.2 真正的双向数据绑定

父组件通过v-model=formData传递一个const formData= ref()类型的对象

子组件let data = ref(...formData),子组件中绑定data,再监听data的变化,当变化是,emit('update:formData'),把数据传递给父组件,这种方式子组件并没有直接修改父组件的数据

5.3 form头部和底部的插槽与search-form

在封装的form组件中,提供两个插槽,分别是头部的插槽header(标题)和底部的插槽footer(可以放重置和查询按钮等)

components/page-search:封装一个新的组件,在内部使用form,并将搜索的头部和底部信息传递给form中的插槽,在组件中使用page-search,并把搜索框配置数据searchFormConfig传递给page-search

5.4 搜索与重置

搜索与重置按钮在<page-search>,<user>中使用<page-search>,<page-search>中使用<form>

3个组件中的formData需要同步,思路如下:

  • <form>和<page-search>通过v-model=‘formData’双向数据绑定,<form>中定义一个数据接受formData的拷贝,在页面中绑定到formData,再监听formData的变化,当发生变化时,将最新的数据发送到<page-search>
// 如果直接把modelValue绑定到form上,则当用户输入时,会直接修改modelValue的值,违背了单向数据流
const formData = ref({ ...prop.modelValue })

// 当用户输入的数据发送变化,把最新的数据发送到page-search
watch(
  formData,
   (newValue) => {
     emit('update:modelValue', newValue)
     },
   { deep: true }
)

当用户点击重置时, <page-search>需要重置formData,并且重新查询用户列表数据

当用户点击查询时,<page-search>需要携带最新的formData数据,并且重新查询用户列表数据

7.封装table

7.1 基础table的封装

基础的table封装在base-ui,多个项目都可以用,接收的数据如下:

  • 接受后端返回的原始数据listData
  • 表格样式数据contentTableConfig,包括title(表格标题),propList用来控制表格每一项数据的展示,包括label(表头)、prop(展示的数据),min-width,soltName等,showIndexColumn控制序号是否展示,showSelectColumn控制select是否展示

7.2 table中的插槽

7.2.1 表格数据中展示的内容

<template v-for="item in propData" :key="item.prop">
   <el-table-column v-bind="item">
      <template #default="scope">
         <slot :name="item.slotName" :row="scope.row">
            {{ scope.row[item.prop] }}
         </slot>
      </template>
   </el-table-column>
</template>

7.2.2 头部的插槽

7.2.3 底部的插槽

lot,作用域插槽,序号优化,选择,操作,header,分页

7.1各个模块的数据保存到store中,获取各模块数据的方法放到actions

8.全局属性

app.config.globalProperties:定义在这上面的变量在全局任意组件中都可以访问

app.config.perpories.$filters={}  :定义全局的filter

$filter.xx:页面中使用 

/global/register-properties/中导出配置变量

6.封装面包屑

1.将面包屑封装成一个组件

2.使用时,根据当前path生成数据传入面包屑组件,

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Vue3 + TypeScript 是一种常用的前端开发技术组合,它结合了Vue框架的便捷性和TypeScript的类型检查能力,可以提高项目的可维护性和开发效率。下面是一些Vue3 + TypeScript项目经验的介绍: 1. 项目初始化:使用Vue CLI创建一个Vue3项目,并选择TypeScript作为项目的语言。这样可以自动生成一些基本的配置和文件结构,方便快速开始开发。 2. 类型定义:在Vue3 + TypeScript项目中,可以使用TypeScript的类型系统来定义组件的props、data、computed等属性的类型,以及事件的参数类型等。这样可以在编码过程中及早发现潜在的类型错误,提高代码的健壮性。 3. 组件开发:在Vue3 + TypeScript项目中,可以使用装饰器(decorators)来定义组件选项,例如使用@Prop来定义props属性的类型,使用@Emit来定义事件的参数类型。这样可以更清晰地描述组件的接口和行为。 4. 路由管理:在Vue3 + TypeScript项目中,可以使用Vue Router进行路由管理。通过定义路由的类型和参数类型,可以在编码过程中获得更好的类型提示和错误检查。 5. 状态管理:在Vue3 + TypeScript项目中,可以使用Vuex进行状态管理。通过定义状态的类型和操作的参数类型,可以提高代码的可读性和可维护性。 6. 第三方库的使用:在Vue3 + TypeScript项目中,可以使用第三方库,并为其编写类型声明文件,以获得更好的类型检查和代码提示。例如,可以使用axios发送HTTP请求,并为其编写类型声明文件,以确保请求参数和响应数据的类型正确。 7. 单元测试:在Vue3 + TypeScript项目中,可以使用Jest等测试框架进行单元测试。通过编写类型安全的测试用例,可以提高代码的质量和可靠性。 8. 构建和部署:在Vue3 + TypeScript项目中,可以使用Webpack等构建工具进行项目的打包和优化。通过配置合适的TypeScript编译选项和Webpack插件,可以生成高效的生产环境代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值