vue3组件库项目学习笔记(七):正式开发问题拾遗

news2025/1/18 16:59:03

目前组件库的开发还在进行中,这里把一些开发过程中遇到的问题和解决方案总结一下,也方便后续开发的同学踩坑了可以马上解决问题,这期的问题主要是:

  • 多项目开发的配置文件优化和全局导入方法的修改
  • 怎么样使用 icon 组件
  • 怎么样使用做组件协作开发

想要看代码的可以直接前往我的 github:https://github.com/aiai0603/seven-bit-ui

想要使用我的组件库的可以直接下载:seven-bit-ui (原来的名字被占用了所以我换了一个)

配置文件优化

按照上一篇的结构搭建的项目还有几个需要优化的地方,这里我说一下:

我们在完成我们的结构之后发现,我们的项目在根目录使用 pnpm run build 命令的时候报错了,提示我们不能使用 require,这里不知道为什么产生了这样的问题,应该是部分包的效果导致的,但是你只要修改根目录的 tsconfig.json 文件,把 module 项目修改即可:

"module": "commonjs",

版本号注意点

之后就是我们需要优化我们的项目编号来解决 pnpm 安装错误的问题,目前我们的项目分为三个,

  • 一个我们本地开发的版本,这个版本在 packages/components/package.json 这个文件中定义
  • 一个是打包后的版本,这个版本的包在 packages/components/transitpkg/package.json 这个文件中,当我们发布以后,它还会存在在 packages/components/dist/package.json ,两者的package.json 编号是一致的
  • 最后一个是我们 publish 上去的包

这三个包分别有什么用呢?

  • 我们本地开发版本的包,如果我们在 examples 上安装了它,当我们在 packages/components 中修改我们的代码的时候,examples 中安装的版本会直接和我们修改的代码同步,所以我们在 examples 中安装它可以快速的测试我们编写的组件,作者将它的版本编写为 0.0.1
  • 当我们打包完成的时候,我们可以在本地安装我们的打包版本来测试我们的项目打包后是否正常,我们需要的操作是,首先将我们的transitpkg/package.json 复制到 dist 文件夹下,因为只有 publish 命令会干这个事情,在我们发布之前测试的话我们需要手动干这个事情,之后我们需要修改 transitpkg/package.json 中的版本号,因为如果存在两个一样的版本号,pnpm 遍历的时候可能会直接安装 transitpkg/package.json 的项目,但是这个项目是空的,然后我们根据我们 dist/package.json 的版本号来安装我们的项目,就可以安装上我们打包好的项目了
  • 当我们把项目上传到 npm ,我们就可以在任何地方使用我们的组件库,比如你的个人博客项目中,你可以在本地新建一个 vue 项目来测试你的组件库

全局安装和局部引用

这里作者被坑了好久,认真学习了以后,我们从原理说起:

当我们使用这样的方式导出我们的组件的时候

export { sbButton, sbLink, sbIcon, sbCol, sbRow, sbModal, sbProgress, sbBread, sbBreadItem };

如果我们需要在项目中引用我们的组件,我们需要:

import  { sbButton } from 'seven-bit-ui'

当我们需要使用 app.use 来安装我们的组件的时候,我们需要给我们的组件一个 install 方法,所以在导出组件的时候,我们为他提供了一个方法:(这里把 withInstall 拿出来是为了方便演示,你应该把它放在单独的一个 utils 中正如之前教程说的那样)

import Button from './sbButton.vue';

const withInstall = (comp: any) => {
  comp.install = (app: any) => {
    //注册组件
    app.component(comp.__name, comp);
  };
  return comp;
};

const sbButton = withInstall(Button);
export default sbButton;

如果我们需要用户直接导入我们的整个组件库,我们可以使用,我们需要为我们的整个组件库提供一个方法来安装所有的组件:

const components = [sbButton, sbLink, sbIcon, sbCol, sbRow, sbBread, sbBreadItem, sbModal, sbProgress];
export default {
  install: (app: any) => {
    for (const comkey in components) {
      app.component(components[comkey].__name, components[comkey]);
    }
  }
};

这样之后我们就支持使用单独安装和全部安装两种方式来引入我们的组件,像这样:

import sbui from 'seven-bit-ui';
const app = createApp(App);
app.use(sbui);

import  { sbButton } from 'seven-bit-ui'
const app = createApp(App);
app.use(sbButton);

所以最后我们的整个目录修改成这样:

  • 在 packages / components / src 文件夹的有一个总的 inex.ts,提供全局安装方法,并且导出所有的组件,像这样:

    import { default as sbButton } from './sbButton';
    import { default as sbLink } from './sbLink';
    import { default as sbModal } from './sbModal';
    import { default as sbProgress } from './sbProgress';
    import { default as sbIcon } from './sbIcon';
    import { default as sbCol } from './sbCol';
    import { default as sbRow } from './sbRow';
    import { default as sbBread } from './sbBread';
    import { default as sbBreadItem } from './sbBreadItem';
    const components = [sbButton, sbLink, sbIcon, sbCol, sbRow, sbBread, sbBreadItem, sbModal, sbProgress];
    export default {
      install: (app: any) => {
        for (const comkey in components) {
          app.component(components[comkey].__name, components[comkey]);
        }
      }
    };
    export { sbButton, sbLink, sbIcon, sbCol, sbRow, sbModal, sbProgress, sbBread, sbBreadItem };
    
  • 而在 src 下的每个组件的文件夹的 index.ts 文件里,我们需要为每个组件单独提供install 方法:

    import Button from './sbButton.vue';
    const withInstall = (comp: any) => {
      comp.install = (app: any) => {
        app.component(comp.__name, comp);
      };
      return comp;
    };
    const sbButton = withInstall(Button);
    export default sbButton;
    

最后作者发现之前我们在 components 文件夹下面也放一个 index.ts 进行操作,这样会导致打包的时候全局安装的方法打包不进去,所以我们将全局安装的方法安排到了 components / src / index.ts 中,任何我们需要将 packages/components/package.json 进行修改,把 main 入口的内容进行修改:

"main": "src/index.ts",

引用iconfont

显然在开发 icon 组件的时候,我们会觉得自己设计 svg 是吃力不讨好的,除非你需要证明你设计方面的技能,所以我们一般会选择使用现有的 icon 设计,这里我们选择 iconfont ,地址是:https://www.iconfont.cn/

下面是一个简单教你引入 iconfont 资源为自己组件的方案

首先我们注册一个自己的账号,创建一个自己的项目,在 资源管理——我的项目 就可以创建项目了,然后注意在创建的时候 FontClass/Symbol 前缀 这一项改成我们项目的名字,比如我改成了 sb-icon-,那么我们到时候引用项目的时候需要使用 sb-icon-xxx 来引用我们的图标,可以防止和其他人的重名,其他的项目配置默认即可
请添加图片描述

之后我们可以直接选择一个图标,添加入库,也就是点击购物车的图标

请添加图片描述

之后我们点击最上方右侧的购物车将我们选择的图标添加到我们的项目:

请添加图片描述

最后我们导出我们的整个项目的代码,我们进入我的项目,选择我们创建的项目,点击下载至本地:

请添加图片描述

这时候我们得到了一个 zip 文件,解压它,取出其中的 iconfont.js 这是我们需要的内容,我们进入我们编写的 icon 组件:

我们引入我们的 iconfont.js ,你可以选择把它放在其他位置,这是你的自由,然后将你的 template 按照作者的方式编写,然后动态生成 iconName 就行了,此时你的用户只需要传入一个 name 就可以展示对应的图标

<template>
  <svg aria-hidden="true" v-bind="attrs">
    <use :xlink:href="iconName"></use>
  </svg>
</template>
<script lang="ts" setup>
  import './font/iconfont.js';
  import './style/index.less';
  import { computed, useAttrs } from 'vue';
  import { iconProps } from './types';
  const props = defineProps(iconProps);
  const attrs = useAttrs();

  const iconName = computed(() => {
    return `#sb-icon-${props.name}`;
  });
</script>

多组件协作

开发面包屑的时候遇到了问题,我们希望我们可以配置我们组件的面包屑间隔图标,比如我希望我的面包屑是 a / b / c 的形式,而另一个人希望是 a > b > c 这样的形式,但是我们的面包屑一般是这样的形式:

  <sb-bread>
      <sb-bread-item>111</sb-bread-item>
      <sb-bread-item href="#">222</sb-bread-item>
      <sb-bread-item>333</sb-bread-item>
   </sb-bread>

你不知道你有几个子项目,你需要在 sb-bread 这个父组件里将信息分发给下面的子项目,但是你有不确定有没有子组件,类似这样:

  <sb-bread separator=">">
      <sb-bread-item>111</sb-bread-item>
      <sb-bread-item href="#">222</sb-bread-item>
      <sb-bread-item>333</sb-bread-item>
   </sb-bread>

作者根据查阅资料使用的方案是这样的,在 sb-bread 里我们使用 provide 将信息传递下去,如果 sb-bread-item 是 sb-bread 的子项目,就可以使用 inject 拿到我们提供的内容,这样就可以使用实现我们自定义分隔符的渲染了,一个简单是例子是:(完整的代码欢迎去我的 git 查看 https://github.com/aiai0603/seven-bit-ui )

<template>
  <div ref="breadcrumb" :class="styleClass" v-bind="attrs">
    <slot />
  </div>
</template>
<script lang="ts" setup>
  import './style/index.less';
  import '../sbIcon';
  import { computed, provide, ref, useAttrs } from 'vue';
  import { breadProps } from './types';
  const props = defineProps(breadProps);
  const attrs = useAttrs();
  const breadcrumb = ref<HTMLDivElement>();

  provide('breadcrum', props);

  const styleClass = computed(() => {
    return {
      'sb-bread': true
    };
  });
</script>
<template>
  <a v-if="props.href" class="sb-bread-item sb-bread-is-link" :href="props.href">
    <slot />
  </a>
  <div v-else class="sb-bread-item">
    <slot />
  </div>
  <sb-icon v-if="separatorIcon" class="sb-bread-item-separator" :name="separatorIcon"></sb-icon>
  <span v-else class="sb-bread-item-separator">
    {{ separator }}
  </span>
</template>
<script lang="ts" setup>
  import './style/index.less';
  import { sbIcon } from '../index';
  import { inject, toRefs } from 'vue';
  import { breadItemProps } from './types';
  const props = defineProps(breadItemProps);

  const breadContext = inject('breadcrum');

  const { separator, separatorIcon } = toRefs(breadContext as any);
</script>

less 来编写动态的样式

我们在编写 grid 组件的时候,需要按照传统将我们的一个块 24 等分,我们根据这 24 等分来写我们的样式,如果我们根据传入是数据来使用 style 计算我们的样式,那就好麻烦了,一个组件要绑定多个 style 而且写在组件上的 style 层级很高,用户很难去修改,所以我们使用 less 循环来编写一组 1-24 等分的样式:

.for(@i) when(@i <= 24) {
  .for(@i + 1);
  @size: (100% * @i / 24);
  .sb-col-span-@{i} {
    display: block;
    width: @size;
    flex: 0 0 @size;
  }
}
.for(1);

这里定义了一个函数叫 for ,传入一个参数 i 循环到 i 等于24的时候;对于每个 i 我们计算出它对应的比例是多少,注意此处的计算一定要带上 () 包裹,否则无法识别,之后我们再将我们计算出来的结果绑定到我们需要的 class 属性上,上述的例子相当于是生成了如下的24个类,使用循环可以快速帮助我们生成我们需要的内容:

.sb-col-span-1 {
    display: block;
    width: 100% * 1 / 24;
    flex: 0 0 100% * 1 / 24;
 }
.sb-col-span-2 {
    display: block;
    width: 100% * 2 / 24;
    flex: 0 0 100% * 2 / 24;
 }
/***省略**/
.sb-col-span-24 {
    display: block;
    width: 100%;
    flex: 0 0 100%;
 }

结尾

以上是作者在开发过程中遇到的问题和处理的方案,作者还在持续更新组件库,后续将会有机会继续更新其他内容,欢迎关注作者,订阅收藏专栏来关注后续

源代码地址: https://github.com/aiai0603/seven-bit-ui

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/197722.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

git-学习git,这一篇就足够了(初学者视角实战教程)

目录git概念命令git配置README.gitignore工作区、暂存区和版本库基础配置创建远程仓库克隆修改查看工作区当前状态添加到暂存区回退版本比较工作区与缓存区的差异添加到本地仓库并加注释push提高git pull文件删除与恢复分支管理列出分支创建分支切换分支分支操作标签管理创建标…

【linux】进程间通信——管道通信

进程间通信一、进程间通信1.1 通信的介绍1.2 通信的目的1.3 通信的分类二、管道2.1 匿名管道2.1.1 pipe2.2.2 读写特征2.2.3 命名管道一、进程间通信 1.1 通信的介绍 通信就是一个进程把数据传递给另一个进程&#xff0c;但是每个进程都具有独立性。通信的本质&#xff1a;OS需…

STL——vector

一、标准库中的vector 1.vector文档介绍 &#xff08;1&#xff09;vector是表示可变大小数组的序列容器。 &#xff08;2&#xff09;像数组一样&#xff0c;vector也采用连续存储空间来存储元素&#xff0c;也就意味着可以采用下标对vector的元素进行访问&#xff0c;和数…

深度:用10000字总结了嵌入式C语言必学知识点

导读&#xff1a;怎么做好嵌入式&#xff1f;相信这个问题无论问谁你都会得到一句学好C语言&#xff01;今天推荐一篇大佬写的嵌入式C语言知识点总结&#xff0c;非常值得一读。 目录 1 关键字 2 数据类型 3 内存管理和存储架构 4 指针和数组 5 结构类型和对齐 6 预处理…

RDC 2022纪念版开发板-D1S在RT-Smart运行

开发环境 软件 ubuntu20.04VMware Workstation 硬件 RDC2022纪念版开发板全志D1s芯片 材料下载 首先打开虚拟机&#xff0c;创建一个目录存放本次测试的代码&#xff0c;然后克隆RT-Smart用户态代码。 git clone https://github.com/RT-Thread/userapps.git在userapps目…

SMB2协议特性之oplock与lease(下

前期回顾上篇文章我们介绍了oplock/lease的相关概念及其基本工作原理&#xff0c;由于间隔时间较长&#xff0c;忘记的读者可以先去回顾一下。本篇文章带大家了解一下&#xff0c;在实际场景中&#xff0c;oplock/lease是如何工作的。实际场景分析在一些警匪影视剧中&#xff0…

PCI驱动程序框架

PCI驱动程序框架 文章目录PCI驱动程序框架参考资料&#xff1a;一、 PCI驱动框架二、 RK3399驱动致谢参考资料&#xff1a; 《PCI Express Technology 3.0》&#xff0c;Mike Jackson, Ravi Budruk; MindShare, Inc.《PCIe扫盲系列博文》&#xff0c;作者Felix&#xff0c;这是…

【NS2】打印c++函数名字/bash将echo赋值给变量

需求&#xff1a;将tcl在c调用的路由算法名字&#xff08;函数名&#xff09;输出&#xff0c;并作为变量赋值给文件名字&#xff0c;但就怎么将函数名字打印出来就思考了很久&#xff0c;并尝试了其他网站“在shell脚本使用tcl变量、如何在bash脚本打印tcl变量、NS2&#xff0…

【实际开发12】- 经验 experience

目录 1. 经验 experience 1. 无多大价值 , 停留数据展示层面 2. 保证数据一致性问题 3. 新增时 , 可先关注核心基础数据 ( 复杂数据以修改形式完善 ) 4. 新增 / 修改 ( 幂等性处理 ) 5. 增 / 删 / 改 添加日志 , 查询无需日志 6. 需要对接多模块的通用字段设计 : String…

什么是CRM系统 企业如何选择合适的CRM系统

在如今市场竞争激烈情况下&#xff0c;企业更加注重客户的数据和管理&#xff0c;因此逐渐形成了“以客户为核心”的理念。而借助CRM系统管理客户数据已然成为一种趋势。 选择一款适合企业的CRM系统可以帮助企业实现更多的价值。但一些企业在初期根本不了解什么是CRM系统&…

Hadoop安装(一) --- JDK安装

目录 1.安装虚拟机 2.关防火墙 3.修改网络配置文件 4.重启网络服务 5.连接shell 6.安装vim工具 7.免密登陆 8. 开启远程免密登录配置 9.远程登录 10.同步时间 10.1.安装ntpdate 10.2.定时更新时间 10.3.启动定时任务 10.4.查看状态 11.修改计算机名 12.配置ho…

数据仓库的架构以及传统数据库与数据仓库的区别

一、数据仓库的分层架构 数据仓库的数据来源于不同的源数据&#xff0c;并提供多样的数据应用&#xff0c;数据自下而上流入数据仓库后向上层开放应用&#xff0c;而数据仓库只是中间集成化数据管理的一个平台。 1&#xff0c;源数据层&#xff08;ODS&#xff09; 操作性数…

袁树雄和杨语莲究竟什么关系 ,《早安隆回》走红后又是《汉川》

自从《早安隆回》火爆全网后&#xff0c;歌迷们就有一种担心&#xff0c;不知道这首好听的歌曲&#xff0c;究竟还能再够火爆多久。歌迷们的担心也不无道理&#xff0c;毕竟花无百日红&#xff0c;人无千般好&#xff0c;《早安隆回》就是再好听&#xff0c;也不可能红一辈子吧…

windows搭建go语言开发环境

1.下载Go语言开发包可以在Go语言官网 ( https://golang.google.cn/dl/ )下载Windows 系统下的Go语言开发包&#xff0c;如下图所示。这里我下载的是 64位的开发包&#xff0c;如果读者的电脑是 32 位系统的话&#xff0c;则需要下载 32 位的开发包&#xff0c;在上图所示页面中…

Fiddler手机抓包

手机抓包软件Fiddler 下载地址以及下载流程 Fiddler 下载地址&#xff1a;https://www.telerik.com/download/fiddler 下载后直接一键安装即可 重要的注意项卸载最前面 pc和手机需要在同一个局域网&#xff0c;也就是同一个wifi 配置 Fiddler界面的简单介绍 pc端Fildde…

Windows Server 2022 Install Veeam ONE 12

借助有关 Veeam Backup & Replication™ 和 Veeam Agents 及 VMware vSphere、Microsoft Hyper-V 和 Nutanix AHV 的洞察&#xff0c;Veeam ONE™ 可通过交互式工具和智能学习提供深度智能监控、报告和自动化功能&#xff0c;帮助客户发现问题并前瞻性地解决问题。 Veeam O…

CUDA编程之CUDA流

文章目录前言CUDA流在默认流中重叠主机与设备用非默认CUDA流重叠多个核函数的执行重叠多个核函数的例子用非默认CUDA流重叠核函数的执行与数据传递不可分页主机内存与异步的数据传输函数总结参考前言 CUDA程序的并行层次主要有两个&#xff0c;一个是核函数内部的并行&#xff…

C++面向对象——C++ 重载运算符和重载函数

C面向对象——C 重载运算符和重载函数C 重载运算符和重载函数C 中的函数重载C 中的运算符重载运算符重载实例C 一元运算符重载C 二元运算符重载C 关系运算符重载C 和 -- 运算符重载C 赋值运算符重载C 函数调用运算符 () 重载C 下标运算符 [] 重载C 类成员访问运算符 -> 重载…

三、进程通信

一、基础知识数据传输一个进程将他的数据发送给另一个进程资源共享多个进程间共享同样的资源通知时间一个进程向另一个进程发送消息&#xff0c;通知他们发生了某种事情通信方式&#xff1a;管道和有名管道信号signal消息队列共享内存信号量套接字二、管道&#xff1a;无名管道…

c++11 标准模板(STL)(std::multiset)(六)

定义于头文件 <set> template< class Key, class Compare std::less<Key>, class Allocator std::allocator<Key> > class multiset;(1)namespace pmr { template <class Key, class Compare std::less<Key>> usi…