如何在有条件的Vue组件中有条件地附加元素?

问题描述 投票:0回答:1

我正在尝试为标题创建一个组件,当它们被双击时可以对其进行编辑。组件将应使用的h-tag和标题作为道具,并应产生一个普通的h-tag,一旦双击,它将变为一个输入字段。如果页面上只有一个标题,这已经可以工作,但是,一旦一个页面上使用了多个组件,它就会中断,因为该组件的作用域不正确。但是我不知道怎么做。这是代码:

<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);
  },

我如何有效地确定范围?预先非常感谢!

javascript vue.js dom
1个回答
1
投票

嗯,使用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>
© www.soinside.com 2019 - 2024. All rights reserved.