Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/vue.js/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 自定义Vue下拉列表保持焦点_Javascript_Vue.js_Vuejs2_Frontend - Fatal编程技术网

Javascript 自定义Vue下拉列表保持焦点

Javascript 自定义Vue下拉列表保持焦点,javascript,vue.js,vuejs2,frontend,Javascript,Vue.js,Vuejs2,Frontend,我试图在这里找到解决方案,但没有找到,于是决定写一个问题 因此,我尝试在Vue中构建一个简单的下拉菜单组件,该组件具有切换按钮,用户可以自由单击并在项目周围设置选项卡,但一旦焦点离开该组件,菜单就会崩溃 现在,我使用@blur和@focus事件保持焦点,但是切换按钮有问题。如果我将相同的侦听器附加到它,那么单击它会显示并立即隐藏菜单,因此您必须再次单击以展开它 下面是演示问题的示例 但是,如果我删除了侦听器,那么在焦点位于组件内部之后单击按钮是有问题的。 我猜我的方法是错误的,所以这里是预期的行

我试图在这里找到解决方案,但没有找到,于是决定写一个问题

因此,我尝试在Vue中构建一个简单的下拉菜单组件,该组件具有切换按钮,用户可以自由单击并在项目周围设置选项卡,但一旦焦点离开该组件,菜单就会崩溃

现在,我使用
@blur
@focus
事件保持焦点,但是
切换按钮有问题。如果我将相同的侦听器附加到它,那么单击它会显示并立即隐藏菜单,因此您必须再次单击以展开它

下面是演示问题的示例

但是,如果我删除了侦听器,那么在焦点位于组件内部之后单击按钮是有问题的。 我猜我的方法是错误的,所以这里是预期的行为:

  • 切换按钮就是一个切换按钮。单击时应折叠/展开列表
  • 只有在列表关闭时单击
    切换
    按钮,才能展开列表
  • 当列表展开时,单击
    切换
    按钮或将焦点从列表中调出,可以折叠列表。这包括将焦点放在按钮上(即,单击切换按钮展开列表,然后单击外部某处而不聚焦任何项目)


编辑:多亏了@Sphinx,我成功地让下拉菜单按我的预期工作。这是更新的。

我不确定这是否修复了您试图完成的任务,但您可以尝试使用 @mouseenter和@mouseout

<button 
@click="toggle" 
tabindex="0"
@mouseenter="itemFocus"
@mouseout="itemBlur"
>
Toogle menu

图格菜单


问题是:

我大约有40%的把握我理解这个问题

根据你的描述,这个按钮似乎不应该是一个开关,而是一个打开的按钮

模板:

<div id="app">
  <button 
    @click="showMenu" 
    tabindex="0"
    @focus="itemFocus"
    @blur="itemBlur"
    >
    Toogle menu
  </button>
  <ul :class="listClass">
    <li
      v-for="(item, key) in items"
      tabindex="0"
      @focus="itemFocus"
      @blur="itemBlur"
    >{{ item }}</li>
  </ul>
</div>
这将在菜单关闭时打开菜单,但不会关闭它


这些具有多种交互方式的UI类型的诀窍是设置UI元素的状态,并让UI元素反映该状态

所以我做的是:

  • 如果鼠标进入,菜单应打开
  • 如果鼠标离开,菜单应关闭
  • 如果是聚焦的,菜单应该是打开的
  • 如果模糊,菜单应该关闭
因此,我的解决方案如下:

HTML:

<div id="app">
  <button 
    tabindex="0"
    @focus="isMenuOpen = true"
    @blur="isMenuOpen = false"
    @mouseenter="isMenuOpen = true"
    @mouseout="isMenuOpen = false"
    >
    Toogle menu
  </button>
  <ul :class="listClass">
    <li
      v-for="(item, key) in items"
      tabindex="0"
      @focus="isMenuOpen = true"
      @blur="isMenuOpen = false"
      @mouseenter="isMenuOpen = true"
      @mouseout="isMenuOpen = false"
    >{{ item }}</li>
  </ul>
</div>

对于您的情况,正如问题下的评论已经指出的那样,您必须处理许多情况,例如
@focus
@click
将连续触发,
@blur
@blur
将在单击其中任何一个时触发

这不是一个好主意。但是您可以检查,它是一个解决方案,具有
setTimeout
cleartimout
。然后您可能已经看到它延迟了100ms,方法是
setTimeout(()=>{},100)
(我添加了一些日志,您可以打开浏览器控制台来检查工作流程)原因是我们必须等待足够的时间,以确保下一个事件处理程序(如先触发焦点,然后再触发单击)能够及时清除上一个
设置超时
,除非菜单可能先打开,然后再次关闭。(PS:对于一些旧机器,100毫秒可能不够,这取决于当前渲染完成的速度)

一种解决方案

  • 移除
    @focus
    @blur

  • this.showMenu
    为true(已打开)时,添加一个侦听器=
    单击它将在触发时执行的Dom=文档
    this.hide()

  • 然后在
    this.hide()
    中,从Dom=document中删除该侦听器=
    单击

  • 为了防止在单击按钮和菜单时合并菜单,请添加修饰符=stop,它将停止单击事件向上层Dom节点的传播

  • 如果将
    包装为一个
    ,则只需添加修饰符=
    停止
    {
    document.addEventListener('click',this.hide)
    })
    },
    隐藏:函数(){
    this.showMenu=false
    document.removeEventListener('单击',this.hide)
    }
    }
    })
    正文{
    背景:#20262E;
    填充:20px;
    字体系列:Helvetica;
    }
    #应用程序{
    背景:#fff;
    边界半径:4px;
    填充:20px;
    过渡:均为0.2s;
    }
    保险商实验室{
    列表样式:无;
    显示:无;
    }
    李{
    填充物:5px;
    边框:1px实心#000;
    }
    李:悬停{
    光标:指针;
    背景:#aaa;
    }
    .表演{
    显示:块;
    }
    
    这是一个演示:
    图格菜单
    
    
  • {{item}

  • 按钮上同时有一个
    @焦点
    @单击
    ,如果您单击它(如果您以前没有单击过它),这两个按钮都会被触发。您可能只想从按钮中删除
    @focus
    。@Tommos的问题是正确的,但请注意它依赖于浏览器。在某些浏览器上,当您单击按钮时,浏览器会在
    单击
    事件之前触发
    焦点
    事件。这就是你所看到的行为的原因。
    focus
    事件打开菜单,然后单击
    事件将其切换,从而将其关闭。当您第二次单击按钮时,不会出现
    focus
    事件,因为该按钮在上一次单击时已具有焦点。@Tommos谢谢,我知道为什么会发生这种情况。但是,如果删除
    @focus
    处理程序,则在单击任何列表项后,单击
    切换
    按钮无法折叠列表。几乎。但我希望能够在列表打开时单击切换按钮来折叠列表。谢谢你的帮助,非常感谢。我记得用
    d的方法
    
    <div id="app">
      <button 
        tabindex="0"
        @focus="isMenuOpen = true"
        @blur="isMenuOpen = false"
        @mouseenter="isMenuOpen = true"
        @mouseout="isMenuOpen = false"
        >
        Toogle menu
      </button>
      <ul :class="listClass">
        <li
          v-for="(item, key) in items"
          tabindex="0"
          @focus="isMenuOpen = true"
          @blur="isMenuOpen = false"
          @mouseenter="isMenuOpen = true"
          @mouseout="isMenuOpen = false"
        >{{ item }}</li>
      </ul>
    </div>
    
    // simplified for clarity
    new Vue({
      el: "#app",
      data: {
        showMenu: false,
        items: [ 'Option 1', 'Option 2', 'Option 3', 'Option 4' ],
        isMenuOpen: false,
      },
      computed: {
        listClass() { // you can omit the `: function` in new ES standard
          return this.isMenuOpen ? 'show' : ''; //ternary op saves lines
      },
      methods: {
        // not needed, as it's done in HTML
        // toggle: function(){
        //  this.showMenu = !this.showMenu
        //},
        /*
        we no longer need these methods:
        itemFocus: function() {
            var self = this;
          Vue.nextTick(function() {
            if(!self.showMenu) {
                self.showMenu = true;
            }
          });
        },
        itemBlur: function() {
            var self = this;
                Vue.nextTick(function() {
            if(self.showMenu) {
                self.showMenu = false;
            }
          });
        }
        */
      }
    })