最近做开源的一些思考和收获

前言

最近给 varlet 组件库的 checkbox group 组件添加了一些新的feature,如optionslabel-keyvalue-key,这里记录下我的思考和收获。

支持 options

支持 options 的缘由

这个最开始考虑支持是因为这个 issue

耗子哥 商量了下,准备开始先支持 options,再去做这个组件

支持 options 的好处

简化代码结构

不用手动重复定义每个复选框的代码,只需在 options 属性中简单地传递复选框列表

动态生成

通过编程方式可以方便地动态生成或变更复选框选项,例如从后端获取数据后直接设置成 options

统一管理和配置

所有选项可以集中在一个数据结构中维护,方便在整个组件中统一对复选框选项数据的管理和使用,比如开关选项排布,值有所变更等均可写入该结构的逻辑内。

实现考量

label

这个字段在设计的时候,考虑支持三种类型,分别是 stringVNodeFunction,如下

ts 复制代码
export type CheckboxGroupOptionLabelRender = (option: CheckboxGroupOption, checked: boolean) => VNodeChild

export interface CheckboxGroupOption {
  label?: string | VNode | CheckboxGroupOptionLabelRender
  value?: any
  disabled?: boolean

  [key: PropertyKey]: any
}

最开始,我写这块内容的时候,考虑支持的是 label 插槽,类似于

后面和耗子哥交流了下,找到了另外一个思路,目前收集组件这种实现方式就很类似于插槽,开发者如果想使用 VNode 的话是行不通的,比如我想拿 h 函数来展示标签,模板是不支持的,就确定要支持VNode,考虑借助 tsx 的能力来实现。

支持 label-key 和 value-key

为什么要支持 label-key 和 value-key

为什么要支持 label-keyvalue-key 呢?这个我思考了下,感觉有以下几个方面

通用性与配置性

label-key 允许指定数据源中哪个属性应该显示给用户。数据源(通常是一个数据对象数组)上的属性名字可以不固定,通过配置 label-key,组件变得更加通用和可重用。例如,不同的应用场景可能有不同的数据接口

js 复制代码
const options1 = [ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' } ]; 

const options2 = [ 
  { id: 'a', transportation: 'Car' }, 
  { id: 'b', transportation: 'Bike' } 
 ]; 
html 复制代码
<CheckboxGroup options={options1} labelKey="name" /> 

<CheckboxGroup options={options2} labelKey="transportation" /> 

国际化

在国际化或者多语言支持的场景下,不同语言可能会有不同的展示文案。label-key 可以灵活地允许开发者动态更改显示语言

js 复制代码
const options = [ 
  { id: 1, enName: 'Apple', esName: 'Manzana' }, 
  { id: 2, enName: 'Orange', esName: 'Naranja' } 
]; 
html 复制代码
<CheckboxGroup options={options} labelKey={isSpanish ? 'esName' : 'enName'} />

自定义渲染

在某些复杂场景下,数据展示不一定是单一属性。例如

js 复制代码
const options = [ 
  { id: 1, firstName: 'Alice', lastName: 'Smith' }, 
  { id: 2, firstName: 'Bob', lastName: 'Johnson' } 
];
html 复制代码
<CheckboxGroup 
  options={options} 
  labelKey={(option) => `${option.firstName} ${option.lastName}`} 
/> 

代码

jsx 复制代码
import { defineComponent, type PropType } from 'vue'
import { isFunction } from '@varlet/shared'
import { CheckboxGroupOption } from './props'
import { createNamespace } from '../utils/components'
import Checkbox from '../checkbox'

const { name } = createNamespace('checkbox-group-option')

export default defineComponent({
  name,
  props: {
    labelKey: {
      type: String,
      required: true,
    },
    valueKey: {
      type: String,
      required: true,
    },
    option: {
      type: Object as PropType<CheckboxGroupOption>,
      required: true,
    },
  },
  setup(props) {
    return () => {
      const { option, labelKey, valueKey } = props

      return (
        <Checkbox checkedValue={option[valueKey]} disabled={option.disabled}>
          {{
            default: ({ checked }: { checked: boolean }) =>
              isFunction(option[labelKey]) ? option[labelKey](option, checked) : option[labelKey],
          }}
        </Checkbox>
      )
    }
  },
})

高内聚概念的实践

相信很多掘友都听说过 高内聚低耦合 这个软件工程的概念,我刚开始参加工作的时候,也知道这个概念,但是自己在真正的编码过程中,很少意识到自己可以主动践行这个概念。

前两天早上起床的时候,我打开微信,看到了耗子哥给我的留言,

一下子就想到了 高内聚 这个概念,对于 checkbox 组件,是否选中这个状态,是由它本身产生并控制的;而对于 checkbox group 组件,渲染出来的每一个 checkbox 组件,都能获取到组件是否被选中了。

但是,这里有两种思路去实现。

checkbox group 组件自己处理选中状态

checkbox group 组件这里加个判断,当前这个 optionvalue 是否在 modelValue 这个数组里面,对应我pr里面的code就是

checkbox 组件通过插槽暴露选中状态

checkbox 组件有几个插槽,如下图

其中,三个是 icon 相关的,肯定不合适,因为这三个插槽和选中状态没有深的关联,一般作为ui展示部分。

对于默认插槽,一般会渲染选项的标签,是比较适合来传递选中状态的,对应pr的code是

第二种选择就对应了 高内聚 概念,选中这个状态只有 checkbox 组件本身去控制,其他地方需要,可以通过插槽去接收,而第一种就显得代码会不凝练,假如我有需要去修改选中这块逻辑,那我两个地方都要改,而且要做出一样的改动,维护的成本就无形之中增加了。

结尾

以上就是我要分享的全部内容了,如有错误,欢迎指正~

相关推荐
扬帆破浪4 分钟前
免费开源AI软件.桌面单机版,可移动的AI知识库,察元 AI桌面版:本地离线知识库的妥协与收益 老电脑跑察元AI的可行边界
人工智能·windows·开源·电脑·知识图谱
我命由我1234513 分钟前
Dart - Dart SDK、Hello World 案例、变量声明、常量声明、常量 final、字符串类型
前端·flutter·前端框架·html·web·dart·web app
冴羽yayujs15 分钟前
GitHub 前端热榜项目 - 日榜(2026-05-11)
前端·github
~|Bernard|16 分钟前
四,go语言中GMP调度模型
java·前端·golang
YOU OU24 分钟前
HTML+CSS+JavaScript
前端·javascript·css·html
xmdy586626 分钟前
Flutter+开源鸿蒙实战|校园易生活Day7 个人中心完善+我的发布/收藏+退出登录+主题切换+全局UI美化(项目闭环)
flutter·开源·harmonyos
一直会游泳的小猫38 分钟前
UI-TARS-desktop
开源·字节跳动·bytedance·多模态gui agent
Rkgua40 分钟前
路径传参和查询传参和请求体传参区以及Vue和React的用法区分
前端·面试
JarvanMo41 分钟前
Flutter + Supabase 集成 Apple Sign-In 完整指南
前端
扬帆破浪1 小时前
免费开源AI软件.桌面单机版,可移动的AI知识库,察元 AI桌面版:本地离线知识库的真完全离线 内网无外网装察元AI的拼装步骤
人工智能·windows·开源·电脑·知识图谱