【问题标题】:Vue.js Element Ui - trap / lock focus when el-dialog is openVue.js Element Ui - 打开 el-dialog 时捕获/锁定焦点
【发布时间】:2019-02-17 00:43:46
【问题描述】:

如您所见here,当您打开任何对话框示例并开始按 Tab 键时,焦点开始突出显示对话框外部/后面的元素。我想知道 element-ui 是否有一些我没有注意到的东西?

无论如何,现在我正在使用vue-focus-lock,但我希望 element-ui 提供原生的东西,而不是拉一个库来解决这个问题。

【问题讨论】:

    标签: javascript html vue.js element-ui


    【解决方案1】:

    这似乎是一个错误,element-ui 尚未修复。如果你想要一个纯粹的原生解决方案,这里有一个想法:你可以在 Tab 键上监听 keydown 事件。在这种情况下,您可以访问对话框中的最后一个元素 (document.activeElement) 并防止进一步按下制表符。如果这样做,请不要忘记在对话框关闭时删除事件侦听器。希望这会有所帮助。

    【讨论】:

    • 我真的需要一个快速修复而不是执行您建议的操作,因为我正在构建的应用程序中有近 30 个对话框。每个都有不同的表单元素。不过谢谢你的建议。
    • 在这种情况下,明智的做法是创建一个指令并在您需要的任何对话框中使用它。
    【解决方案2】:

    这是我自己的问题的答案:

    首先,我尝试使用vue-focus-lock 插件,它可以工作,但在选择el-checkboxel-radio 等组件时也会出现问题。当el-dialog 的外部/后面内容更多(折叠以下)时,您可以看到问题,然后复选框或单选将不会被选中。

    这里是我的解决方案,我创建了一个组件FocusLock.vue

    <template lang="pug">
      div.dialog-focus-lock
        slot
    </template>
    
    <script>
    export default {
      name: 'focus-lock',
    
      data() {
        return {
          focusableEls: [],
          firstFocusableEl: [],
          lastFocusableEl: [],
          focusedElBeforeOpen: document.activeElement,
        };
      },
    
      methods: {
        handleDialogFocusLock() {
          const selectors = '' +
            'a[href], ' +
            'input:not([disabled]), ' +
            'select:not([disabled]), ' +
            'textarea:not([disabled]), ' +
            'button:not([disabled])';
    
          const getEls = this.$el.querySelectorAll(selectors);
    
          this.focusableEls = Array.prototype.slice.call(getEls);
          [this.firstFocusableEl] = this.focusableEls; // get first array item
          [this.lastFocusableEl] = this.focusableEls.slice(-1); // get last array item
    
          this.$el.addEventListener('keydown', e => this.handleKeyDown(e));
          this.firstFocusableEl.focus();
        },
    
        handleBackwardTab(e) {
          if (document.activeElement === this.firstFocusableEl) {
            e.preventDefault();
            this.lastFocusableEl.focus();
          }
        },
    
        handleForwardTab(e) {
          if (document.activeElement === this.lastFocusableEl) {
            e.preventDefault();
            this.firstFocusableEl.focus();
          }
        },
    
        handleKeyDown(e) {
          const KEY_TAB = 9;
    
          switch (e.keyCode) {
            case KEY_TAB:
              if (this.focusableEls.length === 1) {
                e.preventDefault();
                break;
              }
              if (e.shiftKey) {
                this.handleBackwardTab(e);
              } else {
                this.handleForwardTab(e);
              }
              break;
            default:
              break;
          }
        },
      },
    
      mounted() {
        this.handleDialogFocusLock();
      },
    };
    </script>
    

    我希望该组件在全球范围内可用,因此将其导入到 main.js 中,或者在您的情况下,只需将其导入到您需要的任何位置。

    import FocusLock from '@/components/partials/FocusLock.vue';
    Vue.component('FocusLock', FocusLock);
    

    在我需要的地方使用它们,就像这样:

    <template lang="pug">
      focus-lock
        el-dialog(:visible.sync="dialogVisible")
          el-form(:model="editedItem")
            // form elements goes here
    </template>
    

    得到了HERE的帮助。

    另外,我认为你不应该担心处理this.$el.removeEventListener,这是由 vue.js 处理的,你可以通过在浏览器控制台中粘贴以下代码进行测试,并在 el-dialog 打开并再次运行时运行它当它关闭时。

    Array.from(document.querySelectorAll('*'))
      .reduce(function(pre, dom){
        var clks = getEventListeners(dom).click;
        pre += clks ? clks.length || 0 : 0;
        return pre
      }, 0)
    

    【讨论】:

      猜你喜欢
      • 2018-12-05
      • 1970-01-01
      • 1970-01-01
      • 2020-11-15
      • 2018-06-01
      • 1970-01-01
      • 2019-01-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多