我试图在这里找到解决方案,但是找不到,并决定写一个问题。
因此,我试图在Vue中构建一个简单的下拉菜单组件,该组件具有切换按钮,用户可以自由单击并在项目周围进行制表,但是只要焦点离开组件,菜单就会折叠。
现在,我通过@blur
和@focus
事件来保持焦点,但是我对Toggle
按钮有疑问。如果我在其上附加了相同的侦听器,则单击它会显示并立即隐藏菜单,因此您必须再次单击以展开它。
这里是fiddle,说明了问题。
但是,如果我删除了侦听器,则在焦点位于组件内部之后单击按钮是有问题的。 我想我的方法是错误的,所以这是预期的行为:
Toggle
按钮就是这样-一个切换按钮。它应该折叠/扩展点击列表Toggle
按钮才能展开列表Toggle
按钮或将其聚焦在列表上,可以折叠该列表。这包括将重点放在按钮上(即,单击切换按钮以展开列表,然后单击外部某处而不聚焦任何项目)。编辑:感谢@Sphinx,我设法使下拉菜单按预期运行。这是更新后的fiddle。
答案 0 :(得分:0)
我不确定这是否可以解决您要完成的任务,但是您可以尝试使用 @mouseenter和@mouseout
<button
@click="toggle"
tabindex="0"
@mouseenter="itemFocus"
@mouseout="itemBlur"
>
Toogle menu
答案 1 :(得分:0)
我大概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>
方法:
showMenu: function(){
this.showMenu = true;
},
这将在关闭菜单时打开菜单,但不会将其关闭
答案 2 :(得分:0)
使用多种交互方式的这些类型的UI的窍门是设置UI元素的状态,并使UI元素反映该状态。
所以我是这样做的:
这是我的解决方案:https://jsfiddle.net/jaiko86/e0vtf2k1/1/
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>
JS:
// 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;
}
});
}
*/
}
})
答案 3 :(得分:0)
对于您的情况,正如已经在问题下所指出的那样,您必须处理许多情况,例如@focus
和@click
将连续触发,{单击@blur
中的{1}}和<button>
时将触发它们。
这不是一个好主意。但是您可以使用@blur
和<ul></li>
来检查This fiddle,它是一个解决方案。然后您可能已经看到它通过setTimeout
延迟了100毫秒(我添加了一些日志,您可以打开浏览器控制台来检查工作流程)。 原因是我们必须等待足够的时间,以确保下一个事件处理程序(例如先触发焦点,然后再触发单击)可以清除先前的{{1} } 及时,除非菜单可能先打开,然后再关闭。 (PS:对于某些旧机器,100ms可能不够,这取决于完成当前渲染的速度)
一种解决方案:
删除clearTimeout
和setTimeout(()=>{}, 100)
当setTimeout
为真(打开)时,为Dom = document添加一个listener = {@focus
,它将在触发时执行@blur
。
然后在this.showMenu
中,从Dom = document中删除该listener = click
。
为防止在单击按钮和菜单时菜单被折叠,请添加modifier = stop,它将停止单击事件向上级Dom节点的传播。
如果将this.hide()
和this.hide()
包装成一个click
,则只需像<button>
那样添加修饰符= <ul>
。
下面是一个演示:
<div>
stop
<template><div @click.stop><button></button<ul>...<ul></div></template>