IT이야기

외부 요소 클릭 감지

cyworld 2022. 3. 26. 16:22
반응형

외부 요소 클릭 감지

요소 외부 클릭을 감지하려면 어떻게 해야 하는가?나는 Vue.js를 사용하고 있어서 내 템플릿 요소 밖에 있을 거야.바닐라 JS로 할 줄 알지만, 내가 Vue.js를 사용할 때, 더 적절한 방법이 있는지 잘 모르겠어.

이것은 바닐라 JS: Javascript Detect Click 이벤트 disput의 솔루션이다.

좀 더 나은 방법으로 요소에 접근할 수 있을까?

내가 사용한 해결책이 있는데, 리너스 보그 대답을 기반으로 하며 vue.js 2.0과 잘 작동한다.

Vue.directive('click-outside', {
  bind: function (el, binding, vnode) {
    el.clickOutsideEvent = function (event) {
      // here I check that click was outside the el and his children
      if (!(el == event.target || el.contains(event.target))) {
        // and if it did, call method provided in attribute value
        vnode.context[binding.expression](event);
      }
    };
    document.body.addEventListener('click', el.clickOutsideEvent)
  },
  unbind: function (el) {
    document.body.removeEventListener('click', el.clickOutsideEvent)
  },
});

다음을 사용하여 바인딩v-click-outside:

<div v-click-outside="doStuff">

여기 작은 데모가 있다.

사용자 지정 지침과 el, 바인딩, vnode의 의미에 대한 자세한 내용은 https://vuejs.org/v2/guide/custom-directive.html#Directive-Hook-Arguments을 참조하십시오.

이 솔루션은 Vue 1에서만 작동하므로 주의하십시오.

사용자 지정 지침을 한 번 설정하면 다음과 같은 문제를 효율적으로 해결할 수 있음:

Vue.directive('click-outside', {
  bind () {
      this.event = event => this.vm.$emit(this.expression, event)
      this.el.addEventListener('click', this.stopProp)
      document.body.addEventListener('click', this.event)
  },   
  unbind() {
    this.el.removeEventListener('click', this.stopProp)
    document.body.removeEventListener('click', this.event)
  },

  stopProp(event) { event.stopPropagation() }
})

사용량:

<div v-click-outside="nameOfCustomEventToCall">
  Some content
</div>

구성 요소:

events: {
  nameOfCustomEventToCall: function (event) {
    // do something - probably hide the dropdown menu / modal etc.
  }
}

JSFiddle에 대한 작업 데모 및 주의사항에 대한 추가 정보:

https://jsfiddle.net/Linusborg/yzm8t8jq/

추가하다tabindex초점을 맞추고 다음을 수행할 수 있도록 구성 요소의 속성:

<template>
    <div
        @focus="handleFocus"
        @focusout="handleFocusOut"
        tabindex="0"
    >
      SOME CONTENT HERE
    </div>
</template>

<script>
export default {    
    methods: {
        handleFocus() {
            // do something here
        },
        handleFocusOut() {
            // do something here
        }
    }
}
</script>

커뮤니티에서 이 작업에 사용할 수 있는 두 가지 패키지가 있음(둘 다 유지 관리됨):

Vue 3의 경우:

대답은 위의 MadisonTrash의 훌륭한 답변을 바탕으로 하지만 새로운 Vue 3 구문을 사용하도록 업데이트되었다.

현재 Vue 3 사를 한다.beforeMount대신에bind그리고unmounted대신에unbind(src).

const clickOutside = {
  beforeMount: (el, binding) => {
    el.clickOutsideEvent = event => {
      // here I check that click was outside the el and his children
      if (!(el == event.target || el.contains(event.target))) {
        // and if it did, call method provided in attribute value
        binding.value();
      }
    };
    document.addEventListener("click", el.clickOutsideEvent);
  },
  unmounted: el => {
    document.removeEventListener("click", el.clickOutsideEvent);
  },
};

createApp(App)
  .directive("click-outside", clickOutside)
  .mount("#app");

생성된() 내의 함수를 사용하여 약간 다른 방법으로 했다.

  created() {
      window.addEventListener('click', (e) => {
        if (!this.$el.contains(e.target)){
          this.showMobileNav = false
        }
      })
  },

이런 식으로, 만약 누군가가 요소 바깥을 클릭한다면, 내 경우에는 이동 탐색기가 숨겨진다.

모든 답변(vue-clickaway의 한 줄 포함)을 결합하여 나에게 적합한 다음과 같은 솔루션을 생각해 냈다.

Vue.directive('click-outside', {
    bind(el, binding, vnode) {
        var vm = vnode.context;
        var callback = binding.value;

        el.clickOutsideEvent = function (event) {
            if (!(el == event.target || el.contains(event.target))) {
                return callback.call(vm, event);
            }
        };
        document.body.addEventListener('click', el.clickOutsideEvent);
    },
    unbind(el) {
        document.body.removeEventListener('click', el.clickOutsideEvent);
    }
});

구성 요소에서 사용:

<li v-click-outside="closeSearch">
  <!-- your component here -->
</li>

Vue.js 2.5.2:

/**
 * Call a function when a click is detected outside of the
 * current DOM node ( AND its children )
 *
 * Example :
 *
 * <template>
 *   <div v-click-outside="onClickOutside">Hello</div>
 * </template>
 *
 * <script>
 * import clickOutside from '../../../../directives/clickOutside'
 * export default {
 *   directives: {
 *     clickOutside
 *   },
 *   data () {
 *     return {
         showDatePicker: false
 *     }
 *   },
 *   methods: {
 *     onClickOutside (event) {
 *       this.showDatePicker = false
 *     }
 *   }
 * }
 * </script>
 */
export default {
  bind: function (el, binding, vNode) {
    el.__vueClickOutside__ = event => {
      if (!el.contains(event.target)) {
        // call method provided in v-click-outside value
        vNode.context[binding.expression](event)
        event.stopPropagation()
      }
    }
    document.body.addEventListener('click', el.__vueClickOutside__)
  },
  unbind: function (el, binding, vNode) {
    // Remove Event Listeners
    document.body.removeEventListener('click', el.__vueClickOutside__)
    el.__vueClickOutside__ = null
  }
}

요소 외부에서는 클릭하지만 상위 항목에서는 클릭할 수 있는 경우

<div class="parent" @click.self="onParentClick">
  <div class="child"></div>
</div>

이건 모달에 쓰는 거야

Vue 3은 지침의 변화를 깨뜨리며, <Vue3>의 모든 방법이 변경/업데이트되었다.궁금하다면, 어떻게 하는 것이 좋을까?Vue 3여기 그 새끼가 있다.자세한 내용은 이 링크를 참조하십시오.

<div v-click-outside="methodToInvoke"></div>

click-outside.js

export default {
  beforeMount: function (el, binding, vnode) {
    binding.event = function (event) {
      if (!(el === event.target || el.contains(event.target))) {
        if (binding.value instanceof Function) {
          binding.value(event)
        }
      }
    }
    document.body.addEventListener('click', binding.event)
  },
  unmounted: function (el, binding, vnode) {
    document.body.removeEventListener('click', binding.event)
  }
}

및 인main.js다음과 같이 덧붙이다.

// Directives
import ClickOutside from './click-outside'

createApp(App)
 .directive('click-outside', ClickOutside)
 .use(IfAnyModules)
 .mount('#app')
export default {
  bind: function (el, binding, vNode) {
    // Provided expression must evaluate to a function.
    if (typeof binding.value !== 'function') {
      const compName = vNode.context.name
      let warn = `[Vue-click-outside:] provided expression '${binding.expression}' is not a function, but has to be`
      if (compName) { warn += `Found in component '${compName}'` }

      console.warn(warn)
    }
    // Define Handler and cache it on the element
    const bubble = binding.modifiers.bubble
    const handler = (e) => {
      if (bubble || (!el.contains(e.target) && el !== e.target)) {
        binding.value(e)
      }
    }
    el.__vueClickOutside__ = handler

    // add Event Listeners
    document.addEventListener('click', handler)
  },

  unbind: function (el, binding) {
    // Remove Event Listeners
    document.removeEventListener('click', el.__vueClickOutside__)
    el.__vueClickOutside__ = null

  }
}

Mobile Safari를 지원하도록 MadisonTrash의 답변을 업데이트했다(이것은 지원하지 않음).click이벤트,touchend대신 사용해야 한다).여기에는 모바일 기기를 끌어서 이벤트가 트리거되지 않도록 점검도 포함된다.

Vue.directive('click-outside', {
    bind: function (el, binding, vnode) {
        el.eventSetDrag = function () {
            el.setAttribute('data-dragging', 'yes');
        }
        el.eventClearDrag = function () {
            el.removeAttribute('data-dragging');
        }
        el.eventOnClick = function (event) {
            var dragging = el.getAttribute('data-dragging');
            // Check that the click was outside the el and its children, and wasn't a drag
            if (!(el == event.target || el.contains(event.target)) && !dragging) {
                // call method provided in attribute value
                vnode.context[binding.expression](event);
            }
        };
        document.addEventListener('touchstart', el.eventClearDrag);
        document.addEventListener('touchmove', el.eventSetDrag);
        document.addEventListener('click', el.eventOnClick);
        document.addEventListener('touchend', el.eventOnClick);
    }, unbind: function (el) {
        document.removeEventListener('touchstart', el.eventClearDrag);
        document.removeEventListener('touchmove', el.eventSetDrag);
        document.removeEventListener('click', el.eventOnClick);
        document.removeEventListener('touchend', el.eventOnClick);
        el.removeAttribute('data-dragging');
    },
});

vue 3에 대한 전체 사례

매디슨트래쉬 답변과 사파리 호환 및 vue 3 api 변경을 위한 benrwb 및 프레드리벳 트윗을 기반으로 한 완벽한 솔루션이다.

편집:

아래에 제안된 솔루션은 여전히 유용하며, 사용 방법은 여전히 유효하지만, 나는 그것을 사용하기 위해 변경했다.document.elementsFromPoint대신에event.contains왜냐하면 그것은 어린아이로 인식하지 못하기 때문이다.<path>svgs의 안쪽에 있는 . 그러니까 과 같다그래서 올바른 지시는 다음과 같다.

export default {
    beforeMount: (el, binding) => {
        el.eventSetDrag = () => {
            el.setAttribute("data-dragging", "yes");
        };
        el.eventClearDrag = () => {
            el.removeAttribute("data-dragging");
        };
        el.eventOnClick = event => {
            const dragging = el.getAttribute("data-dragging");
            // Check that the click was outside the el and its children, and wasn't a drag
            console.log(document.elementsFromPoint(event.clientX, event.clientY))
            if (!document.elementsFromPoint(event.clientX, event.clientY).includes(el) && !dragging) {
                // call method provided in attribute value
                binding.value(event);
            }
        };
        document.addEventListener("touchstart", el.eventClearDrag);
        document.addEventListener("touchmove", el.eventSetDrag);
        document.addEventListener("click", el.eventOnClick);
        document.addEventListener("touchend", el.eventOnClick);
    },
    unmounted: el => {
        document.removeEventListener("touchstart", el.eventClearDrag);
        document.removeEventListener("touchmove", el.eventSetDrag);
        document.removeEventListener("click", el.eventOnClick);
        document.removeEventListener("touchend", el.eventOnClick);
        el.removeAttribute("data-dragging");
    },
};

이전 답변:

지시

const clickOutside = {
    beforeMount: (el, binding) => {
        el.eventSetDrag = () => {
            el.setAttribute("data-dragging", "yes");
        };
        el.eventClearDrag = () => {
            el.removeAttribute("data-dragging");
        };
        el.eventOnClick = event => {
            const dragging = el.getAttribute("data-dragging");  
            // Check that the click was outside the el and its children, and wasn't a drag
            if (!(el == event.target || el.contains(event.target)) && !dragging) {
                // call method provided in attribute value
                binding.value(event);
            }
        };
        document.addEventListener("touchstart", el.eventClearDrag);
        document.addEventListener("touchmove", el.eventSetDrag);
        document.addEventListener("click", el.eventOnClick);
        document.addEventListener("touchend", el.eventOnClick);
    },
    unmounted: el => {
        document.removeEventListener("touchstart", el.eventClearDrag);
        document.removeEventListener("touchmove", el.eventSetDrag);
        document.removeEventListener("click", el.eventOnClick);
        document.removeEventListener("touchend", el.eventOnClick);
        el.removeAttribute("data-dragging");
    },
}

createApp(App)
  .directive("click-outside", clickOutside)
  .mount("#app");

은 지시가 되는 구성 및 지만이 지만이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이이유하하하하이유임을 한다.event.target원소 또한 어린아이다.만약 그런 경우라면, 그것은 구성 요소 안에 있기 때문에 트리거되지 않을 것이다.

사용방법

트리거를 처리하기 위한 메서드 참조와 함께 지시어로만 사용하면 된다.

<template>
    <div v-click-outside="myMethod">
        <div class="handle" @click="doAnotherThing($event)">
            <div>Any content</div>
        </div>
    </div>
</template>

다음 코드를 사용하십시오.

표시 숨기기 단추

 <a @click.stop="visualSwitch()"> show hide </a>

표시-숨기기 요소

<div class="dialog-popup" v-if="visualState" @click.stop=""></div>

각본을 뜨다

data () { return {
    visualState: false,
}},
methods: {
    visualSwitch() {
        this.visualState = !this.visualState;
        if (this.visualState)
            document.addEventListener('click', this.visualState);
        else
            document.removeEventListener('click', this.visualState);
    },
},

업데이트: watch 제거, 전파 중지 추가

나는 추가적인 기능들이 싫어서...여기에 추가 vue 메서드가 없는 멋진 vue 솔루션만 있음

  1. html 요소 생성, 제어 및 지시어 설정
    <p @click="popup = !popup" v-out="popup">

    <div v-if="popup">
       My awesome popup
    </div>
  1. 다음과 같은 데이터에서 변수 생성
data:{
   popup: false,
}
  1. 부에 훈령을 붙이다그것의
Vue.directive('out', {

    bind: function (el, binding, vNode) {
        const handler = (e) => {
            if (!el.contains(e.target) && el !== e.target) {
                //and here is you toggle var. thats it
                vNode.context[binding.expression] = false
            }
        }
        el.out = handler
        document.addEventListener('click', handler)
    },

    unbind: function (el, binding) {
        document.removeEventListener('click', el.out)
        el.out = null
    }
})

나는 몸의 끝에 다음과 같은 div를 창조한다.

<div v-if="isPopup" class="outside" v-on:click="away()"></div>

.outside는:

.outside {
  width: 100vw;
  height: 100vh;
  position: fixed;
  top: 0px;
  left: 0px;
}

그리고 away()는 Vue 인스턴스의 방법이다.

away() {
 this.isPopup = false;
}

이렇게 클릭 이벤트에 두 개의 이벤트 수신기를 등록할 수 있다.

document.getElementById("some-area")
        .addEventListener("click", function(e){
        alert("You clicked on the area!");
        e.stopPropagation();// this will stop propagation of this event to upper level
     }
);

document.body.addEventListener("click", 
   function(e) {
           alert("You clicked outside the area!");
         }
);

이 물음에 대한 답은 이미 많으며, 그 대부분은 유사한 관습 지시 사상에 근거하고 있다.이 접근방식의 문제는 메서드 함수를 지시문에 전달해야 하고, 다른 사건처럼 코드를 직접 쓸 수 없다는 것이다.

나는 새로운 소포를 만들었다.vue-on-clickout그건 정말 달라요.다음 사이트에서 확인하십시오.

글씨를 쓸 수 있게 해준다.v-on:clickout다른 사건들처럼 말이야예를 들어, 당신은 글을 쓸 수 있다.

<div v-on:clickout="myField=value" v-on:click="myField=otherValue">...</div>

그리고 그것은 동작한다.

갱신하다

vue-on-clickout이제 Vue 3을 지지한다!

업데이트 2

vue-on-clickout이제 모든 프런트 엔드 프레임워크(또는 바닐라)에 적용되는 새로운 패키지로 대체된다!

지시문에서 사용자 정의 네이티브 자바스크립트 이벤트를 내보낼 수 있다.node.dispatchEvent를 사용하여 노드에서 이벤트를 디스패치하는 지시문 만들기

let handleOutsideClick;
Vue.directive('out-click', {
    bind (el, binding, vnode) {

        handleOutsideClick = (e) => {
            e.stopPropagation()
            const handler = binding.value

            if (el.contains(e.target)) {
                el.dispatchEvent(new Event('out-click')) <-- HERE
            }
        }

        document.addEventListener('click', handleOutsideClick)
        document.addEventListener('touchstart', handleOutsideClick)
    },
    unbind () {
        document.removeEventListener('click', handleOutsideClick)
        document.removeEventListener('touchstart', handleOutsideClick)
    }
})

이렇게 사용할 수 있는 것

h3( v-out-click @click="$emit('show')" @out-click="$emit('hide')" )

루트 요소 내부에 여러 요소가 포함된 구성 요소가 있는 경우 이 솔루션을 부울로 작동하십시오.

<template>
  <div @click="clickInside"></div>
<template>
<script>
export default {
  name: "MyComponent",
  methods: {
    clickInside() {
      this.inside = true;
      setTimeout(() => (this.inside = false), 0);
    },
    clickOutside() {
      if (this.inside) return;
      // handle outside state from here
    }
  },
  created() {
    this.__handlerRef__ = this.clickOutside.bind(this);
    document.body.addEventListener("click", this.__handlerRef__);
  },
  destroyed() {
    document.body.removeEventListener("click", this.__handlerRef__);
  },
};
</script>
  <button 
    class="dropdown"
    @click.prevent="toggle"
    ref="toggle"
    :class="{'is-active': isActiveEl}"
  >
    Click me
  </button>

  data() {
   return {
     isActiveEl: false
   }
  }, 
  created() {
    window.addEventListener('click', this.close);
  },
  beforeDestroy() {
    window.removeEventListener('click', this.close);
  },
  methods: {
    toggle: function() {
      this.isActiveEl = !this.isActiveEl;
    },
    close(e) {
      if (!this.$refs.toggle.contains(e.target)) {
        this.isActiveEl = false;
      }
    },
  },

단답:작업은 사용자 지정 지시사항을 사용하여 수행해야 한다.

여기에도 이렇게 말하는 훌륭한 해답이 많지만, 내가 본 해답의 대부분은 아웃사이드 클릭을 광범위하게 사용하기 시작할 때(특히 레이어드 또는 복수의 제외) 분해된다.나는 Custom Directives의 뉘앙스와 특히 이 지침의 구현에 대해 이야기하는 매체 기사를 썼다.그것은 모든 에지 케이스를 커버하지는 않을지 모르지만 내가 생각해낸 모든 것을 커버해 주었다.

이렇게 하면 여러 바인딩, 여러 단계의 다른 요소 제외가 설명되며 처리기가 "비즈니스 논리"만 관리할 수 있다.

여기 최소한 그것의 정의 부분에 대한 코드가 있어, 자세한 설명은 기사를 확인해봐.

var handleOutsideClick={}
const OutsideClick = {
  // this directive is run on the bind and unbind hooks
  bind (el, binding, vnode) {
    // Define the function to be called on click, filter the excludes and call the handler
    handleOutsideClick[el.id] = e => {
      e.stopPropagation()
      // extract the handler and exclude from the binding value
      const { handler, exclude } = binding.value
      // set variable to keep track of if the clicked element is in the exclude list
      let clickedOnExcludedEl = false
      // if the target element has no classes, it won't be in the exclude list skip the check
      if (e.target._prevClass !== undefined) {
        // for each exclude name check if it matches any of the target element's classes
        for (const className of exclude) {
          clickedOnExcludedEl = e.target._prevClass.includes(className)
          if (clickedOnExcludedEl) {
            break // once we have found one match, stop looking
          }
        }
      }
      // don't call the handler if our directive element contains the target element
      // or if the element was in the exclude list
      if (!(el.contains(e.target) || clickedOnExcludedEl)) {
        handler()
      }
    }
    // Register our outsideClick handler on the click/touchstart listeners
    document.addEventListener('click', handleOutsideClick[el.id])
    document.addEventListener('touchstart', handleOutsideClick[el.id])
    document.onkeydown = e => {
      //this is an option but may not work right with multiple handlers
      if (e.keyCode === 27) {
        // TODO: there are minor issues when escape is clicked right after open keeping the old target
        handleOutsideClick[el.id](e)
      }
    }
  },
  unbind () {
    // If the element that has v-outside-click is removed, unbind it from listeners
    document.removeEventListener('click', handleOutsideClick[el.id])
    document.removeEventListener('touchstart', handleOutsideClick[el.id])
    document.onkeydown = null //Note that this may not work with multiple listeners
  }
}
export default OutsideClick

사용자가 루트 구성요소(모든 수준 구성요소와 함께 작동)를 유지하는지 여부를 알고자 하는 경우

Vue({
  data: {},
  methods: {
    unfocused : function() {
      alert('good bye');
    }
  }
})
<template>
  <div tabindex="1" @blur="unfocused">Content inside</div>
</template>

모달 바깥을 클릭할 때 모달 숨기는 방법을 찾는 사람이 있다면 말이다.모달은 보통 클래스의 포장지를 가지고 있기 때문이다.modal-wrap이름만 대면 돼도 돼@click="closeModal"포장되어vuejs 설명서에 명시된 이벤트 처리를 사용하여 클릭된 대상이 래퍼에 있는지 모달에 있는지 확인할 수 있다.

methods: {
  closeModal(e) {
    this.event = function(event) {
      if (event.target.className == 'modal-wrap') {
        // close modal here
        this.$store.commit("catalog/hideModal");
        document.body.removeEventListener("click", this.event);
      }
    }.bind(this);
    document.body.addEventListener("click", this.event);
  },
}
<div class="modal-wrap" @click="closeModal">
  <div class="modal">
    ...
  </div>
<div>

나는 이 패키지를 사용하고 있다: https://www.npmjs.com/package/vue-click-outside

그것은 나에게 잘 맞는다.

HTML :

<div class="__card-content" v-click-outside="hide" v-if="cardContentVisible">
    <div class="card-header">
        <input class="subject-input" placeholder="Subject" name=""/>
    </div>
    <div class="card-body">
        <textarea class="conversation-textarea" placeholder="Start a conversation"></textarea>
    </div>
</div>

내 스크립트 코드:

import ClickOutside from 'vue-click-outside'
export default
{
    data(){
        return {
            cardContentVisible:false
        }
    },
    created()
    {
    },
    methods:
        {
            openCardContent()
            {
                this.cardContentVisible = true;
            }, hide () {
            this.cardContentVisible = false
                }
        },
    directives: {
            ClickOutside
    }
}

@Denis Danilenko 솔루션은 나에게 효과가 있다, 내가 한 것은 다음과 같다: 내가 VueJS CLI3와 NuxtJS를 여기서 그리고 Bootstrap4와 함께 사용하고 있지만, 그것은 NuxtJS가 없는 VueJS에서도 효과가 있을 것이다:

<div
    class="dropdown ml-auto"
    :class="showDropdown ? null : 'show'">
    <a 
        href="#" 
        class="nav-link" 
        role="button" 
        id="dropdownMenuLink" 
        data-toggle="dropdown" 
        aria-haspopup="true" 
        aria-expanded="false"
        @click="showDropdown = !showDropdown"
        @blur="unfocused">
        <i class="fas fa-bars"></i>
    </a>
    <div 
        class="dropdown-menu dropdown-menu-right" 
        aria-labelledby="dropdownMenuLink"
        :class="showDropdown ? null : 'show'">
        <nuxt-link class="dropdown-item" to="/contact">Contact</nuxt-link>
        <nuxt-link class="dropdown-item" to="/faq">FAQ</nuxt-link>
    </div>
</div>
export default {
    data() {
        return {
            showDropdown: true
        }
    },
    methods: {
    unfocused() {
        this.showDropdown = !this.showDropdown;
    }
  }
}

이 패키지 vue-click-outside 사용

그것은 간단하고 신뢰할 수 있으며, 현재 다른 많은 패키지에서 사용되고 있다.필요한 구성 요소에서만 패키지를 호출하여 Javascript 번들 크기를 줄일 수도 있다(아래 예 참조).

npm install vue-click-outside

사용량:

<template>
  <div>
    <div v-click-outside="hide" @click="toggle">Toggle</div>
    <div v-show="opened">Popup item</div>
  </div>
</template>

<script>
import ClickOutside from 'vue-click-outside'

export default {
  data () {
    return {
      opened: false
    }
  },

  methods: {
    toggle () {
      this.opened = true
    },

    hide () {
      this.opened = false
    }
  },

  mounted () {
    // prevent click outside event with popupItem.
    this.popupItem = this.$el
  },

  // do not forget this section
  directives: {
    ClickOutside
  }
}
</script>

휠을 다시 개발하지 말고 이 패키지를 v-click-outside로 사용하십시오.

외부 클릭을 처리하는 새 구성 요소를 생성할 수 있음

Vue.component('click-outside', {
  created: function () {
    document.body.addEventListener('click', (e) => {
       if (!this.$el.contains(e.target)) {
            this.$emit('clickOutside');
           
        })
  },
  template: `
    <template>
        <div>
            <slot/>
        </div>
    </template>
`
})

그리고 다음 구성 요소를 사용하십시오.

<template>
    <click-outside @clickOutside="console.log('Click outside Worked!')">
      <div> Your code...</div>
    </click-outside>
</template>

누가 이 답을 볼지는 모르겠지만 여기 있다.여기서의 아이디어는 단순히 요소 자체 밖에서 클릭이 이루어졌는지를 감지하는 것이다.

나는 먼저 내 "dropdown"의 메인 디브에 아이디를 주는 것으로 시작한다.

<template>
  <div class="relative" id="dropdown">
    <div @click="openDropdown = !openDropdown" class="cursor-pointer">
      <slot name="trigger" />
    </div>

    <div
      class="absolute mt-2 w-48 origin-top-right right-0 text-red  bg-tertiary text-sm text-black"
      v-show="openDropdown"
      @click="openDropdown = false"
    >
      <slot name="content" />
    </div>
  </div>
</template>

그리고 나서 나는 마우스 이벤트의 경로를 반복해서 내 아이디가 "dropdown"인 div가 거기에 있는지 확인한다.만약 그렇다면, 우리는 괜찮고, 그렇지 않다면, 우리는 드롭다운을 닫는다.

<script>
export default {
  data() {
    return {
      openDropdown: false,
    };
  },
  created() {
    document.addEventListener("click", (e) => {
      let me = false;
      for (let index = 0; index < e.path.length; index++) {
        const element = e.path[index];

        if (element.id == "dropdown") {
          me = true;
          return;
        }
      }

      if (!me) this.openDropdown = false;
    });
  }
};
</script>

중첩된 요소가 많다면 성능 문제가 발생할 수 있다고 확신하지만, 나는 이것이 가장 게으른 방법이라는 것을 알았다.

참조URL: https://stackoverflow.com/questions/36170425/detect-click-outside-element

반응형