在 Vue 开发中,我们经常会遇到一些需要在多个组件中复用的功能 —— 比如格式化时间的工具方法、限制输入的自定义指令、通用的弹窗组件等。如果每个组件都重复定义这些内容,不仅代码冗余,还会增加维护成本。本文将系统讲解 Vue 2 和 Vue 3 中定义全局方法、指令、组件的标准方式,帮你打造更高效的代码复用体系。
一、全局方法:让通用逻辑随处可用
全局方法适用于无状态的工具类函数(如数据格式化、校验逻辑),注册后可在任意组件的模板或脚本中直接调用。
Vue 2 实现方式
Vue 2 中可直接通过
Vue.prototype挂载全局方法,这是最经典的写法:javascript
运行
// main.js
import Vue from 'vue'
import App from './App.vue'
// 1. 定义全局方法:格式化时间
Vue.prototype.$formatTime = function (timestamp) {
if (!timestamp) return ''
const date = new Date(timestamp)
return date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit'
})
}
// 2. 定义全局工具方法:校验手机号
Vue.prototype.$checkPhone = function (phone) {
const reg = /^1[3-9]\d{9}$/
return reg.test(phone)
}
new Vue({
el: '#app',
render: h => h(App)
})
使用方式(任意组件中):
vue
<template>
<div>
<p>格式化时间:{{ $formatTime(Date.now()) }}</p>
<button @click="validatePhone">校验手机号</button>
</div>
</template>
<script>
export default {
methods: {
validatePhone() {
const isValid = this.$checkPhone('13800138000')
console.log('手机号是否有效:', isValid)
}
}
}
</script>
Vue 3 实现方式
Vue 3 移除了
Vue.prototype,推荐使用app.config.globalProperties挂载全局方法(Vue 3 采用组合式 API,无this的场景需特殊处理):javascript
运行
// main.js
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
// 1. 挂载全局方法
app.config.globalProperties.$formatTime = (timestamp) => {
if (!timestamp) return ''
const date = new Date(timestamp)
return date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit'
})
}
app.mount('#app')
组合式 API 中使用:
vue
<script setup>
import { getCurrentInstance } from 'vue'
// 获取全局实例
const appContext = getCurrentInstance()
const $formatTime = appContext.appContext.config.globalProperties.$formatTime
// 调用全局方法
console.log($formatTime(Date.now()))
</script>
二、全局指令:扩展 DOM 元素的能力
自定义指令用于操作 DOM 元素(如自动聚焦、权限控制、输入限制),全局注册后可在任意组件模板中使用。
基础语法(Vue 2/Vue 3 通用逻辑)
全局指令的核心是钩子函数,常用的有:
bind(Vue 2)/mounted(Vue 3):指令绑定到元素时触发update:元素更新时触发unbind(Vue 2)/unmounted(Vue 3):指令解绑时触发
Vue 2 注册全局指令
javascript
运行
// main.js
import Vue from 'vue'
// 1. 注册全局指令:v-focus(自动聚焦输入框)
Vue.directive('focus', {
// 绑定元素插入DOM时执行
inserted(el) {
el.focus()
}
})
// 2. 注册全局指令:v-permission(权限控制)
Vue.directive('permission', {
bind(el, binding) {
// 获取指令值(需要的权限)
const requiredPerm = binding.value
// 模拟用户权限
const userPerms = ['add', 'edit']
// 无权限则隐藏元素
if (!userPerms.includes(requiredPerm)) {
el.style.display = 'none'
}
}
})
Vue 3 注册全局指令
javascript
运行
// main.js
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
// 1. 全局指令:v-focus
app.directive('focus', {
// Vue 3使用mounted替代inserted
mounted(el) {
el.focus()
}
})
// 2. 全局指令:v-limit(输入长度限制)
app.directive('limit', {
mounted(el, binding) {
// 指令参数:限制的长度
const maxLen = binding.value || 10
// 监听输入事件
el.addEventListener('input', (e) => {
e.target.value = e.target.value.slice(0, maxLen)
})
}
})
app.mount('#app')
使用全局指令:
vue
<template>
<!-- 自动聚焦 -->
<input v-focus type="text" />
<!-- 权限控制 -->
<button v-permission="'delete'">删除按钮</button>
<!-- 输入长度限制 -->
<input v-limit="10" type="text" placeholder="最多输入10个字" />
</template>
三、全局组件:复用通用 UI 模块
全局组件适用于项目中高频使用的 UI 组件(如按钮、弹窗、加载动画),无需在每个组件中 import 即可使用。
单个组件全局注册
Vue 2
javascript
运行
// main.js
import Vue from 'vue'
import App from './App.vue'
// 导入组件
import MyButton from './components/MyButton.vue'
import Loading from './components/Loading.vue'
// 注册全局组件
Vue.component('MyButton', MyButton)
Vue.component('Loading', Loading)
new Vue({
el: '#app',
render: h => h(App)
})
Vue 3
javascript
运行
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import MyButton from './components/MyButton.vue'
const app = createApp(App)
// 注册全局组件
app.component('MyButton', MyButton)
app.mount('#app')
批量注册全局组件(推荐)
当全局组件较多时,手动逐个注册效率低,可通过
require.context批量导入(Vue 2/Vue 3 通用):javascript
运行
// main.js (Vue 2)
import Vue from 'vue'
// 自动注册components下的所有.vue组件
const requireComponent = require.context(
'./components', // 组件目录
false, // 是否遍历子目录
/\.vue$/ // 匹配.vue文件
)
requireComponent.keys().forEach(fileName => {
// 获取组件配置
const componentConfig = requireComponent(fileName)
// 获取组件名(如 ./MyButton.vue → MyButton)
const componentName = fileName.replace(/^\.\/(.*)\.\w+$/, '$1')
// 全局注册组件
Vue.component(
componentName,
componentConfig.default || componentConfig
)
})
// main.js (Vue 3)
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
const requireComponent = require.context('./components', false, /\.vue$/)
requireComponent.keys().forEach(fileName => {
const componentConfig = requireComponent(fileName)
const componentName = fileName.replace(/^\.\/(.*)\.\w+$/, '$1')
app.component(componentName, componentConfig.default || componentConfig)
})
app.mount('#app')
使用全局组件:
vue
<template>
<div>
<!-- 无需import,直接使用 -->
<MyButton type="primary">全局按钮</MyButton>
<Loading v-if="loading" />
</div>
</template>
四、注意事项与最佳实践
- 避免过度全局化:全局注册会增加应用初始化体积,仅对真正通用的内容使用全局注册,业务相关的组件 / 方法建议局部导入。
- 命名规范:全局方法建议加
$前缀(如$formatTime),避免与组件内部方法冲突;全局组件使用大驼峰或连字符命名(如MyButton/my-button)。 - Vue 3 组合式 API 替代方案:对于全局方法,Vue 3 更推荐使用
provide/inject或创建工具类文件(如utils/index.js)导入使用,减少对globalProperties的依赖。 - 类型提示:Vue 3 + TypeScript 项目中,需扩展
ComponentCustomProperties接口,为全局方法添加类型提示:
typescript
运行
// types/global.d.ts
import type { ComponentCustomProperties } from 'vue'
declare module '@vue/runtime-core' {
interface ComponentCustomProperties {
$formatTime: (timestamp: number) => string
}
}
总结
- 全局方法:Vue 2 用
Vue.prototype,Vue 3 用app.config.globalProperties,适用于通用工具函数; - 全局指令:Vue 2 用
Vue.directive,Vue 3 用app.directive,专注于 DOM 操作类场景; - 全局组件:单个注册用
component方法,批量注册推荐require.context,适用于高频通用 UI 组件。
合理使用全局注册能大幅提升开发效率,但需把握 “全局” 的边界 —— 只注册真正跨组件复用的内容,才能既保持代码简洁,又避免全局污染。