source

조건부로 부모 요소 렌더링, 내부 html 유지

manycodes 2022. 10. 26. 21:12
반응형

조건부로 부모 요소 렌더링, 내부 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.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-buffix(https://www.npmjs.com/package/vue-fragment) 라이브러리)를 사용하고 있는 경우는, 다음의 조작을 실행할 수 있습니다.

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

그렇다고 해서, 이것을 하기 위해서 한 개의 라이브러리를 사용하는 것은 추천하지 않습니다.하지만 이미 알고 있다면, 유용할 수 있습니다.

Vue v3.x의 경우 다음 기능이 작동합니다.

  <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' : 'v-div'"
    custom-component-prop
    ...
  >
    ...
  </component>
// VDiv.vue
<template>
  <div>
    <slot></slot>
  </div>
</template>

<script>
  export default {
    inheritAttrs: false,
  }
</script>

단점은 다음과 같은 추가 요소가 있다는 것입니다.divVue v2.x는 fragment를 지원하지 않기 때문에 렌더링됩니다.

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'에 따라 변경되며 자녀는 두 조건 모두 동일합니다.

언급URL : https://stackoverflow.com/questions/43293401/conditionally-rendering-parent-element-keep-inner-html

반응형