使用hooks抽离逻辑结合享元模式等实现逻辑复用和文件规范

94 阅读5分钟

最近接到了一个老项目的翻新工作,结束了总结一下自己的经验方法

使用hooks抽离常用的逻辑,然后使用一套逻辑匹配多种UI版式来提高工作效率

一、以常见的列表展示形式为例子 1.在PC上有列表展示的方式,有卡片展示的方式,有整页轮播的方式等等一系列,通常我们为了适配UI会去实现多个vue,*sx文件,当需求任务样式慢慢的迭代,内容就会慢慢的变得不可控,代码的稳健性会大幅度下降我们可能会写出下面这些代码
// 文件1
interface 列表1的文件参数 {
  // 数据
  data: any[]
  //... xxx一系列参数
}
defineOptions({
  name: "文件1",
})

defineProps<IListProps>()

这是第二个样式的列表

// 文件2
interface 列表2的文件参数 {
  // 数据
  data: any[]
  //... xxx一系列参数
}
defineOptions({
  name: "文件2",
})

defineProps<IListProps>()

这是第三个样式的列表(以此类推,可能慢慢就会有很多参数类似,只是样式大同小异的文件出现)

// 文件3
interface 列表3的文件参数 {
  // 数据
  data: any[]
  //... xxx一系列参数
}
defineOptions({
  name: "文件3",
})

defineProps<IListProps>()

聪明的你一定可以想得到抽离逻辑,然后通过type去区分以及写一个大的props涵盖之前所有的参数来保证之前的控件不出问题 最终可能会写成这样

// 大合集文件
interface 大合集文件的文件参数 {
  // 数据
  data: any[]
  // 判断是什么类型的列表
  type:"1"|"2"|"3"|"4"|"5"|"6"....
  //... xxx一系列参数 包含之前的列表的文件
}
defineOptions({
  name: "大合集文件",
})

const props =  defineProps<IListProps>()
// 模拟场景 为了保证不影响 还可能会在判断里面加上return 来确保逻辑的正确执行
function test(){
    if(props.type==="1"){
        // 做什么
    }
    if(props.type==="2"){
        // 做什么
    }
    if(props.type==="3"){
        // 做什么
    }
    if(["5","6"]){
    // ...
    }
}

当这么一个大而全的列表经历1到2年的迭代可能会慢慢的面目全非,然后会变得难以维护。这个时候就可以试试把逻辑单独写出来(参考了设计模式

设计思路

  1. 抽离共有逻辑
  2. 留出位置可以绑定不同UI实现同时不影响原有功能(单一原则)
  3. 图片所示

image.png 大致就是这样的一个思路 公共逻辑 对外暴露的模块 + 一个符合条件的UI文件 就可以组成一个列表了 下面看看代码 公共逻辑 对外暴露的模块

// 名字你们自己看着起 可能需要props和emits 先定义 但是可以为空
export function use公共部分(props={},emits=null){
    function 获取表格数据
    function 上一页
    function 下一页
    // 你需要的一切方法
    function ...
}

export function use外暴露的模块(props={},emits=null){
    // 需要绑定的组件提供的内容
    const Instance = ref(null)
    // 绑定的方法
  function register(instance) {
    if (!instance) return console.error('instance is required')
    if (instance) {
      popupInstance.value = instance
    }
  }
  function 类型1需要的方法(){
      //类型1你需要做的事情 额外判断一下防止在渲染前调用(可以写一个数组去维护 然后在生命周期里面执行
      // 当执行完了 就清空数组 这样可以不判断
     if (Instance.value && Instance.value.你的方法名
      Instance.value.你的方法名()
    }
  }
 function 类型2需要的方法(){
       //类型2你需要做的事情 额外判断一下防止在渲染前调用(可以写一个数组去维护 然后在生命周期里面执行
      // 当执行完了 就清空数组 这样可以不判断
     if (Instance.value && Instance.value.你的方法名
      Instance.value.你的方法名()
    }
  }
  function 类型3需要的方法(){
       //类型3你需要做的事情 额外判断一下防止在渲染前调用(可以写一个数组去维护 然后在生命周期里面执行
      // 当执行完了 就清空数组 这样可以不判断
     if (Instance.value && Instance.value.你的方法名
      Instance.value.你的方法名()
    }
  }
  //这里导出数组混对象  是为了一个页面有多个名字的时候方便起别名,然后数组的形式更加特殊也方便理解
  return [register, { 类型1需要的方法,类型2需要的方法,类型3需要的方法}]
}

需要匹配的的UI文件

// UI样式1
const {方法1} = use公共部分()    
// 叫啥名不重要只要有就行
const emit = defineEmits(['register'])
onMounted(() => {
  emit('register', {
    样式1的方法1,
    样式1的方法2,
    样式1的方法3,
  })
})

// UI样式2
const {方法2} = use公共部分()    
// 叫啥名不重要只要有就行
const emit = defineEmits(['register'])
// 如果都在公共里面 可以直接用 不需要这么麻烦 我写这么多主要是为了举例子
onMounted(() => {
  emit('register', {
    样式2的方法1,
    样式2的方法2,
    样式2的方法3,
    样式2的特殊方法1
  })
})


// 调用UI文件的地方
<script setup lang="ts">
const [register,{你需要的方法}] = use外暴露的模块({...一系列参数})
// 在你需要的时候 执行你需要的方法 这样更加的灵活可控
</script>
 <template>
   <UI样式1 @register="register">
      
    </UI样式1>
 </template>
 
 
 
 // 不同的ui使用相同的逻辑
 <script setup lang="ts">
const [register,{你需要的方法2}]=use外暴露的模块({...一系列参数})
</script>
 <template>
   <UI样式2 @register="register">
      
    </UI样式2>
 </template>

这样通过hooks+设计 把逻辑统一到了一个文件里面,后期维护也是可以维护在一起,这样哪怕是多人协同维护同一个文件,也可以知道有没有可以共有的部分,能够很大程度减少资源的浪费以及复用他人的功能。(因为通过设计模式把所有的资源约束到了一条主线上)

有不懂的小伙伴可以留言,一起探讨。

以上就是经验方法的总结