Как условно добавить элемент в компонент Vue в области видимости? - PullRequest
0 голосов
/ 31 марта 2020

Я пытаюсь создать Компонент для заголовков, который можно редактировать, когда они дважды щелкают. Компонент принимает h-тег, который должен использоваться, и заголовок как реквизит и должен создавать обычный h-тег, который после двойного щелчка превращается в поле ввода. Это уже работает, если на странице есть только один заголовок, однако, если на одной странице используется несколько Компонентов, он ломается, так как Компонент неправильно определен. Но я не могу понять, как. Вот код:

<template>
  <div class="edit-on-click">
    <input
      :class="sizeClass"
      type="text"
      v-if="edit"
      v-model="editedTitle"
      @blur="finishEdit"
      @keyup.enter="finishEdit"
      v-focus="true"
    />
    <span v-show="!edit" @dblclick.prevent="edit = true"></span>
  </div>
</template>

Смонтированный крюк, который я не могу понять, как охватить:

  mounted() {
    let node = document.createElement(this.size); // Takes h-tag (h1, h2 etc.)
    let titleText = document.createTextNode(this.finalTitle); // Takes title

    node.appendChild(titleText);
    node.classList.add("editable-title");

    // This breaks the code once there are multiple components in the document
    document.getElementsByTagName("span")[0].appendChild(node);
  },

Как я могу эффективно охватить это? Заранее большое спасибо!

1 Ответ

1 голос
/ 31 марта 2020

Что ж, с Vue вы, возможно, захотите избегать создания элементов DOM "родным" способом, когда это возможно, поскольку вы можете столкнуться с состоянием гонки, когда Vue не знает о существовании этих элементов, которые вы, вероятно, Я хочу, чтобы в какой-то момент времени вы реагировали (в вашем случае это двойной щелчок <span>).

Вместо этого вы могли бы, возможно, динамически «переключаться» между этими разными заголовками с помощью этого <component> и v-bind:is проп. Рассмотрим следующий пример:

Vue.component('EditableHeading', {
  template: '#editable-heading',

  props: {
    size: {
      type: String,
      default: 'h1'
    },
    value: {
      type: String,
      required: true
    }
  },

  data() {
    return {
      editing: false
    }
  },

  methods: {
    confirm(e) {
      this.$emit('input', e.target.value);
      this.close();
    },
    start() {
      this.editing = true;
      
      this.$nextTick(() => {
        this.$el.querySelector('input[type="text"]').select();
      });
    },
    close() {
      this.editing = false;
    }
  }
})

new Vue({
  el: '#app',

  data: () => ({
    titleList: [],
    text: 'New Title',
    size: 'h3'
  }),

  methods: {
    addNewTitle() {
      this.titleList.push({
        text: this.text,
        size: this.size
      });
    }
  }
})
.edit-on-click {
  user-select: none;
}

.heading-size {
  margin-top: 1rem;
  width: 24px;
}

p.info {
  background-color: beige;
  border: 1px solid orange;
  color: brown;
  padding: 4px 5px;
  margin-top: 2rem;
}
<script src="https://vuejs.org/js/vue.min.js"></script>

<div id="app">
  <editable-heading 
    v-for="(title, index) of titleList" :key="index" 
    v-model="title.text" 
    :size="title.size">
  </editable-heading>

  <div>
    <label>
      Heading size: 
      <input v-model="size" class="heading-size" />
    </label>
  </div>
  <div>
    <label>
      Title: 
      <input v-model="text" />
    </label>
  </div>
  <div>
    <button @click="addNewTitle()">Add new title</button>
  </div>

  <p class="info">
    [double-click]: Edit <br />
    [enter]: Confirm <br />
    [esc/mouseleave]: Cancel
  </p>
</div>

<script id="editable-heading" type="text/x-template">
  <div class="edit-on-click">
    <input 
      type="text" 
      v-if="editing" 
      :value="value" 
      @blur="close" 
      @keydown.enter="confirm" 
      @keydown.esc="close" />

    <component :is="size" v-else @dblclick="start">{{value}}</component>
  </div>
</script>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...