背景问题:
需要全局注册常用组件,避免重复导入。
方案思考:
在应用初始化时批量注册全局组件。
具体实现:
创建自动注册全局组件的工具函数:
// utils/global-components.jsimport{App}from'vue'// 手动导入需要全局注册的组件importGlobalButtonfrom'@/components/GlobalButton.vue'importGlobalInputfrom'@/components/GlobalInput.vue'importBaseDialogfrom'@/components/BaseDialog.vue'importBaseTablefrom'@/components/BaseTable.vue'constglobalComponents={GlobalButton,GlobalInput,BaseDialog,BaseTable}// 注册所有全局组件exportfunctionregisterGlobalComponents(app){Object.entries(globalComponents).forEach(([name,component])=>{app.component(name,component)})}更高级的自动导入方式:
// utils/auto-import.jsimport{App}from'vue'// 自动导入全局组件exportfunctionsetupGlobalComponents(app){// 自动导入 components 目录下的全局组件constcomponents=import.meta.glob('../components/Global*.vue')Object.entries(components).forEach(([path,component])=>{// 从路径中提取组件名constcomponentName=path.split('/').pop().replace('.vue','')// 动态注册组件component().then(module=>{app.component(componentName,module.default)})})}创建一个全局按钮组件示例:
<!-- components/GlobalButton.vue --> <template> <button :class="[buttonClass, sizeClass, typeClass]" :disabled="disabled || loading" @click="handleClick" > <el-icon v-if="icon || loading" class="button-icon"> <component :is="loading ? 'Loading' : icon" /> </el-icon> <span v-if="$slots.default" class="button-text"> <slot /> </span> </button> </template> <script setup> import { computed } from 'vue' const props = defineProps({ type: { type: String, default: 'default', validator: (value) => [ 'default', 'primary', 'success', 'warning', 'danger', 'info' ].includes(value) }, size: { type: String, default: 'medium', validator: (value) => [ 'medium', 'small', 'mini' ].includes(value) }, icon: String, disabled: Boolean, loading: Boolean }) const emits = defineEmits(['click']) const buttonClass = computed(() => { return [ 'global-button', props.disabled ? 'is-disabled' : '', props.loading ? 'is-loading' : '' ].filter(Boolean).join(' ') }) const sizeClass = computed(() => `button-${props.size}`) const typeClass = computed(() => `button-${props.type}`) const handleClick = (event) => { if (!props.disabled && !props.loading) { emits('click', event) } } </script> <style scoped> .global-button { display: inline-flex; justify-content: center; align-items: center; line-height: 1; height: 32px; padding: 6px 12px; border: 1px solid #dcdfe6; border-radius: 4px; cursor: pointer; outline: none; transition: all 0.2s; } .global-button:not(.is-disabled):not(.is-loading):hover { border-color: #c6e2ff; background-color: #ecf5ff; color: #409eff; } .global-button.button-primary { background-color: #409eff; border-color: #409eff; color: #fff; } .global-button.button-success { background-color: #67c23a; border-color: #67c23a; color: #fff; } .global-button.button-danger { background-color: #f56c6c; border-color: #f56c6c; color: #fff; } .global-button.is-disabled { opacity: 0.6; cursor: not-allowed; } .button-icon { margin-right: 4px; } </style>在 main.js 中使用:
// main.jsimport{createApp}from'vue'importAppfrom'./App.vue'import{registerGlobalComponents}from'@/utils/global-components'constapp=createApp(App)// 注册全局组件registerGlobalComponents(app)app.mount('#app')在任意组件中使用全局组件:
<template> <div class="example-page"> <GlobalButton type="primary" @click="handleClick">点击我</GlobalButton> <GlobalButton type="success" icon="Check" :loading="isLoading"> 加载中 </GlobalButton> <GlobalInput v-model="inputValue" placeholder="输入内容" /> </div> </template> <script setup> import { ref } from 'vue' const inputValue = ref('') const isLoading = ref(false) const handleClick = () => { console.log('按钮被点击') } </script>