​​Vue3 自定义公共组件的实现实例

 更新时间:2025年11月24日 08:34:52   作者:Rysxt  
本文主要介绍了​​Vue3 自定义公共组件的实现实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

​​​一 环境准备与项目初始化​​

  • 使用 ​​Vite​​ 快速搭建 Vue3 项目,选择 ​​Vue​​ 模板:
    • 创建项目:npm create vite@latest my-component-lib --template vue
    • 进入目录:cd my-component-lib
    • 安装依赖:npm install

推荐采用 monorepo 风格组织组件库源码,便于多组件维护与发布:

新建目录:packages/(组件源码)、src/(示例与文档)

示例结构:

my-component-lib/
├── packages/
│   ├── button/
│   │   └── index.vue
│   └── index.js
├── src/
├── package.json
└── vite.config.js

packages/index.js 统一导出组件,便于全局注册与按需引入。

​​二 编写一个可复用的按钮组件​​

  • 组件功能:支持 ​​size​​、​​type​​、​​disabled​​,通过 ​​插槽​​ 自定义内容,点击时 ​​emit('click')​​。
  • 组件代码:packages/button/index.vue
    <template>
      <button
        :class="['zd-btn', sizeClass, typeClass, { 'is-disabled': disabled }]"
        :disabled="disabled"
        @click="handleClick"
      >
        <slot />
      </button>
    </template>
    
    <script setup>
    import { computed } from 'vue'
    
    const props = defineProps({
      size: {
        type: String,
        default: 'middle',
        validator: v => ['large', 'middle', 'small', 'mini'].includes(v)
      },
      type: {
        type: String,
        default: 'default',
        validator: v => ['default', 'primary', 'success', 'warning', 'danger', 'info', 'text'].includes(v)
      },
      disabled: {
        type: Boolean,
        default: false
      }
    })
    
    const emit = defineEmits(['click'])
    
    const sizeClass = computed(() => `zd-btn--${props.size}`)
    const typeClass = computed(() => `zd-btn--${props.type}`)
    
    const handleClick = (e) => {
      if (!props.disabled) emit('click', e)
    }
    </script>
    
    <style scoped>
    .zd-btn {
      border: none;
      border-radius: 4px;
      padding: 0 16px;
      font-family: inherit;
      cursor: pointer;
      transition: all 0.2s ease;
      outline: none;
    }
    .zd-btn:disabled {
      cursor: not-allowed;
      opacity: 0.6;
    }
    .zd-btn--large  { height: 48px; font-size: 16px; }
    .zd-btn--middle { height: 40px; font-size: 14px; }
    .zd-btn--small  { height: 32px; font-size: 13px; }
    .zd-btn--mini  { height: 24px; font-size: 12px; }
    
    .zd-btn--default { background: #fff; border: 1px solid #d9d9d9; color: #333; }
    .zd-btn--default:hover:not(.is-disabled) { border-color: #c0c0c0; background: #f5f5f5; }
    .zd-btn--primary { background: #409eff; color: #fff; border: 1px solid #409eff; }
    .zd-btn--primary:hover:not(.is-disabled) { background: #66b1ff; border-color: #66b1ff; }
    .zd-btn--success { background: #67c23a; color: #fff; border: 1px solid #67c23a; }
    .zd-btn--warning { background: #e6a23c; color: #fff; border: 1px solid #e6a23c; }
    .zd-btn--danger  { background: #f56c6c; color: #fff; border: 1px solid #f56c6c; }
    .zd-btn--info   { background: #909399; color: #fff; border: 1px solid #909399; }
    .zd-btn--text   { background: transparent; border: none; color: #409eff; }
    .zd-btn--text:hover:not(.is-disabled) { background: rgba(64,158,255,0.1); }
    </style>
  • 入口导出:packages/index.js
    import { App } from 'vue'
    import ZdButton from './button/index.vue'
    
    const components = [ZdButton]
    
    const install = (app) => {
      components.forEach(c => app.component(c.name || c.displayName, c))
    }
    
    export { ZdButton, install }
    export default { install }
  • 本地测试:在 src/main.js 全局注册并使用
    import { createApp } from 'vue'
    import App from './App.vue'
    import ZdComponentLib from '../packages/index.js'
    
    createApp(App).use(ZdComponentLib).mount('#app')
    <template>
      <zd-button type="primary" size="large" @click="onClick">Primary</zd-button>
    </template>
    
    <script setup>
    const onClick = () => alert('clicked')
    </script>
  • 要点
    • 使用 ​​defineProps / defineEmits​​ 声明式 API,类型清晰。
    • 通过 ​​validator​​ 约束枚举值,减少错误用法。
    • 使用 ​​scoped​​ 样式避免泄漏,必要时用 ​​CSS 变量​​ 支持主题定制。

​​三 组件库打包与发布到 npm​​

  • 库模式构建配置:vite.config.js
    import { defineConfig } from 'vite'
    import vue from '@vitejs/plugin-vue'
    import { resolve } from 'path'
    
    export default defineConfig({
      plugins: [vue()],
      build: {
        lib: {
          entry: resolve(__dirname, 'packages/index.js'),
          name: 'MyUILib',
          fileName: (fmt) => `my-ui.${fmt}.js`
        },
        rollupOptions: {
          external: ['vue'],
          output: {
            globals: { vue: 'Vue' }
          }
        }
      }
    })
  • 入口包配置:package.json(建议独立包名与版本管理)
    {
      "name": "@your-org/vue3-ui",
      "version": "1.0.0",
      "type": "module",
      "main": "dist/my-ui.umd.js",
      "module": "dist/my-ui.es.js",
      "files": ["dist", "packages"],
      "types": "dist/types/index.d.ts",
      "scripts": {
        "dev": "vite",
        "build": "vite build",
        "preview": "vite preview"
      },
      "peerDependencies": { "vue": "^3.0.0" },
      "keywords": ["vue3", "components", "ui"],
      "author": "Your Name",
      "license": "MIT"
    }
  • 类型声明(可选,提升 TS 体验):dist/types/index.d.ts
    import type { DefineComponent } from 'vue'
    export const ZdButton: DefineComponent<{
      size?: 'large' | 'middle' | 'small' | 'mini'
      type?: 'default' | 'primary' | 'success' | 'warning' | 'danger' | 'info' | 'text'
      disabled?: boolean
    }, {}, {}, {}, {
      click: [MouseEvent]
    }>
    export const install: any
    export default { install }
  • 发布流程
    • 登录 npm:npm login(确保源为官方仓库)
    • 构建:npm run build
    • 发布:npm publish --access public
  • 其他项目使用
    • 全局注册:app.use(MyUILib)
    • 按需引入:import { ZdButton } from '@your-org/vue3-ui'(并单独引入样式文件,如有)。

​​四 使用方式与最佳实践​​

  • 两种引入方式
    • 全局注册:适合通用 UI 组件,减少重复 import。
      import { createApp } from 'vue'
      import App from './App.vue'
      import MyUILib from '@your-org/vue3-ui'
      app.use(MyUILib).mount('#app')
    • 按需引入:减小打包体积,配合构建工具自动引入(如 unplugin-vue-components)。
      <template>
        <zd-button type="primary">Hello</zd-button>
      </template>
      
      <script setup>
      import { ZdButton } from '@your-org/vue3-ui'
      </script>
  • 组件设计要点
    • Props:明确 ​​类型​​、​​默认值​​、​​校验器​​,保持 API 稳定。
    • 事件:语义化命名(如 ​​click​​、​​change​​),必要时透传事件对象与业务数据。
    • 插槽:优先使用默认插槽与具名插槽提升可定制性。
    • 样式:优先 ​​scoped​​;跨组件主题用 ​​CSS 变量​​;对外提供主题变量文件。
    • 可访问性:支持键盘操作、焦点管理、ARIA 属性。
    • 表单组件:优先支持 ​​v-model​​,遵循原生表单元素交互约定。
  • 简单测试示例(Jest + Vue Test Utils)
    import { mount } from '@vue/test-utils'
    import { ZdButton } from '@your-org/vue3-ui'
    
    test('emits click when not disabled', async () => {
      const wrapper = mount(ZdButton)
      await wrapper.trigger('click')
      expect(wrapper.emitted('click')).toHaveLength(1)
    })
    
    test('does not emit click when disabled', async () => {
      const wrapper = mount(ZdButton, { props: { disabled: true } })
      await wrapper.trigger('click')
      expect(wrapper.emitted('click')).toBeUndefined()
    })
  • 常见问题与排查
    • 事件未触发:检查是否被 ​​disabled​​ 拦截或事件绑定写法是否正确。
    • 样式冲突:确认使用 ​​scoped​​ 或命名规范(BEM)。
    • 全局污染:避免在组件内使用过多样式全局选择器。
    • 按需引入样式缺失:确认是否单独引入组件样式文件或配置了样式自动引入插件。

到此这篇关于​​Vue3 自定义公共组件的实现实例的文章就介绍到这了,更多相关​​Vue3 自定义公共组件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Vue+elementUI下拉框自定义颜色选择器方式

    Vue+elementUI下拉框自定义颜色选择器方式

    这篇文章主要介绍了Vue+elementUI下拉框自定义颜色选择器方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • elementUI table表格动态合并的示例代码

    elementUI table表格动态合并的示例代码

    这篇文章主要介绍了elementUI table表格动态合并的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-05-05
  • vue怎样获取当前时间,并且传递给后端(不用注解)

    vue怎样获取当前时间,并且传递给后端(不用注解)

    这篇文章主要介绍了vue怎样获得当前时间,并且传递给后端(不用注解)问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12
  • 浅谈Vue初学之props的驼峰命名

    浅谈Vue初学之props的驼峰命名

    这篇文章主要介绍了浅谈Vue初学之props的驼峰命名,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07
  • 使用Vue Router进行路由组件传参的实现方式

    使用Vue Router进行路由组件传参的实现方式

    Vue Router 为 Vue.js 应用提供了完整的路由解决方案,其中包括了组件间的数据传递功能,通过路由组件传参,我们可以轻松地在导航到新页面时传递必要的数据,本文将深入探讨如何使用 Vue Router 进行路由组件间的传参,并通过多个示例来展示其实现方式
    2024-09-09
  • element-ui 限制日期选择的方法(datepicker)

    element-ui 限制日期选择的方法(datepicker)

    本篇文章主要介绍了element-ui 限制日期选择的方法(datepicker),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-05-05
  • vue3中watch和watchEffect的区别

    vue3中watch和watchEffect的区别

    本文主要介绍了vue3中watch和watchEffect的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • vue父子组件slot插槽的使用

    vue父子组件slot插槽的使用

    这篇文章主要介绍了vue父子组件slot插槽的使用,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-08-08
  • Vue实现背景更换颜色操作

    Vue实现背景更换颜色操作

    这篇文章主要介绍了Vue实现背景更换颜色操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-07-07
  • vue iview封装模态框的方法

    vue iview封装模态框的方法

    这篇文章主要为大家详细介绍了vue iview封装模态框的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-07-07

最新评论