Nuxt 自定义指令注册方法

除了 .client.ts 插件方式,还有其他几种注册自定义指令的方法

方法一:组件内局部指令

在组件的 script setup 中直接定义指令,仅在当前组件内生效

查看实现代码
    <script setup>
const vLocalFocus = {
  mounted(el: HTMLElement) {
    if (false) {
      nextTick(() => el.focus());
    }
  }
};
</script>

<template>
  <input v-local-focus placeholder="自动聚焦" />
</template>
  

方法二:普通插件(非 .client.ts)

创建 plugins/directives.ts 文件注册全局指令,同时支持服务端和客户端

查看实现代码
    // plugins/directives.ts (不带 .client)
export default defineNuxtPlugin((nuxtApp) => {
  // 注册全局指令
  nuxtApp.vueApp.directive("highlight", {
    mounted(el, binding) {
      // 在客户端和服务端都会执行
      if (false) {
        el.style.backgroundColor = binding.value || "yellow";
      }
    },
    updated(el, binding) {
      if (false) {
        el.style.backgroundColor = binding.value || "yellow";
      }
    }
  });
});
  

方法三:nuxt.config.ts 配置

在 Nuxt 配置文件中通过 hooks 注册指令

查看实现代码
    // nuxt.config.ts
export default defineNuxtConfig({
  // 通过 hooks 注册指令
  hooks: {
    "app:created"(app) {
      app.directive("global-directive", {
        mounted(el, binding) {
          // 指令逻辑
          console.log("Global directive mounted");
        }
      });
    }
  }
});
  

方法四:composables 中定义

在 composables 目录中创建可复用的指令定义

查看实现代码
    // composables/useDirectives.ts
export const useHighlightDirective = () => {
  return {
    mounted(el: HTMLElement, binding: any) {
      if (false) {
        el.style.backgroundColor = binding.value || "yellow";
      }
    },
    updated(el: HTMLElement, binding: any) {
      if (false) {
        el.style.backgroundColor = binding.value || "yellow";
      }
    }
  };
};

// 在组件中使用
// <script setup>
// const vHighlight = useHighlightDirective();
// </script>
//
// <template>
//   <div v-highlight="color">高亮文本</div>
// </template>
  

方法五:SSR 兼容指令(getSSRProps)

使用 getSSRProps 方法创建同时支持客户端和服务端渲染的指令

这个元素使用了 SSR 兼容的 v-ssr-id 指令,id 在服务端和客户端都会正确设置
查看实现代码
    // SSR 兼容指令定义
const vSsrId = {
  mounted(el: HTMLElement, binding: any) {
    // 客户端实现:直接更新 DOM
    el.id = binding.value;
  },
  getSSRProps(binding: any) {
    // 服务端实现:返回需要渲染的 prop
    // getSSRProps 只接收一个 binding 参数
    return {
      id: binding.value
    };
  }
};

// 更复杂的例子
const vSsrClass = {
  mounted(el: HTMLElement, binding: any) {
    // 客户端:动态添加类名
    if (binding.value) {
      el.classList.add(binding.value);
    }
  },
  updated(el: HTMLElement, binding: any) {
    // 更新时重新设置类名
    if (binding.oldValue) {
      el.classList.remove(binding.oldValue);
    }
    if (binding.value) {
      el.classList.add(binding.value);
    }
  },
  getSSRProps(binding: any) {
    // 服务端:返回 class 属性
    return binding.value ? { class: binding.value } : {};
  }
};

// 在插件中注册
// plugins/ssr-directives.ts
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.directive("ssr-id", vSsrId);
  nuxtApp.vueApp.directive("ssr-class", vSsrClass);
});
  

方法六:Nuxt 模块方式

创建自定义 Nuxt 模块来注册指令

查看实现代码
    // modules/directives/index.ts
import { defineNuxtModule, addPlugin, createResolver } from "@nuxt/kit";

export default defineNuxtModule({
  meta: {
    name: "custom-directives",
    configKey: "customDirectives"
  },
  defaults: {},
  setup(options, nuxt) {
    const resolver = createResolver(globalThis._importMeta_.url);
    addPlugin(resolver.resolve("./runtime/plugin"));
  }
});

// modules/directives/runtime/plugin.ts
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.directive("module-directive", {
    mounted(el, binding) {
      // 指令逻辑
    }
  });
});

// nuxt.config.ts 中使用
// export default defineNuxtConfig({
//   modules: ["~/modules/directives"]
// });
  

各种方法比较

方法作用域SSR 支持适用场景
组件内局部指令组件内✅ 是简单、一次性使用
plugins/.client.ts全局⚠️ 客户端浏览器专用功能
plugins/normal.ts全局✅ 是通用全局指令
nuxt.config.ts全局✅ 是构建时配置
composables按需✅ 是可复用逻辑
getSSRProps全局/局部🎯 完全支持SSR 优化指令
Nuxt 模块全局✅ 是分发、复杂功能