指令 (Directives)
指令(Directives)是Vue模板中提供指令性操作的特殊标记,如v-model
、v-show
、v-if
等。自定义指令侧重于对普通DOM元素进行底层操作。
只有当所需功能只能通过直接的 DOM 操作来实现时,才应该使用自定义指令。其他情况下应该尽可能地使用 v-bind 这样的内置指令来声明式地使用模板,这样更高效,也对服务端渲染更友好。
文档
Vue 2 vs Vue 3
- Vue2:
- 全局注册:
Vue.directive()
- 局部注册:
directives: { }
。 - 钩子函数:
bind
、inserted
、update
、componentUpdated
、unbind
- 参数:
el
、binding
、vnode
和oldVnode
- 全局注册:
- Vue3: 在Vue 3中,自定义指令的钩子函数发生了变化,使其更好地与组件的生命周期保持一致.
- 全局注册:
app.directive()
- 局部注册:
directives: { }
或<script setup>
中以v开头的驼峰式命名的变量。 - 钩子函数:
created
、beforeMount
、mounted
、beforeUpdate
、updated
、beforeUnmount
、unmounted
- 参数:
el
、binding
、vnode
和prevVnode
- 全局注册:
场景示例:
点击外部关闭弹窗: 可以通过自定义指令来监听点击事件,如果点击发生在弹窗外部,则关闭弹窗。
js
// Vue2
Vue.directive('click-outside', {
bind(el, binding, vnode) {
el.clickOutsideEvent = function(event) {
if (!(el === event.target || el.contains(event.target))) {
binding.value(event);
}
};
document.body.addEventListener('click', el.clickOutsideEvent)
},
unbind(el) {
document.body.removeEventListener('click', el.clickOutsideEvent)
},
});
// Vue3
const app = createApp({})
app.directive('click-outside', {
// 在元素被插入到 DOM 前调用
beforeMount(el,binding,vnode){
el.clickOutsideEvent = function(event) {
if (!(el === event.target || el.contains(event.target))) {
binding.value(event);
}
};
document.body.addEventListener('click', el.clickOutsideEvent)
},
// 绑定元素的父组件卸载后调用
unmounted(el){
document.body.removeEventListener('click', el.clickOutsideEvent)
}
})
插件 (Plugins)
插件是用于添加全局级别功能的Vue.js库。它们可以提供全局方法和属性、自定义指令、过滤器、过渡等。
文档
Vue 2 vs Vue 3
- Vue2: 插件通过
Vue.use()
方法按照,并且可以接受选项。 - Vue3: 插件安装方式同Vue2,但是Vue3的插件需要使用新的应用实例方法
app.use()
。因为Vue 3是基于应用实例创建的。
场景示例
- Vue Router: 用于页面路由管理的插件。
- Vuex: 用于状态管理的插件。
js
// Vue 2
Vue.use(VueRouter);
Vue.use(Vuex);
// Vue 3
const app = Vue.createApp({});
app.use(VueRouter);
app.use(Vuex);
理解Vue.use()
Vue.use()
方法用于安装Vue插件。如果插件是一个对象,必须提供install方法。
如果插件是一个函数,它会被作为install方法。install方法调用时,会将Vue作为参数传入。
指令是否需要都封装成插件呢?
直接使用指令
指令可以直接在单个组件中定义和使用。这对于只有少数几个地方需要指令的情况来说非常方便。
将指令封装成插件
- 复用性强:封装成插件后,指令可以在多个项目或者应用的多个部分重复使用,不仅减少了重复代码,也提高开发效率。
- 易于管理:通过将插件发布到NPM,指令的更新和修复变得简单。通过版本控制和依赖管理,在多个项目中复用插件变得更加高效。
- 扩展性:插件不仅可以包含指令,还可以包含组件、混入、过滤器等。
总结
如果你的指令只在少数几个地方使用,且与特定组件紧密相关,直接在组件内使用指令可能更合适。
如果你的指令具有广泛的适用性,或者你希望创建一个包含多个功能(如指令、组件等)的库,那么将指令封装成插件会是更好的选择。
封装成插件的方式提供了更好的复用性和扩展性,但也需要更多的配置和管理。直接使用指令则更加简单直接,但可能会导致代码重复和难以管理。选择哪种方式取决于你的具体需求和项目规模。
将指令封装成插件实现
将指令封装成插件的思路是,创建一个对象或函数,提供一个install方法。在install方法内部,你可以使用Vue.directive()
或app.directive
来全局注册你的指令。
Vue2 vs Vue3
指令封装成插件的基本思路是相似的,但是由于Vue3引入了一些新的API和概念,因此实现上会有所不同
- 注册方式:Vue 2使用
Vue.directive
进行全局注册,而Vue 3使用app.directive
进行应用级别的注册。 - 插件安装:Vue 2通过
Vue.use()
安装插件,Vue 3则需要在创建应用实例后,通过实例的use()方法安装。 - 指令钩子函数:Vue 3在指令的钩子函数中引入了
beforeMount
和mounted
等新的钩子,替代了Vue 2中的bind
和inserted
等钩子,以更好地与组件的生命周期保持一致。 - 应用实例:在Vue 3中,你可以创建多个独立的应用实例,每个实例可以独立配置插件和指令。这意味着在同一个页面中,你可以有多个Vue应用运行,而每个应用可以有自己的插件配置,不会互相影响。这在Vue2中是不可能的。
js
const MyClickOutsidePlugin = {}
// Vue 2 插件示例
MyClickOutsidePlugin.install = (Vue) => {
Vue.directive('click-outside', {
bind(el, binding, vnode) {
// 指令的钩子函数
}
// 其他钩子函数...
});
}
// 使用插件
Vue.use(MyClickOutsidePlugin);
// Vue 3 插件示例
MyClickOutsidePlugin.install = (app) => {
app.directive('click-outside', {
beforeMount(el, binding, vnode) {
// 指令的钩子函数
}
// 其他钩子函数...
});
}
// 创建Vue应用并使用插件
const app = Vue.createApp({});
app.use(MyClickOutsidePlugin);