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

Disable IE Image Toolbar

I just tried it on IE6, and it does show the toolb...

Detailed tutorial on installing harbor private warehouse using docker compose

Overview What is harbor? The English word means: ...

CSS to achieve scrolling image bar example code

On some websites, you can often see some pictures...

Docker generates images through containers and submits DockerCommit in detail

Table of contents After creating a container loca...

Perform data statistics on different values ​​of the same field in SQL

Application scenario: It is necessary to count th...

How to construct a table index in MySQL

Table of contents Supports multiple types of filt...

MySQL detailed explanation of isolation level operation process (cmd)

Read uncommitted example operation process - Read...

How to collect Nginx logs using Filebeat

Nginx logs can be used to analyze user address lo...

MySQL 8.0.15 installation and configuration graphic tutorial

This article records the installation and configu...

How to implement responsive layout with CSS

Implementing responsive layout with CSS Responsiv...

Detailed explanation of Vue life cycle functions

Table of contents Lifecycle Functions Common life...

How to calculate the value of ken_len in MySQL query plan

The meaning of key_len In MySQL, you can use expl...

The principle and direction of JavaScript this

How to determine what this points to? ①When calle...