Vue js Vuetify自定义组件未根据显示断点渲染

Vue js Vuetify custom component not rendered based on the display breakpoint

我有一个自定义组件,它基本上是一个具有特定样式的 v-btn 组件。当我在具有基于显示断点的条件的 v-menu 激活器中使用它时,自定义组件不会显示在屏幕上。但是如果我使用常规的 v-btn,按钮会根据显示断点正确显示。我在这里做错了什么?

https://codepen.io/jgunawan-dc/pen/XWzJqRy?editors=1010

<div id="app">
  <v-app id="inspire">
    <div class="text-center">
      <v-menu offset-y>
        <template v-slot:activator="{ on, attrs }">
          <global-custom-button
            v-if="$vuetify.breakpoint.mdAndDown"
            v-bind="attrs"
            v-on="on"
          >
            Show on medium and lower
          </global-custom-button>
          <v-btn v-else
            color="primary"
            dark
            v-bind="attrs"
            v-on="on"
          >
            Dropdown
          </v-btn>
        </template>
        <v-list>
          <v-list-item
            v-for="(item, index) in items"
            :key="index"
          >
            <v-list-item-title>{{ item.title }}</v-list-item-title>
          </v-list-item>
        </v-list>
      </v-menu>
    </div>
  </v-app>
</div>
Vue.component('global-custom-button', {
  template: '<v-btn outlined color="info" @click="$emit(\'click\', $event)"><slot></slot></v-btn>'
});
new Vue({
  el: '#app',
  vuetify: new Vuetify(),
  data: () => ({
    items: [
      { title: 'Click Me' },
      { title: 'Click Me' },
      { title: 'Click Me' },
      { title: 'Click Me 2' },
    ],
  }),
})

上述情况产生了两个错误:

错误信息 1:

[Vue warn]: Error in nextTick: "NotFoundError: Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node."

错误信息 2:

DOMException: Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node.

当 Vue 尝试在另一个元素之前插入一个元素,但该元素不再存在于 DOM 中时,就会出现这种情况。

在您的情况下,将 $vuetify.breakpoint.mdAndDown 从 true 更改为 false 或 vice-versa 会清理 global-custom-button 组件或下拉列表 v-btn.

一种可能的解决方法是使用 v-show 而不是 v-if

注意事项:

Note that v-show doesn’t support the element, nor does it work with v-else.

所以这个建议可行(您可以更改以满足您的需要):

      <global-custom-button
        v-show="$vuetify.breakpoint.mdAndDown"
        v-bind="attrs"
        v-on="on"
      >
        Show on medium and lower
      </global-custom-button>
      <v-btn v-show="!$vuetify.breakpoint.mdAndDown"
        color="primary"
        dark
        v-bind="attrs"
        v-on="on"
      >
        Dropdown
      </v-btn>

编辑:

This works 没有 v-ifv-show

如@Rotiken 所说,要快速修复,请使用 v-show

作为另一种解决方案,您还可以注册两个全局组件并 show/hide 使用额外的 condition prop:

<v-menu offset-y>
  <template v-slot:activator="{ on, attrs }">
    <global-custom-button
      :condition="$vuetify.breakpoint.mdAndDown"
      v-bind="attrs"
      v-on="on"      
    >
      Show on medium and lower
    </global-custom-button>
          
    <global-custom-button-2
      :condition="!$vuetify.breakpoint.mdAndDown"
      v-bind="attrs"
      v-on="on"
    >
      Dropdown
    </global-custom-button-2>
  </template>
  ...
</v-menu>

...

Vue.component('global-custom-button', {
  template: '<v-btn v-if="condition" outlined color="info" @click="$emit(\'click\', $event)"><slot></slot></v-btn>',
  props: ['condition']
});

Vue.component('global-custom-button-2', {
  template: '<v-btn v-if="condition" color="primary" dark @click="$emit(\'click\', $event)"><slot></slot></v-btn>',
  props: ['condition']
});
...

根据 this CodePen,这也有效。


为什么 会发生这种情况以及为什么 v-show 使用相同的模板可以正常工作:我无法给出确切的答案,但有一些假设。

Vue.js docs 表示 v-if 从 DOM 中删除对象,而 v-show 在 CSS 中更改其显示状态,但在 [=47] 中保留它=].

由于您在 vuetify v-menu 组件中使用 v-if,也许该组件有一些更新 v-slot:activator 内容的方法可能会发生冲突(并且不会同时执行) ) 使用 v-if 和 vuetify 显示断点进行条件渲染。

如果您熟悉 TypeScript,可以查看 v-menu sources or into activatable mixin sources。也许在这里你会找到这种行为的真正原因。

如果您只想避免此类问题,请在此类情况下使用v-show