When I was refactoring an old project with VUe3 recently, I found that vuE-Clipboard3 only provided a composite API, and the instructions in v2 version seemed to be missing. It was a good time to think about how to package the instructions in the project library.

Train of thought
  1. Create a separate folder for the instruction set
  2. The index.ts export provides a Plugin object in which all directives are installed collectively

The file structure is as follows:

The contents of index.ts are also easier to implement:

//index.ts
import { ObjectDirective, App, Plugin } from "vue";

// Custom directives can reference more than one
import vClipboard from "./vClipboard";

// Define the instruction option category
export interface DirectiveOption {
  name: string; // Directive name
  options: ObjectDirective; // Command options
}

// Build the instruction set
const directives: DirectiveOption[] = [vClipboard];

export default <Plugin>{
  install: (app: App) = > {
 // Install instruction set
    directives.forEach((item) = >{ app.directive(item.name, item.options); }); }};Copy the code
  1. We can export each directive individually if we want to use on-demand references
VClipboard3 instruction implementation
  1. The original vclipboard provides the following commands: V-CLIpboard :copy, V-Clipboard :success, and V-Clipboard :error
  2. The VUe3 directive also supports dynamic instruction parameters
  3. We only need to deal with these instruction parameters
  4. Copy accepts the value that you want to copy
  5. Success accepts a successful callback from COPY
  6. Error accepts a copy failure callback
  7. Our directive supports copy

Based on the above code implementation is as follows:

// vClipboard.ts

import { DirectiveOption } from "./index";
// Vue-Clipboard3 composition API
import useClipboard from "vue-clipboard3";
const { toClipboard } = useClipboard();
export default <DirectiveOption>{
  name: "clipboard".options: {
   / / a mount
    mounted(el, binding) {
     // binding.arg is a dynamic directive parameter
     // Since directives are responsive, we need to have a "global" object, so we use el itself instead of wasting resources with other objects
     // Bind copy's value success callback, failure callback and click event to el for easy operation during update and uninstall
      switch (binding.arg) {
        case "copy":
        / / copy
          el.clipValue = binding.value;
        / / click event
          el.clipCopy = function () {
            toClipboard(el.clipValue)
              .then(result= > {
                el.clipSuccess && el.clipSuccess(result);
              })
              .catch(err= > {
                el.clipError && el.clipError(err);
              });
          };
        // Bind the click event
          el.addEventListener("click", el.clipCopy);
          break;
        case "success":
        // Successful callback
          el.clipSuccess = binding.value;
          break;
        case "error":
        // Failed callback
          el.clipError = binding.value;
          break; }},// Change the corresponding value
    updated(el, binding) {
      switch (binding.arg) {
        case "copy":
          el.clipValue = binding.value;
          break;
        case "success":
          el.clipSuccess = binding.value;
          break;
        case "error":
          el.clipError = binding.value;
          break; }},// Remove the click event to remove the corresponding custom property
    unmounted(el, binding) {
      switch (binding.arg) {
        case "copy":
          el.removeEventListener("click", el.clipCopy);
          delete el.clipValue;
          delete el.clipCopy;
          break;
        case "success":
          delete el.clipSuccess;
          break;
        case "error":
          delete el.clipError;
          break; ,}}}};Copy the code
use
  1. Global mount
import { createApp } from 'vue'
import DirectiveExtensions from './directive'
import App from './App.vue'
const app = createApp(App)
app.use(DirectiveExtensions)
app.mount('#app')
Copy the code
  1. Components use
<template>
  <section class="test-component-copy">
        <div
          class="btn-copy"
          v-clipboard:copy="content"
          v-clipboard:success="Copy"
          v-clipboard:error="Error"
        >{{ content }}</div>
      </div>
  </section>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { toast } from '.. /.. /.. /components/toast/useToast'
const content = ref("Please manually enter what you want to copy in the code!")
function Copy() {
  toast('Content copied to clipboard! ');
}
function Error() {
  toast('Copy error! ');
}
</script>
Copy the code
Granularity and location of instruction encapsulation
  1. Vue3 provides a way to customize instructions in setup
  2. So we need a tradeoff, generally generic instructions that we recommend going straight into the instruction set
  3. If the instructions are not generic, you can customize them in Setup alone, but my feeling is that if the instructions are not generic, then they don’t need to exist
Thank you for reading