programing

렌더 기능을 사용할 때 Vue 구성 요소가 하위 텍스트 노드를 표시하지 않음

javaba 2022. 7. 27. 23:49
반응형

렌더 기능을 사용할 때 Vue 구성 요소가 하위 텍스트 노드를 표시하지 않음

Vue 2를 사용하여 편집 가능한 컴포넌트를 수행하려고 합니다. Vue 2에서는contenteditable일반 입력을 대체하여 임의의 태그에서 속성을 지정합니다.사용자가 아무것도 제공하지 않을 때 값을 표시하기 위해 플레이스홀더 기능을 부여하고 싶은데 작동하지 않는 것 같습니다.

컴포넌트 및 설정의 현재 값을 감시하고 있습니다.data.isEmpty로.true사용자 콘텐츠가 존재하지 않는 경우.그러면 구성 요소에 자리 표시자 값이 표시되지만 현재 아무것도 표시되지 않습니다.

만약 내가console.log의 결과rendermethod는 플레이스홀더 자노드가 올바르게 인스턴스화 되었음을 나타내지만 어떤 이유로 최종 HTML에는 표시되지 않습니다.

여기 JSFiddle이 있습니다.https://jsfiddle.net/dy27fa8t/

그리고 그것을 선호하는 사람들을 위해 삽입된 단편:

Vue.component('editable-content', {
  props: {
    initial: {
      type: String
    },
    placeholder: {
      type: String,
      required: false
    }
  },
  data() {
    return {
      value: this.initial,
      isEmpty: this.initial === ''
    }
  },
  render: function(createElement) {
    const self = this
    return createElement(
      'div', {
        attrs: {
          contenteditable: true
        },
        on: {
          input: function(event) {
            self.value = event.target.innerHTML
            self.$emit('edited', event.target.value)
          }
        }
      },
      this.isEmpty ? this.placeholder : this.value
    )
  },
  watch: {
    value(to, from) {
      this.isEmpty = to === ''
    }
  }
})

new Vue({
  el: '#app',
  components: [
    'editable-content'
  ]
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.0/vue.min.js"></script>

<div id="app">
  <editable-content initial="Initial value" placeholder="Placeholder" />
</div>

보아하니 렌더링 중contenteditable직관적으로 동작하지 않습니다.대신,innerHTML내용이 비어 있을 때 플레이스 홀더와 직접 연결할 수 있습니다.그럼...keydown(입력 이벤트 전) 내용이 현재 비어 있는 것으로 표시된 경우 자리 표시자를 제거합니다.에서keyup(입력 이벤트 후) div에 아직 콘텐츠가 없는 경우 다시 빈칸으로 표시합니다(Shift 키와 같이 플레이스 홀더를 지우지 않습니다).

실례를 무릅쓰고 만들었다v-model플레이스 홀더와 호환되고 스타일링됩니다.

Vue.component('editable-content', {
  props: {
    value: {
      type: String
    },
    placeholder: {
      type: String,
      required: false
    }
  },
  data() {
    return {
      isEmpty: this.value === ''
    };
  },
  methods: {
    setEmpty() {
      this.$el.innerHTML = `<div contenteditable="false" class="placeholder">${this.placeholder}</div>`;
      this.isEmpty = true;
    },
    clearEmpty() {
      this.$el.innerHTML = '';
      this.isEmpty = false;
    }
  },
  mounted() {
    if (this.$el.innerHTML === '') {
      this.setEmpty();
    }
  },
  watch: {
    value(newValue) {
      if (newValue === '') {
        this.setEmpty();
      }
    }
  },
  render: function(createElement) {
    return createElement(
      'div', {
        attrs: {
          contenteditable: true
        },
        on: {
          keydown: () => {
            if (this.isEmpty) {
              this.clearEmpty();
            }
          },
          input: (event) => {
            this.$emit('input', event.target.textContent);
          },
          keyup: () => {
            if (this.$el.innerHTML === '') {
              this.setEmpty();
            }
          }
        }
      },
      this.value
    )
  }
});

new Vue({
  el: '#app',
  data: {
    startingBlank: '',
    editedValue: 'initial value'
  },
  components: [
    'editable-content'
  ]
})
.placeholder {
  color: rgba(0,0,0, 0.5);
}
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.3.0/vue.min.js"></script>

<div id="app">
  <editable-content v-model="startingBlank" placeholder="Placeholder"></editable-content>
  <editable-content v-model="editedValue" placeholder="Placeholder"></editable-content>
</div>

최종적으로는 JS와 CSS의 혼합 솔루션을 사용하고 있습니다.:empty유사 클래스Vue만의 회피책은 너무 다루기 어려워 보였기 때문에, 이것은 건전한 타협으로 느껴졌습니다.난 심지어 이 모든 것들을 추적할 필요조차 느끼지 못해value더이상.

단일 파일 컴포넌트에서는 범위 지정 CSS를 사용할 수 있기 때문에 CSS는 컴포넌트의 핵심 기능에 필수적이기 때문에 더욱 편리합니다.

Vue.component('editable-content', {
  props: {
    initial: {
      type: String
    },
    placeholder: {
      type: String,
      required: false
    }
  },
  data() {
    return {
      value: this.initial
    }
  },
  render: function(createElement) {
    const self = this
    return createElement(
      'div', {
        attrs: {
          contenteditable: true,
          'data-placeholder': this.placeholder
        },
        on: {
          input: function(event) {
            self.$emit('edited', event.target.value)
          }
        }
      },
      this.value
    )
  }
})

new Vue({
  el: '#app',
  components: [
    'editable-content'
  ]
})
[data-placeholder]:empty::after {
  content: attr(data-placeholder);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.0/vue.min.js"></script>

<div id="app">
  <editable-content initial="Initial value" placeholder="Placeholder" />
</div>

합격하지 못하면initial컴포넌트에 프로포트를 컴포넌트에 추가합니다.따라서 가 정의되어 있지 않은지 확인해야 합니다.

data() {
    return {
      value: this.initial,
      isEmpty: typeof this.initial === 'undefined'
    }
  },

언급URL : https://stackoverflow.com/questions/43720999/vue-component-not-showing-child-text-node-when-using-render-function

반응형