首页 > 解决方案 > vuetify v-menu 在打开第三方库的表单点击事件后立即关闭

问题描述

我正在尝试将 cytoscape 集成到 vuetify SPA 中。将图形渲染到 v-card-element 已经可以了。同样有效的是单击处理程序,当单击图表中的注释时使用 vue 路由器导航到不同的页面。但是,当我用打开上下文菜单(v-menu)的命令替换 router-push 时,上下文菜单永远不会出现。如果从 vue 页面的不同位置触发,我已经仔细检查过是否会出现相同的上下文菜单。

打开上下文菜单是通过在 vue 中注册的一个简单的布尔值实现的,该值绑定到 v-menu 的 v-model。通过将值设置为 true 上下文菜单应该打开。

但是,当在 cytoscape on-click 处理程序中将该值设置为 true 时,这种情况永远不会发生。

代码部分复制自 vuetify 示例。

这是模板:

<template>
  <v-container fluid>

    <v-layout row justify-center align-center>
      <v-flex xs10>
        <v-card>
            <v-toolbar>
              <v-btn @click="contextMenuOpen=true">Show Contextmenu</v-btn>
            </v-toolbar> 
          <div ref="cytoscape" class="cytoscape" style="width: 100%; height: 80vh;" id="cytopane"></div>
        </v-card>
      </v-flex>
    </v-layout>

    <v-menu v-model="contextMenuOpen" :position-x="x" :position-y="y" absolute offset-y>
      <v-list>
        <v-list-tile @click="doSomething()">
          <v-list-tile-title>Do Somethin</v-list-tile-title>
        </v-list-tile>
        <v-list-tile @click="doSomethingElse()">
          <v-list-tile-title>Do Someting</v-list-tile-title>
        </v-list-tile>
      </v-list>
    </v-menu>

  </v-container>
</template>

和js部分:

. . .
data: function () {
  return {
    contextMenuOpen: false,
    style: [
      {
        selector: 'node',
        style: {
          . . .
        }
      }, {
        selector: 'edge',
        style: {
          . . .
        }
      }
    ],
    layout: {
      name: 'cose-bilkent'
    }
  }
},
methods: {
  showContextMenu: function (x, y) {
    let vs = this
    this.contextMenuOpen = false
    this.x = x
    this.y = y
    this.$nextTick(() => {
      this.contextMenuOpen = true
    })
  },
  renderView: function (data) {
    let vs = this
    cytoscape.use(coseBilkent)
    let cy = cytoscape({
      container: document.getElementById(this.$refs['cytoscape'].id),
      elements: data,
      style: this.style,
      layout: this.layout
    })
    cy.on('click', 'node', function (evt) {
      vs.showContextMenu(evt.originalEvent.clientX, evt.originalEvent.clientY)
    })
  },
},
mounted() {
  . . . 
  this.renderView()
}

通过单击工具栏中的按钮,我输入用于测试上下文菜单会出现。我觉得奇怪的是,如果布尔值 'contextMenuOpen' 绑定到菜单的 v-model 并且将从点击处理程序设置为 true,则该值将立即设置回 false。如果我从 v-menu 中的 v-model 绑定中删除该变量,则该值将保持为真。

这是线程问题吗?我做错了什么?

更新:我准备了一个 js-fiddle 来重现我遇到的问题: https ://jsfiddle.net/gofrm76/0tkjp3rs/63/

UPDATE2:通过在 contextMenuOpen 上创建一个监视并在此监视内设置一个断点,我能够使用堆栈跟踪至少一点点跟踪问题的根源。事实上,菜单会出现一毫秒并立即关闭,因为在菜单中执行了点击外部处理程序。这通常会在出现上下文菜单并且我再次单击屏幕上的其他位置以再次关闭它时发生。在 cytoscape on-click 事件的情况下,我显然错过了某种事件传播停止,因为单击节点会导致打开菜单并立即触发 click-outside 处理程序。

UPDATE3:我在 vuetify v-menu 上找到了一个配置选项,该选项禁用通过单击外部某处关闭上下文菜单的功能。通过将另一个 bool 变量绑定到最初为 false 并在短暂延迟后设置为 true 的“单击时关闭”,我绕过了对上述第二个事件的处理,菜单保持打开状态。延迟之后,单击时关闭将设置回默认的“真”,用户可以通过单击菜单外部来关闭菜单。

所以对我来说,这是我现在可以使用的解决方案。它还表明更新 2 关于这两个事件的假设是正确的,它还表明原始帖子具有误导性/不正确:v-menu 按预期工作,但实际问题是“第三个事件”发出了两个事件党库”/细胞景观。

这给我留下了一个问题:我怎样才能防止第二次事件发生?

标签: javascriptvue.jsvuetify.jscytoscape.js

解决方案


尽管这个问题是不久前提出的,但我最近遇到了同样的问题,并希望帮助那些面临类似问题的人。因此,我意识到带有 absolute 属性的 vuetify 菜单仅适用于 @contextmenu,而不能按预期使用 @click。原因是菜单的工作方式是检查菜单外的单击以关闭菜单。因此,当您单击另一个按钮时,该按钮会发出一个尝试打开菜单的事件,但同时检测到菜单外的单击会导致菜单立即关闭。上下文菜单不会出现此问题,因为没有单击被检测到。因此,我处理此问题的方式是延迟单击菜单的打开,以便在检测到菜单外的单击时触发关闭事件后触发。一个 setTimeout 将解决这个问题。


推荐阅读