Vue 插件是什么?和组件有什么区别?全局方法应该挂 globalProperties 还是 provide?
先理解原理和示例,再练习完整口述与追问。
回答要点
插件是带 install(app, options) 的对象或函数,用 app.use 安装,可注册全局组件、指令、provide 和全局属性;组件是可复用的 UI 单元。Vue3 的 app.config.globalProperties 只能在模板和 Options API 的 this 中访问,组合式 API 中更推荐 provide/inject 或直接导入模块,类型也更清楚。
原理拆解
app.use(plugin, options) 调用 install,并记录已安装的插件,避免同一插件重复安装。Vue Router、Pinia、Element Plus 都是插件:Router 注册 RouterLink、RouterView 组件并 provide 路由实例,Pinia provide 当前 store 容器。Vue2 的插件通过 Vue.prototype.$xxx 挂全局方法,所有实例共享;Vue3 改为每个应用独立的 app 实例,多个应用之间互不污染。
globalProperties 上的属性通过 this 访问,<script setup> 中没有 this,需要用 getCurrentInstance(),这属于内部用法,不推荐。provide/inject 是显式依赖,也可以导出组合式函数 useToast() 包装 inject,测试时容易替换。
示例与推演
const ToastKey = Symbol('toast')
export const ToastPlugin = {
install(app, options = {}) {
const toast = message => showToast(message, options.duration ?? 2000)
app.provide(ToastKey, toast)
app.config.globalProperties.$toast = toast
}
}
export function useToast() {
const toast = inject(ToastKey)
if (!toast) throw new Error('ToastPlugin 未安装')
return toast
}
TypeScript 中给 $toast 加类型,需要扩展 ComponentCustomProperties 接口。
易错点
插件中不要创建全局单例状态,SSR 下所有请求会共享它,应在 install 内为每个 app 创建;全局注册大量组件会削弱按需加载和 Tree Shaking 效果。
参考回答可直接练习口述
插件是有 install 方法的对象,用 app.use 安装,内部可以注册全局组件、指令、provide 或全局属性,Router、Pinia 都是插件;组件则是具体的 UI 单元。Vue3 的 globalProperties 只能在模板和 this 上用,setup 里拿不到,所以我会让插件 provide 一个服务,再导出 useXxx 组合式函数去 inject,依赖显式、类型清楚、测试也好替换。另外要注意 SSR 下不要在插件中共享全局状态。