vuejs:div元素上的@ keyup.esc不起作用

时间:2018-03-01 04:32:25

标签: vue.js vuejs2 vue-events

我期待'关闭'事件在我被解雇时被解雇 单击ESC按钮处于“阴影模式”div,但它没有发生

vue 2.5.13,任何想法为什么?

<template>
  <div class="shadow-modal"
     @keyup.esc="$emit('close')">
    <transition name="modal">
      <div class="modal-mask">
        <div class="modal-wrapper">
          <div class="modal-container">
            <div class="modal-header">
              <slot name="header">
                default header
              </slot>
            </div>
            <div class="modal-body">
              <slot name="body">
                default body
              </slot>
            </div>
            <div class="modal-footer">
              <slot name="footer">
                <a href="#"
                   class="btn btn--diagonal btn--blue"
                   @click="$emit('close')">Cancel</a>
              </slot>
            </div>
          </div>
        </div>
      </div>
    </transition>
  </div>
</template>

6 个答案:

答案 0 :(得分:17)

虽然您尝试绑定keyborad事件不是输入元素,但除非您定义tabindex,否则它们将无法工作:

<div class="shadow-modal" @keyup.esc="$emit('close')" tabindex="0">

以下是参考资料:https://www.w3.org/WAI/GL/WCAG20/WD-WCAG20-TECHS/SCR29.html

答案 1 :(得分:3)

(除了之前的2个答案。)

你没有用Vue处理所有事件。

这是另一种方式

export default {
  created() {
    document.onkeydown = evt => {
      evt = evt || window.event;
      if (evt.keyCode == 27) {
        this.$emit("close");
      }
    };
  }
};

答案 2 :(得分:1)

虽然DmitrySemenov解决方案对我有用,但当页面上有多个模态时,它不是最佳解决方案。我尝试了一下,发现它触发了每个模式的关闭事件。

我认为最好的方法是在显示模态时注册“ keyup”事件,并在隐藏后注销它。它给您带来了好处,因为仅在需要时才注册事件。为此,您需要为“ show”属性添加一个观察者:

  props: {
    show: {
      type: Boolean,
      default: false
    }
  },
  watch: {
    show() {   
      if (this.show === false) {
        window.removeEventListener("keyup", this.onEscapeKeyUp);
      } else {
        window.addEventListener("keyup", this.onEscapeKeyUp);
      }
    }
  },
  methods: {
    onEscapeKeyUp(event) {
      if (event.which === 27) {
        this.$emit("close");
      }
    }
  }

模态应具有v-if="show",以控制模态的可见性:

<div class="modal-mask" v-if="show" @click="$emit('close');">

完整解决方案代码(您可以在codesandbox.io上看到它):

Modal.vue

<template>
  <transition name="modal">
    <div class="modal-mask" v-if="show" @click="$emit('close');">
      <div class="modal-wrapper" @click.stop>
        <div class="modal-container">
          <div class="modal-header"><slot name="header"></slot></div>
          <div class="modal-body"><slot name="body"></slot></div>
          <div class="modal-footer">
            <slot name="footer">
              <div class="buttons">
                <a class="button" href="#" @click.prevent="$emit('close');">
                  OK
                </a>
              </div>
            </slot>
          </div>
        </div>
      </div>
    </div>
  </transition>
</template>

<script>
export default {
  name: "Modal",
  props: {
    show: {
      type: Boolean,
      default: false
    }
  },
  watch: {
    show() {
      const body = document.querySelector("body");

      if (this.show === false && body.style.overflow === "hidden") {
        body.style.overflow = "";
        window.removeEventListener("keyup", this.onEscapeKeyUp);
      } else {
        body.style.overflow = "hidden";
        window.addEventListener("keyup", this.onEscapeKeyUp);
      }
    }
  },
  methods: {
    onEscapeKeyUp(event) {
      if (event.which === 27) {
        console.log("close event");
        this.$emit("close");
      }
    }
  }
};
</script>

<style lang="scss" scoped>
.modal-mask {
  position: fixed;
  z-index: 1100;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  overflow: auto;
  transition: opacity 0.3s ease;
  display: flex;
  justify-content: center;
  align-items: center;
}

.modal-wrapper {
  max-width: 980px;
  width: 100%;
}

.modal-container {
  padding: 1.5em 2em;
  background-color: white;
  border-radius: 2px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
  transition: all 0.3s ease;
}

.wrapper {
  max-width: 980px;
}

.modal-body {
  margin: 1em 0;
}

.modal-enter {
  opacity: 0;
}

.modal-leave-active {
  opacity: 0;
}

.modal-enter .modal-container,
.modal-leave-active .modal-container {
  -webkit-transform: scale(1.1);
  transform: scale(1.1);
}
</style>

App.vue

<template>
  <div id="app">
    <button @click="show1 = true;">Show first modal</button>
    <button @click="show2 = true;">Show second modal</button>

    <Modal :show="show1" @close="show1 = false;">
      <div slot="header"><h1>First Modal</h1></div>
      <div slot="body">
        Lorem ipsum dolor sit amet consectetur, adipisicing elit. Rem beatae
        repellat dolores deleniti illum voluptatem facilis neque ut placeat,
        eius iusto tempore! Totam omnis non tempore perferendis expedita numquam
        neque!
      </div>
    </Modal>

    <Modal :show="show2" @close="show2 = false;">
      <div slot="header"><h1>Second Modal</h1></div>
      <div slot="body">
        Lorem ipsum dolor sit amet consectetur, adipisicing elit. Rem beatae
        repellat dolores deleniti illum voluptatem facilis neque ut placeat,
        eius iusto tempore! Totam omnis non tempore perferendis expedita numquam
        neque!
      </div>
    </Modal>
  </div>
</template>

<script>
import Modal from "./components/Modal";

export default {
  name: "App",
  components: {
    Modal
  },
  data() {
    return {
      show1: false,
      show2: false
    };
  }
};
</script>

答案 3 :(得分:0)

我的替代实施

<template>
  <div class="shadow-modal"
     @keyup.esc="$emit('close')">
    <transition name="modal">
      <div class="modal-mask">
        <div class="modal-wrapper">
          <div class="modal-container">
            <div class="modal-header">
              <slot name="header">
                default header
              </slot>
            </div>
            <div class="modal-body">
              <slot name="body">
                default body
              </slot>
            </div>
            <div class="modal-footer">
              <slot name="footer">
                <a href="#"
                   class="btn btn--diagonal btn--blue"
                   @click="$emit('close')">Cancel</a>
              </slot>
            </div>
          </div>
        </div>
      </div>
    </transition>
  </div>
</template>

<script>
export default {
  beforeMount() {
    window.addEventListener('keyup', this.onEscapeKeyUp);
  },
  beforeDestroy () {
    window.removeEventListener('keyup', this.onEscapeKeyUp)
  },
  methods: {
    onEscapeKeyUp (event) {
      if (event.which === 27) {
        this.$emit('close');
      }
    },
  },
};
</script>

答案 4 :(得分:0)

如果需要关闭模式窗口,则必须遵守几个条件。

  1. 在模式窗口的标签中:
<div class="modal-content" ref="modal" tabindex="0" @keyup.esc="$emit('close')">
  1. 在生命周期挂钩中mount():
mounted() {
   this.$refs.modal.focus()
}

答案 5 :(得分:-1)

无法从div或其他元素生成Key事件。为了从div获取关键事件,您需要在div元素中使用<Input type="text"></Input>