有条件地呈现父元素,保留内部 html



是否有任何内置方法可以有条件地显示父元素?

举例说明:

<a v-show-but-keep-inner="someCondition">
    <span>This is always rendered no matter what</span>
</a
我认为

这是自定义指令的工作。我做了这个作为快速 POC:

Vue.directive('showButKeepInner', {
  bind(el, bindings) {
    bindings.def.wrap = function(el) {
      // Find all next siblings with data-moved and move back into el
      while (el.nextElementSibling && el.nextElementSibling.dataset.moved) {
        el.appendChild(el.nextElementSibling).removeAttribute('data-moved')
      }
      el.hidden = false
    }
    bindings.def.unwrap = function(el) {
      // Move all children of el outside and mark them with data-moved attr
      Array.from(el.children).forEach(child => {
        el.insertAdjacentElement('afterend', child).setAttribute('data-moved', true)
      })
      el.hidden = true
    }
  },
  inserted(el, bindings) {
    bindings.def[bindings.value ? 'wrap' : 'unwrap'](el)
  },
  update(el, bindings) {
    bindings.def[bindings.value ? 'wrap' : 'unwrap'](el)
  }
})
new Vue({
  el: '#app',
  data: {
    someCondition: false
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.min.js"></script>
<div id="app">
  <p>
    <button v-on:click="someCondition = !someCondition">{{ someCondition }}</button>
  </p>
  <a v-show-but-keep-inner="someCondition" href="/">
    <span>This is always rendered no matter what</span>
  </a>
</div>

对于 Vue v3.x,以下内容将起作用:

<!-- `v-fragment` is globally registered -->
<component
  :is="condition ? 'custom-component' : 'v-fragment'"
  custom-component-prop
  ...
>
  ...
</component>
// VFragment.vue
<template>
  <slot></slot>
</template>
<script>
  export default {
    inheritAttrs: false,
  }
</script>

对于 Vue v2.x,解决方法是执行以下操作:

<component
  :is="condition ? 'custom-component' : 'div'"
  custom-component-prop
  ...
>
  ...
</component>

代价是渲染一个额外的元素,如 div 将呈现,因为 Vue v2.x 不支持片段。

我刚刚遇到了同样的问题。

Vue.js核心团队成员LinusBorg使用具有自定义渲染函数的功能组件为这个用例提供了一个很好的解决方案:

Vue.component('with-root', {
  functional: true,
  props: ['show'],
  render(h, ctx) {
    const children = ctx.children.filter(vnode => vnode.tag) // remove unnecessary text nodes
    // console.log(children)
    if (children.length !== 1) {
      console.warn('this component accepts only one root node in its slot')
    }
    if (ctx.props.show) {
      return children[0]
    } else {
      return children[0].children
    }
  }
})
new Vue({
  el: '#app',
  data: {
    show: true
  }
})
<script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
<div id="app">
  <with-root v-bind:show="show">
    <a href="#">
      <span>This is always rendered no matter what</span>
    </a>
  </with-root>
  <br>
  <button @click="show = !show">Toggle</button>
  <pre>{{$data}}</pre>
</div>

他的小提琴:https://jsfiddle.net/Linusborg/w9d8ujn8/

源:https://forum.vuejs.org/t/conditionally-render-parent-element/9324/2

如果有人碰巧正在使用 vue-fragment (https://www.npmjs.com/package/vue-fragment( 库,则以下工作:

<component :is="someCondition ? 'a' : 'fragment'">
   <span>This is always rendered no matter what</span>
</component>

话虽如此,我不建议仅仅使用一个库来执行此操作。但是,如果您已经这样做了,那么它可能很有用。

没有 Vuejs 或其他框架上下文,只有 DOM。如果不删除其子元素,则无法删除 DOM 元素。你可以做的是获取 DOM 元素的子元素,并用父元素或类似的东西替换它们。
使用 Vuejs,您可以将此功能隐藏在指令或组件后面,但我认为这会使您想要实现的目标过于复杂。

如果您希望锚点在某些情况下不可点击,您可以执行类似 v-on:click.prevent="yourCondition && xxx()" .最重要的是,您可以使用css类来隐藏它仍然是锚v-bind:class="{ fakeAnchor: yourCondition}"的事实。

尽管最简单的解决方案可能是复制您的 html。

<a v-show="someCondition">
    <span>This is always rendered no matter what</span>
</a>
<span v-show="!someCondition">This is always rendered no matter what</span>

最佳解决方案取决于您的情况。如果真正的内部内容要大得多,那么复制它可能是不可能的。如果是这种情况,你可以将其封装在另一个 vue 组件中。

也许这种方法可以帮助你(使用"is"(:

<template lang="pug">
  component(is=someCondition?"v-show-but-keep-inner":"my-another-component")
    v-form
      v-layout
        v-flex
          v-btn(@click="doThat")
</template>

这样,父组件会根据"someCondition"而变化,并且子组件对于两个条件都是相同的。

最新更新