Vue3.0 implements the encapsulation of the drop-down menu

Vue3.0 implements the encapsulation of the drop-down menu

Vue3.0 has been out for a while, and it is necessary to start studying it!

Let’s first look at the effect we want to achieve

It is very common to expand the content of the menu item. How to develop it in vue3.0? Here we use the default style of bootstrap

Idea 1:

<DropDown :title="'Exit'" :list="menuLists" />

Idea 2:

<drop-down :title="'Exit'">
   <drop-dowm-item>Create a new article</drop-down-item>
   <drop-dowm-item>Edit Article</drop-down-item>
   <drop-dowm-item>Personal Information</drop-down-item>
</drop-down>

Both ideas are fine. In comparison, the second idea is clearer. When using it, you know the specific level, which is also the mode of elementUI component development.
Now let's analyze the second component development idea

DropDown.ts

<template>
  <div class="dropdown" ref="dropDownRef">
    <a
      @click.prevent="toggleOpen"
      class="btn btn-secondary dropdown-toggle"
      href="#" rel="external nofollow" 
    >
      {{ title }}
    </a>
    <div class="dropdown-menu" :style="{ display: 'block' }" v-show="isOpen">
      <slot></slot>
    </div>
  </div>
</template>

js part

<script lang="ts">
import { defineComponent, ref, onMounted, onUnmounted, watch } from "vue";
import useClickOutside from "../hooks/useClickOutside";
export default defineComponent({
  name: "DropDown",
  props: {
    title:
      type: String,
      required: true,
    },
  },

  setup(context) {
    const isOpen = ref(false);
    //vue3.0 gets the reference of the DOM object const dropDownRef = ref<null | HTMLElement>(null);
    const toggleOpen = () => {
      isOpen.value = !isOpen.value;
    };
    const handleClick = (e: MouseEvent) => {
      console.log(e.target, "e");
      if (dropDownRef.value) {
        console.log(dropDownRef.value);
        if (
        //contains determines whether the node contains the node!dropDownRef.value.contains(e.target as HTMLElement) &&
          isOpen.value
        ) {
          isOpen.value = false;
        }
      }
    };
    onMounted(() => {
    //Register global click event document.addEventListener("click", handleClick);
    });
    onUnmounted(() => {
    //Unbind document.removeEventListener("click", handleClick);
    }); 
    return {
      isOpen,
      toggleOpen,
      dropDownRef,
    };
  },
});
</script>

DropDownItem.ts

<template>
  <li class="dropdowm-option" :class="{ 'is-disabled': disabled }">
    <slot></slot>
  </li>
</template>
<style scoped>

/* This is where the slot needs to penetrate*/
.dropdowm-option.is-disabled >>> * {
  color: #6c757d;
  pointer-events: none;
  background-color: transparent;
}
</style>
<script lang="ts">
import { defineComponent } from "vue";

export default defineComponent({
  props: {
    disabled:
      type: Boolean,
      default: false,
    },
  },
  setup() {
    return {};
  },
});
</script>

At this point the component is complete. But... we can see that the event of clicking to hide the entire document is not very relevant to the entire component, so we can extract it into a hook

useClickOutside.ts

import { ref, onMounted, onUnmounted,Ref } from 'vue'
const useClickOutside = (elementRef:Ref<null | HTMLElement>) => {
    const isClickOutside = ref(false)
    const handler = (e: MouseEvent) => {
        console.log(elementRef.value);
        if (elementRef.value) {
            if (elementRef.value.contains(e.target as HTMLElement)) {
                isClickOutside.value = false
            } else {
                isClickOutside.value = true
            }
        }
    }
    onMounted(() => {
      document.addEventListener("click", handler);
    });
    onUnmounted(() => {
      document.removeEventListener("click", handler);
    });
    return isClickOutside
}

export default useClickOutside

Then rewrite our DropDown.ts component

//Delete the existing event logic<script lang="ts">
... 
 const isClickOutside = useClickOutside(dropDownRef);
    /* console.log(isClickOutside.value, "isClickOutside"); */
    //Introduce the monitoring method, when the data changes, we change the value of isOpen to false
    watch(isClickOutside, (newValue) => {
      if (isOpen.value && isClickOutside.value) {
        isOpen.value = false;
      }
    });
 ...
</script>

The same effect is achieved, and the code of the entire component is also simplified a lot!

The above is the full content of this article. I hope it will be helpful for everyone’s study. I also hope that everyone will support 123WORDPRESS.COM.

You may also be interested in:
  • Detailed explanation of vue3 cache page keep-alive and unified routing processing
  • Vue3.0 combined with bootstrap to create a multi-page application
  • Vue3+TypeScript implements a complete example of a recursive menu component
  • Detailed explanation of the difference between routing hooks in Vue2.x and Vue3.x
  • A simple example of using Vue3 routing VueRouter4
  • Vue2/vue3 routing permission management method example
  • Use of Vue3 pages, menus, and routes

<<:  Solve the problem of IDEA configuring tomcat startup error

>>:  Determine whether MySQL update will lock the table through examples

Recommend

Win2008 R2 mysql 5.5 zip format mysql installation and configuration

Win2008 R2 zip format mysql installation and conf...

React + Threejs + Swiper complete code to achieve panoramic effect

Let’s take a look at the panoramic view effect: D...

Reasons and methods for Waiting for table metadata lock in MySQL

When MySQL performs DDL operations such as alter ...

Difference between MySQL btree index and hash index

In MySQL, most indexes (such as PRIMARY KEY, UNIQ...

Will this SQL writing method really cause the index to fail?

Preface There are often some articles on the Inte...

Docker data management and network communication usage

You can install Docker and perform simple operati...

How to solve the mysql error 1033 Incorrect information in file: 'xxx.frm'

Problem Description 1. Database of the collection...

MySQL 8.0.20 installation tutorial and detailed tutorial on installation issues

Original address: https://blog.csdn.net/m0_465798...

JS realizes the scrolling effect of announcement online

This article shares the specific code of JS to ac...

Summary of MySQL usage specifications

1. InnoDB storage engine must be used It has bett...

How to add a disk in Vmware: Expand the disk

This article describes how to add or expand a dis...

Introduction to fourteen cases of SQL database

Data Sheet /* Navicat SQLite Data Transfer Source...

Listen directive example analysis in nginx

Plot Review In the previous article, we analyzed ...