InfoMenu1-Bad

by Chige12

HTML

<div id="app">
  <div class="containter">
    <p>問題1 メニューが閉じない場合がある</p>
    <msg-comp
      v-for="msg in msgList"
      :msg="msg"
    ></msg-comp>
  </div>
</div>

<script type="text/x-template" id="message">
  <div class="msg">
    <button v-on:click.stop="showInfo = !showInfo">Info {{msg}}</button>
    <info-menu 
          v-if="showInfo"
          v-on:close="showInfo = false">
    </info-menu>
  </div>
</script>

<script type="text/x-template" id="info">
  <div class="info">
    <button>AAA</button>
    <button>BBB</button>
    <button>CCC</button>
  </div>
</script>

CSS

.msg {
  position: relative;
  border: 1px solid blue;
  width: 60px;
  margin: 4px;
  padding: 4px;
  background: #fff;
}

.info {
  position: absolute;
  top: 0;
  left: 72px;
  background: #fff;
  border: 1px solid red;
  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
  padding: 5px;
}

Vue

var listener = {
    methods:{
    listen :function(target, eventType, callback) {
        if (!this._eventRemovers){
        this._eventRemovers = [];
      }
      target.addEventListener(eventType, callback);
      this._eventRemovers.push( {
        remove :function() {
          target.removeEventListener(eventType, callback)
        }
      })
    }
  },
  destroyed:function(){
    if (this._eventRemovers){
      this._eventRemovers.forEach(function(eventRemover){
        eventRemover.remove();
      });
    }
 }
}

Vue.component('info-menu', {
  mixins:[listener],
  template: '#info',
  created:function(){
    this.listen(window, 'click', function(e){
      if (!this.$el.contains(e.target)){
        this.$emit('close');
      }
    }.bind(this));
  }
});

Vue.component('msg-comp', {
  template: '#message',
  props: ['msg'],
  data() {
    return {
      showInfo: false
    }
  }
});

new Vue({
  el: '#app',
  data: {
		msgList: [
      1, 2, 3
    ]
	}
})