前端组件抽取

前言

纯菜鸡记录

业务场景

[图片上传失败...(image-ed53dd-1658375271104)]

  • 拆分思路:
  1. 根据业务,可以分成 nav(面包屑+树状导航)、page(内容展示);根据内容展示的不同,还可以继续拆分
  2. 根据项目结构,可以分为xxx.vue(页面)、data_xx.ts(接口)、use_xx.ts(逻辑),还有其他文件,如常量管理、路由管理、鉴权管理等
  • 拆分方向:

拆分足够细,尽量使用函数式编程(有很多方向,只是选择了其中的一种)

  • 以拆分nav(面包屑+树状导航)为例

文件结构:

[图片上传失败...(image-670478-1658375271104)]

/*
* bread-crumb.vue
* 面包屑页面:包含页面需要的数据以及跳转功能
* data_nav.ts
* nav(面包屑+树状导航)相关接口文件及简单数据处理
* index.vue
* nav(面包屑+树状导航)入口页面(布局、提供各个子页面所需的数据
* interface.ts
* typescript相关接口定义等
* tree.vue和tree_menu.vue
* 树状导航:包含页面需要的数据以及跳转功能
* use_base.ts
* 组装全局所需的一些字段,如 id 等
* use_nav.ts
* 组装nav(面包屑+树状导航)所需的数据
* use_router.ts
* 跳转功能封装
*/
  • 不同业务模块之间的数据交互(在交互设计上,需要尽可能做到功能分离化)

在nav(面包屑+树状导航)模块定义:

/**
 * use_base.ts
 * 基本信息钩子:暴露了基本数据base,并且provide了可供全局使用的数据和方法
 */
import { provide, computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { BASE, BASE_ID_OPEN } from './constant'

function fmtId(v?: string) {
  return v || ''
}


export function useBase() {
  const router = useRouter()
  const route = useRoute()


  const base = computed(() => {
    return {
      id: fmtId(route.query.id as string),
      parentId: fmtId(route.query.parentId as string)
    }
  })

  provide(BASE, base)

  provide(BASE_ID_OPEN, (id: string) => {
    router.push({ query: { id } })
  })


  return {
    base
  }
}

在内容展示模块使用:

// use_main.ts
import { computed, ComputedRef, inject, watch } from 'vue'
import { BASE, CHAIN, BASE_ID_OPEN } from './constant'
import { TribeData } from './interface'

export function useMain() {
  const base = inject>(BASE, computed(() => ({
    id: '',
    parentId: ''
  })))

  const openId = inject<(id: string) => void>(BASE_ID_OPEN)

  const updateChain = (name: string) => {
    const lastChainItem = chain.value[chain.value.length - 1]
    lastChainItem.label = name
  }

  return {
    base,
    openId,
    chain,
    updateChain
  }
}

这样,在内容展示模块就可以使用这些基本信息和方法了。

补充:
最近遇到了这样一个场景(如下图)

[图片上传失败...(image-4f9ae9-1658375271104)]

页面上的表格和弹窗中的表格其实会调同一个接口,由于页面上可操作这个表格,进行新增、编辑和删除等,而弹窗中的表格是全量数据(先不谈展示优化)

因此,为保证弹窗中的表格数据要与页面的保持一致,需要每弹出一次弹窗就要调一下全量数据的接口。

但是根据需求分析,有一些状态下,页面表格是不可操作状态的,也就意味着,弹窗数据不会发生变化,此时,就可以将请求返回的数据缓存起来,不必每次点击查看就发起请求了。

// use_cache.ts

import { computed, ref, watch, reactive } from 'vue'

import { getXXX } from './data_XXX'
import { showError } from '@/XXX'
import type { IXXX } from './interface'

// 页面数据缓存池
export const poolList: Record = {}

// 用于显示更多信息
export function useCache() {
  // 是否发请求
  const noCache = ref(true)
  // 区分数据缓存池中不同数据的标识
  const cacheId = ref()

  const cache = reactive>([])

  async function echo() {
    const id = cacheId.value
    if (id === undefined) { return }
    if (noCache.value && !(poolList[id])) {
      try {
        const ret = await getXXX({
          id,
          current: -1
        })
        poolList[id] = ret.list
        Object.assign(cache, ret.list)
      } catch (err) {
        showError(err)
      }
    }
  }

  return {
    noCache,
    cacheId,
    cache,
    echo
  }
}

// 弹窗




如果后台配合的话,还可以做的更多,比如后台返回一个数据id,记录这份数据的更新,每一次更新都会改变这个字段,这样就可以将这个字段与cacheId组合起来区分数据缓存池中的不同数据

你可能感兴趣的:(前端组件抽取)