음악, 삶, 개발

Vue 3 - dropdown 메뉴 만들기 (최소 순살 코드) 본문

개발 Web/Vue.js 공부방

Vue 3 - dropdown 메뉴 만들기 (최소 순살 코드)

Lee_____ 2022. 9. 14. 02:44

다른 사람들의 코드를 보면 막 css class 명, vue 에서 제공하는 특정 함수들이 막 섞여있어서

그런것들 다 배제하고 작성해야하는 최소한의 코드만을 사용했다.

잔 곁가지들을 다 걷어내고 완전한 순살 코드만 작성한것이다.

"click" 대신 "mousedown" 을 사용하였고,

vue 의 component 들과 송신하기위한 ref 외에는 lifecycle hook 등은 일체 사용하지않고 구현하였다.

dropdown 메뉴에서 중요한건 window event listener 가 메뉴가 열리면 생기고, 닫히면 소멸해야하는것이다.

Vue 에서 잠시 Svelte 로 넘어갔던 이유가 boilerplate 코드가 너무 많다고 느꼈기때문인데,

Vue 3 의 script setup 이 생기면서 거의 Svelte 수준에 코드양을 가질수있게 되었다.

<!-- dropdown.vue -->
<script setup lang="ts">

    import { ref } from 'vue'

    const state  = ref (false)
    const header = ref <HTMLElement | null> (null)

    function toggleListener (active: boolean): void {

        active ?  window.addEventListener    ("mousedown", mouseDownOutside) : 
                  window.removeEventListener ("mousedown", mouseDownOutside)

    }

    function mouseDownHeader (): void {

        toggleListener (state.value = !state.value)

    }

    function mouseDownOutside (e: MouseEvent): void {

        const isOutside = header.value && !header.value.contains(e.target as Node) 

        if (isOutside) toggleListener (state.value = false)

    }

    function mouseDownItem (): void {

        toggleListener (state.value = false)

    }

</script>

<template>

    <button ref = "header" @mousedown.prevent = mouseDownHeader >
        click
    </button>

    <ul v-if = state >
        <li @mousedown.prevent = mouseDownItem >one</li>
        <li @mousedown.prevent = mouseDownItem >two</li>
    </ul>

</template>

위의 코드에서 약간의 살을 붙여서, 선택한 item 을 header 에서 text 로 나타나게끔 해볼수있다.

 

<script setup lang="ts">

    import { ref } from 'vue'

    const items  = ["one", "two", "three", "four"]
    const value  = ref (0)
    const state  = ref (false)
    const header = ref <HTMLElement | null> (null)

    function toggleListener (active: boolean): void {

        active ?  window.addEventListener    ("mousedown", mouseDownOutside) : 
                  window.removeEventListener ("mousedown", mouseDownOutside)

    }

    function mouseDownHeader (): void {

        toggleListener (state.value = !state.value)

    }

    function mouseDownOutside (e: MouseEvent): void {

        const isOutside = header.value && !header.value.contains(e.target as Node) 

        if (isOutside) toggleListener (state.value = false)

    }

    function mouseDownItem (index: number): void {

        value.value = index 
        toggleListener (state.value = false)

    }

</script>

<template>

    <button ref = "header" @mousedown.prevent = mouseDownHeader >
        {{items [value]}}
    </button>

    <ul v-if = state >
        <li v-for = "(item, i) in items" @mousedown.prevent = "() => mouseDownItem (i)" >{{item}}</li>
    </ul>

</template>

 

참고자료:  https://stackoverflow.com/questions/46038989/how-to-hide-dropdown-menu-if-we-click-outside-the-menu-in-vuejs