WEB/Vue.js

[Vue.js] Custom Directive : Outside Click Event

S0PH1A 2021. 1. 13. 22:28
๋ฐ˜์‘ํ˜•

[Vue.js] Custom Directive : Outside Click Event

 

 

| `Custom Directive`๋ž€? ๐Ÿ‘‰ itinerant.tistory.com/181

 

 

 

Custom Directive๋ฅผ ์ด์šฉํ•ด์„œ, ๋””๋ ‰ํ‹ฐ๋ธŒ๋ฅผ ๊ฐ–๊ณ  ์žˆ๋Š” ์—˜๋ฆฌ๋จผํŠธ ๋ฐ”๊นฅ(์™ธ) ๋ถ€๋ถ„์„ ํด๋ฆญํ•  ๊ฒฝ์šฐ๋ฅผ ๊ฐ์ง€ํ•˜๋Š” ์ด๋ฒคํŠธ๋ฅผ ๋งŒ๋“ค์–ด ๋ณด๊ณ ์ž ํ•œ๋‹ค.

 

1. ์›๋ฆฌ

โ˜๏ธ ๋ฐ”๊นฅ ๋ถ€๋ถ„์„ ์„ ํƒํ•˜๋Š”์ง€ ๊ฐ์ง€ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Body ํด๋ฆญ ์ด๋ฒคํŠธ๋ฅผ ๊ฐ์ง€ํ•ด์„œ ํ˜„์žฌ ํด๋ฆญํ•œ ํƒ€๊ฒŸ์ด ํ•ด๋‹น ์—˜๋ฆฌ๋จผํŠธ์ธ์ง€ ์ฒดํฌํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์‰ฝ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

 

 

2. ์ˆœ์„œ

1. ๊ฐ€์žฅ ๋จผ์ €, bind ๋ฅผ ์ด์šฉํ•ด์„œ ์ฒ˜์Œ ์—˜๋ฆฌ๋จผํŠธ์— ๋ฐ”์ธ๋”ฉ ๋  ๋•Œ ์‹คํ–‰ํ•  ๊ฒƒ์„ ์„ ์–ธํ•ด ์ค€๋‹ค.

{
	bind: function (el, binding, vnode) {
    	// ...
	},
}

 

2. ์šฐ๋ฆฌ๋Š” ๋””๋ ‰ํ‹ฐ๋ธŒ๋ฅผ ๊ฐ–๋Š” ์—˜๋ฆฌ๋จผํŠธ ์™ธ์˜ ๋ถ€๋ถ„์— ์ด๋ฒคํŠธ๋ฅผ ๊ฑธ์–ด์ค„ ๊ฒƒ์ด๋ฏ€๋กœ

๋ฐ”๋””์— ํด๋ฆญ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ์—ฐ๊ฒฐํ•ด์„œ ๋ชจ๋“  ํด๋ฆญ์„ ๊ฐ์ง€ํ•˜๋„๋ก ํ•œ๋‹ค.

{
	bind: function (el, binding, vnode) {
		document.body.addEventListener('click', [์‹คํ–‰ํ• _ํ•จ์ˆ˜]);
	},
}

 

3. ๊ทธ ๋‹ค์Œ, ํด๋ฆญ์ด๋ฒคํŠธ ํƒ€๊ฒŸ์ด ๋””๋ ‰ํ‹ฐ๋ธŒ์— ์—ฐ๋™๋œ ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ์— ์›ํ•˜๋Š” ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋„๋ก ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๋ฉด ๋œ๋‹ค. 

 

{
	bind: function (el, binding, vnode) {
		el.eventClickOutside = function (event) {
			if (!(el == event.target || el.contains(event.target))) {
				//  ... do something ...
			}
		};
	},
}

์ „์ฒด ์ฝ”๋“œ

{
	bind: function (el, binding, vnode) {
		// create event
		el.eventClickOutside = function (event) {
			// when target is not element or is not element childs
			if (!(el == event.target || el.contains(event.target))) {
				//  ... do something ...
			}
		};

		// event binding
		document.body.addEventListener('click', el.eventClickOutside);
	},

	unbind: function (el) {
		document.body.removeEventListener('click', el.eventClickOutside);
	},
}

 


3. ์‹คํ–‰ ์ฝ”๋“œ(์˜ˆ์‹œ)

์™„๋ฃŒ ํ™”๋ฉด

// example.vue

<template>
  <div id="app">
    <button @click.stop="openMenu">open menu</button>
    
    <div id="menu" v-show="show" v-click-outside:openMenu="false">
      <a herf="#">1. Apple</a>
      <a herf="#">2. Banana</a>
      <a herf="#">3. Carrot</a>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      show: false,
    };
  },
  directives: {
    'click-outside': {
        bind: function (el, binding, vnode) {
          // create event
          el.eventClickOutside = function (event) {
            // when target is not element or is not element childs
            if (!(el == event.target || el.contains(event.target))) {
              // call function
              vnode.context[binding.arg](binding.value);
            }
          };

          // event binding
          document.body.addEventListener('click', el.eventClickOutside);
        },

        unbind: function (el) {
          document.body.removeEventListener('click', el.eventClickOutside);
        },
      },
  },
  methods: {
    openMenu(value) {
      if (typeof value === 'boolean')  this.show = value;
      else {
        this.show = !this.show;
      }
    }
  }
};
</script>

<style>
  button {
    background-color: #334867;
    color: white;
    border: 1px solid #334867;
    border-radius: 5px;
    padding: 4px 10px;
    font-size: 20px;
  }
  
  #menu {
    background-color: skyblue;
    width: fit-content;
    margin-top: 5px;
    padding: 4px 28px;
    
    display: flex;
    flex-direction: column;
  }
  
  a {
    cursor: pointer;
    font-weight: 800;
    font-size: 14px;
    color: white;
    padding: 4px 0px;
  }
</style>

 

๋ฐ˜์‘ํ˜•