添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
安静的人字拖  ·  sidekiq ...·  2 年前    · 

在后台管理系统中存在大量的字典数据,比如各种状态、类型。后端有时会返回字典的code,前端需要通过字典表来渲染出对应的文字,有的后端比较体贴直接给我们字典的文字,前端无需处理即可展示。

但是,为了优化用户体验,常常需要对不同的字典code显示不同的UI效果,比如“禁用”使用红色标签,“启用”使用绿色,这样页面可读性就会好很多。

最简单的写法,直接在表格插槽中写:

<el-table-column label="状态">
    <template #default="scope">
       <el-tag :type="scope.row.status === '0' ? 'danger' : 'success'">
           {{ scope.row.status === '0' ? '禁用' : '启用' }}
       </el-tag>
    </template>
</el-table-column>

如果使用字典的地方很少,字典也不会变,这样写没问题。但是实际系统中往往定义了几十上百个字典类型,每个类型下的字典项也会变化,上面的写法就显得吃力了,这时封装一个字典标签组件非常必要。

约定接口请求和返回

在apiFox中新建一个接口/getDicts,用于mock返回

建立了2个期望,用于模拟不同字典类型的返回值

在项目中配置好api并使用后,可以看到如期返回

在页面中获取字典数据

给字典组件添加字典数据源,在我经历过的代码汇中,见过3种方式:

  • 在字典组件中请求接口,获取数据源
  • 把数据源一次性保存到vuex中
  • 每次进入页面获取数据源
  • 第一种每用一次字典组件就会发送一次请求,太频繁了。 第二种基本不需要几次请求,但是数据变化不及时,如果在使用期间修改字典选项,前端没反应。 我觉得第三种更合理,实现起来也不麻烦 😁。

    进入页面,就获取所需字典的数据源,这里采用vue3的组合式函数(hook),让代码更加简洁高效

    hooks/useDict.ts

    一个页面可能有多个字典类型,此处接口只能查询一个类型,所以需要用Promise.all配合forEach返回数组中所有类型的字典选项。

    当然也可以把mock接口改成支持多个类型的(前端更简单),但是想试试promise.all所以没改,大家可以根据实际情况修改。

    import { reactive, onMounted } from 'vue'
    import system from '~/api/system'
    import systemApi from '~/api/system'
    export function useDict(dictType: Array<string>) {
      let dicts = reactive<any>({})
      onMounted(() => {
        let ps: Promise<any>[] = []
        dictType.forEach((dt, index) => {
          ps[index] = systemApi.getDicts(dt).then((res) => {
            return { type: dt, values: res }
        Promise.all(ps).then((res) => {
          res.forEach((val) => {
            dicts[val.type] = val.values
      return { dicts }
    

    在页面中使用

    import { useDict } from '~/hooks/useDict'
    let { dicts } = useDict(['status', 'clientType'])
    

    基于el-tag,二次封装字典组件

     <el-table-column label="状态">
              <template #default="scope">
                <MoDict :value="scope.row.status" :dicts="dicts.status" />
              </template>
            </el-table-column>
    </template>
    

    根据和后端约定好的字典结构,定义一个字典元素接口 DictItem

    interface DictItem {
      label: string
      value: string
      type?: string
      class?: string
      effect?: string
    

    组件props,使用Dict组件时,只需传入字典选项的的数组和字段值,然后一切交给组件来处理

    const props = defineProps<{
      value: string
      dicts: any
    

    给组件增加对应的参数,选择了一些el-tag的属性,如有需要可以继续扩展。

    属性名说明类型默认
    typeTag 的类型enum**''
    effectTag 的主题enum**light
    const item = props.dicts.find((val: DictItem) => val.value === props.value) as unknown as DictItem
    const label = item.label || props.value
    const tagType = item.type
    const tagClass = item.class || ''
    const tagEffect = item.effect || 'light'
    

    今天又被自己蠢哭了,在我写完以上useDict的hook后,网络请求始终只有最后一个字典类型,无论如何都不返回2个。改成直接用axios.get请求又是正常的。难道二次封装的axois有问题??? 看了半天也没看出问题。

    在不断试错中,终于发现问题,之前封装axios的时候,不是增加了取消请求方法么,这个消失的请求就是被取消了。。。 然而F12并没有看出来“已取消”而是直接不见了。

    找到取消请求拼接标识这块,补上get请求参数,一切正常。

    function getRequestKey(config: AxiosRequestConfig) {
      return (
        (config.method || '') +
        config.url +
        '?' +
        qs.stringify(config?.data) +
        qs.stringify(config?.params)  // 漏了这一截,get请求的参数没有拼接
    

    这里不仅仅是浪费了我1个多小时的时间,还让人非常焦躁,怀疑自己对promise、axios的理解出了问题。实际还是在写代码时不够严谨,测试不完全,基础没打好,后面容易出问题。

    本项目GIT地址:github.com/lucidity99/…

    如果有帮助,给个star ✨ 点个赞👍

  • 私信