How to write a VUE3 plug-in

How to write a VUE3 plug-in

As a plug-in for VUe3, you need to use the following syntax:

import {createApp} from 'vue const app = createApp(component, props) app.use(plugin)Copy the code

CreateApp takes two parameters, the Component template component and the props property of the component template.

Why can use? Because vue3 has an install method inside that is used to install extension tripartite plug-ins

  • First, the plugin has its own template, our.vue file

Here we are going to write a right-click menu directive, we install this directive on an element, the right-click menu appears

<template>
  <! -- Right click menu -->
  <div
    id="rightMenuDom"
    class="right-menu"
    :style="{ display: rightMenuStatus, top: rightMenuTop, left: rightMenuLeft, }"
  >
    <ul>
      <li v-for="item in rightMenuList" :key="item.id" v-show="item.id <= 3">
        <! -- if status is true, disable -->
        <span v-if="item.text? .status === true" class="disable">
          {{ item.text.content }}
        </span>
        <! -- If status is false, the argument is an object, and the value in content is set to -->
        <span v-else-if="item.text? .status === false" @click="item.handler">
          {{ item.text.content }}
        </span>
        <span v-else @click="item.handler">{{ item.text }}</span>
      </li>
      <li>
        <div v-for="item in rightMenuList" :key="item.id" v-show="item.id > 3">
          <! -- if status is true, disable -->
          <span v-if="item? .status === true" class="disable">
            {{ item.text.content }}
          </span>
          <! -- If status is false, the argument is an object, and the value in content is set to -->
          <span v-else-if="item.text? .status === false" @click="item.handler">
            {{ item.text.content }}
          </span>
          <span v-else @click="item.handler">
            {{ item.text }}
          </span>
        </div>
      </li>
    </ul>
  </div>
</template>

<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
  name: "RightMenu".props: {
    rightMenuStatus: String.rightMenuTop: String.rightMenuLeft: String.rightMenuList: Array,}});</script>

<style lang="scss" scoped>// Right-click menu style.right-menu {
  position: fixed;
  left: 0;
  top: 0;
  width: 166px;
  height: auto;
  background-color: rgb(242.242.242);
  border: solid 1px #c2c1c2;
  box-shadow: 0 10px 10px #c2c1c2;
  display: none;
  border-radius: 5px;
  ul {
    padding: 0;
    margin: 0;
    font-size: 15px;
    li {
      list-style: none;
      box-sizing: border-box;
      padding: 6px 0;
      border-bottom: 1px solid rgb(216.216.217);
      &:nth-child(1) {
        padding-top: 2px;
      }
      &:nth-last-child(1) {
        border-bottom: none;
      }
      div {
        height: 25px;
        span {
          display: block;
          height: 100%;
          line-height: 25px;
          padding-left: 16px;
          &:hover {
            background-color: #0070f5;
            cursor: pointer;
            color: #ffffff; }} // Disallow clicking on styles.disable {
          color: # 666666;
          &:hover {
            cursor: not-allowed;
            background-color: #f2f2f2;
            color: # 666666;
          }
        }
      }
    }
  }
}
</style>
Copy the code

Now that I have a template,

  • We need to create an app
  • Create an element div to append to body
  • Then use the app to mount the div element
/** * Hangs the component on the node *@param Comp needs to mount components *@param Prop Specifies the parameter */ to pass to the component

const createComp = function (comp: Component, prop: rightMenuAttribute) {
    // Create a component
    constapp = createApp(comp, { ... prop })// Create an element
    const divEle = document.createElement('div');
    // Attach the created div element to the body
    document.body.appendChild(divEle);
    // Mount the component into the div you just created
    app.mount(divEle);
    // Returns the mounted element to facilitate this operation
    return divEle;
}
Copy the code

Then we need to expose an install method that handles all the logic of the right-click menu so that Vue can use the plugin

export default {
    install(app: App): void {
        // Listen for global clicks and destroy the right-click menu DOM
        document.body.addEventListener('click'.() = > {
            if(menuVM ! =null) {
                // Destroy the right-click menu DOM
                document.body.removeChild(menuVM);
                menuVM = null; }});// Create directive
        app.directive("rightClick", (el, binding): boolean | void= > {
            // Determine whether the directive binding element exists
            if (el == null) {
                throw "Right click instruction error: element unbound";
            }
            el.oncontextmenu = function (e: MouseEvent) {
                if(menuVM ! =null) {
                    // Destroy the DOM of the right-click menu triggered last time
                    document.body.removeChild(menuVM);
                    menuVM = null;
                }
                const textArray = binding.value.text;
                const handlerObj = binding.value.handler;
                // Menu options and event handlers exist
                if (textArray == null || handlerObj == null) {
                    throw "Right-click menu contents and event handlers are mandatory";
                }
                // Event handler array
                const handlerArray = [];
                // Processed right click menu
                const menuList = [];
                // Put the event handler into an array
                for (const key in handlerObj) {
                    handlerArray.push(handlerObj[key]);
                }
                if(textArray.length ! == handlerArray.length) {// The amount of text is not equal to the event handling
                    throw "Every option in the right-click menu must have its event handler.";
                }
                // Append right-click menu data
                for (let i = 0; i < textArray.length; i++) {
                    // Right-click the menu object and add the name
                    const menuObj: rightMenuObjType = {
                        text: textArray[i],
                        handler: handlerArray[i],
                        id: i + 1
                    }
                    menuList.push(menuObj);
                }
                // The coordinates of the mouse point
                const oX = e.clientX;
                const oY = e.clientY;
                // Dynamically mount the component to display the right-click menu
                menuVM = createComp(RightMenu, {
                    rightMenuStatus: "block".rightMenuTop: oY + "px".rightMenuLeft: oX + "px".rightMenuList: menuList
                })
                return false; }}}})Copy the code

pluginType.ts

// The types used in the plug-in are uniformly defined
// right-click the DOM attribute definition

export type rightMenuAttribute = {
    rightMenuStatus: string; // Right-click menu to display hidden state
    rightMenuTop: string; // Right click menu display position: left measurement distance
    rightMenuLeft: string; // Right-click menu to display position: top distance
    rightMenuList: Array<rightMenuObjType>; // Right-click menu list data: text list, event handler
}

// right-click menu type definitions
export type rightMenuObjType = {
    id: number,
    text: string | { status: boolean, content: string }, // Text array
    handler: Record<string, (. params: any) = > void> // Event handlers
}

// right-click menu parameter type definition
export type rightMenuType = {
    this: any, // The current component this object
    text: Array<string | { status: boolean, content: string }>, // Text array
    handler: Record<string, (. params: any) = > void> // Event handlers
}


Copy the code