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

Vue.js 有条件地呈现父元素,保留内部html,vue.js,vuejs2,Vue.js,Vuejs2,是否有任何内置方法可以有条件地显示父元素 举例说明: <a v-show-but-keep-inner="someCondition"> <span>This is always rendered no matter what</span> </a 无论发生什么情况,这都会被渲染 没有Vuejs或其他框架上下文,只有DOM。 如果不删除DOM元素的子元素,则无法删除该元素。 您可以做的是获取DOM元素的子元素并用父元素或类似的东西替换它们。

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

举例说明:

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

无论发生什么情况,这都会被渲染

没有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组件中。

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

Vue.directive('showButKeepInner'{
绑定(el,绑定){
bindings.def.wrap=函数(el){
//查找数据已移动的所有下一个同级并移回el
while(el.nextElementSibling&&el.nextElementSibling.dataset.moved){
el.appendChild(el.nextElementSibling).removeAttribute('data-moved'))
}
el.hidden=false
}
bindings.def.unwrap=函数(el){
//将el的所有子项移到外部,并用数据移动属性标记它们
Array.from(el.children).forEach(child=>{
el.insertAdjacentElement('afterend',child).setAttribute('data-moved',true)
})
el.hidden=true
}
},
插入(el,绑定){
bindings.def[bindings.value?'wrap':'unwrap'](el)
},
更新(el,绑定){
bindings.def[bindings.value?'wrap':'unwrap'](el)
}
})
新Vue({
el:“#应用程序”,
数据:{
某些条件:假
}
})


{{someCondition}}


我也遇到了同样的问题

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

Vue.component('with-root'{
功能性:对,
道具:['show'],
渲染(h,ctx){
const children=ctx.children.filter(vnode=>vnode.tag)//删除不必要的文本节点
console.log(子级)
if(children.length!==1){
console.warn('此组件在其插槽中只接受一个根节点')
}
如果(ctx.props.show){
返回子项[0]
}否则{
返回子项[0]。子项
}
}
})
新Vue({
el:“#应用程序”,
数据:{
秀:真的
}
})


切换 {{$data}}
也许这种方法可以帮助您(使用“is”):


组件(is=someCondition?“v-show-but-keep-inner”:“我的另一个组件”)
v型
v型布局
v-flex
v-btn(@click=“doThat”)

这样,父组件会根据“someCondition”的不同而发生变化,而子组件在这两种情况下都是相同的。

如果有人碰巧正在使用vue fragment()库,则以下操作有效:


无论发生什么情况,这都会被渲染

也就是说,我不建议只使用一个库来实现这一点。但是,如果您已经这样做了,它可能会很有用。

对于Vue v3.x,以下功能将起作用:


...
//VFragment.vue
导出默认值{
继承属性:false,
}
对于Vue v2.x,解决方法是:


...
//VDiv.vue
导出默认值{
继承属性:false,
}

折衷的办法是,由于Vue v2.x不支持fragment,因此将呈现一个额外的元素,如
div

看看插槽是否可以帮助您实现所需的功能。这回答了你的问题吗?如果复制的话,它足够大,会弄得一团糟。当它被包装在
元素中时,它也有不同的样式,在这一点上进行更改可能会更加复杂。这样的指令会是什么样子?也许你最好使用render函数。在这种情况下,您可以在一个变量中捕获子变量,并使用js使用锚将其包装起来。指令也会很混乱。尝试将复杂的html包装到另一个组件中。这是一个很好的指令,但它不考虑包含任何文本节点的顶部元素。它只移动元素,因为它使用了
el.children
。我认为使用
el.childNode
也应该考虑文本节点。
<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>
<component :is="someCondition ? 'a' : 'fragment'">
   <span>This is always rendered no matter what</span>
</component>