• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

github开源组件库提 PR

武飞扬头像
是明明就
帮助79

在 Vant UI 组件库中使用 TreeSelect 分类选择组件时,可以使用 content 插槽自定义右侧区域内容,那么左侧是否也可以自定义呢?

有人提出了这样一个 Issue ,并且被贴上 PR welcome 标签

[Feature Request] van-tree-select 最左侧希望可以插入html

最近正好在看 Vant 源码,于是我就尝试去实现这个 feature

初次尝试

对于这个功能首先让我想到的是平时使用最多的 dialog 弹出框组件,当使用函数调用时,组件提供了一个选项 allowHtml 表示是否允许在弹出框内容中渲染 HTML

同理,我在 TreeSelect 组件中也加上了这个逻辑,让组件左侧的 Sidebar 也能自定义

 const renderSidebar = () => {
    const Items = props.items.map((item) => {
    const renderContent = item.allowHtml ? (
      <div innerHTML={String(item.text)} />
    ) : (
      <>{item.text}</>
    );

    return (
      <SidebarItem
            dot={item.dot}
            badge={item.badge}
            class={[bem('nav-item'), item.className]}
            disabled={item.disabled}
            onClick={onClickSidebarItem}
            v-slots={{ title: renderContent }}
      />
    );
});

开发者在使用该组件时,需要提前定义TreeSelectItem 数据结构:

[
  {
    // 导航名称
    text: '所有城市',
    // 导航名称右上角徽标
    badge: 3,
    // 是否在导航名称右上角显示小红点
    dot: true,
    // 导航节点额外类名
    className: 'my-class',
    // 是否允许 text 内容中渲染 HTML
    allowHtml: true,
    // 该导航下所有的可选项
    children: [
      {
        // 名称
        text: '<span style="color:red;">温州</span>',
        // id,作为匹配选中状态的标识符
        id: 1,
        // 禁用选项
        disabled: true,
      },
      {
        text: '杭州',
        id: 2,
      },
    ],
  },
];

相较于之前增加了allowHtml 选项,用于判断是否允许使用 HTML 自定义 text 中的内容。加上对应的文档描述就提交了 PR

一周后,Vant 核心维护者回复了我:

他认为提供一个 slot 会比一个 prop 好,主要有两个原因:

  1. slot 可以渲染 Vue 组件,prop 只能渲染 HTML
  2. 提供 prop 渲染自定义 HTML 可能会导致 XSS 安全问题

再次尝试

 const Items = props.items.map((item) => (
    <SidebarItem
      dot={item.dot}
      title={item.text}
      badge={item.badge}
      class={[bem('nav-item'), item.className]}
      disabled={item.disabled}
      onClick={onClickSidebarItem}
      v-slots={{ title: slots['nav-text']?.() }}
    />
));

这次就简单多了,核心代码就一句:

v-slots={{ title: slots['nav-text']?.() }}

判断开发者是否传入了 nav-text 这个 slot,将其结果再次传入给 SidebarItem 组件名为 title 的 slot ,在此其中也做了判断:

// SidebarItem 组件
{slots.title ? slots.title() : title}

这样一来就实现了自定义组件左侧 Sidebar 内容的需求

终于,我的 PR 被合并了,成为了 Contributor , 在 README 中也可以看到我的头像

后续

Vant 核心维护者对我提交的代码做了一些优化:

  1. 移除了组件 prop 传入 text 的方式,改用在 slot 中使用三元运算符判断传入。
  2. 优化文档描述
  3. 针对该 feature 增加单元测试
const Items = props.items.map((item) => (
    <SidebarItem
      dot={item.dot}
      badge={item.badge}
      class={[bem('nav-item'), item.className]}
      disabled={item.disabled}
      onClick={onClickSidebarItem}
      v-slots={{
        title: () =>
          slots['nav-text'] ? slots['nav-text'](item) : item.text,
      }}
    />
));

目前该 feature 已在 v4.1.0 中正式被发布,详情见 更新日志

总结

通过参与开源项目,可以提高自己的技术水平和知名度,在贡献的过程中,可以学到更多的知识和技能。如果你也在学习源码,不妨试着给项目提一个 PR 吧

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanfekif
系列文章
更多 icon
同类精品
更多 icon
继续加载