web-dev-qa-db-ja.com

Vueに異なるコンポーネントを動的に追加する

Vueを使用して簡単なフォームビルダーを作成します。ここで、ユーザーがメニューのボタンをクリックしてフォームにさまざまなフォームフィールドを追加します。追加するフォームフィールドが1種類だけの場合は、私はこのようなものでそれを行うことができました( https://jsfiddle.net/u6j1uc3u/32/ ):

<div id="app">
  <form-input v-for="field in fields"></form-input>

  <button type="button" v-on:click="addFormElement()">Add Form Element</button>
</div>

<script type="x-template" id="form-input">
  <div>
    <label>Text</label>
    <input type="text" />
  </div>
</script>

そして:

Vue.component('form-input', {
  template: '#form-input'
});

new Vue({
  el: '#app',
  data: {
    fields: [],
    count: 0
  },

  methods: {
    addFormElement: function() {
      this.fields.Push({type: 'text', placeholder: 'Textbox ' + (++this.count)});
    }
  }
})

しかし、フォームフィールドのタイプ(入力、ファイル、選択など)が複数ある場合はどうでしょうか。タイプごとに異なるコンポーネントを作成することを考えていましたが、フォーム要素の単一のリストに複数のタイプのコンポーネントをどのように表示しますか?

fields配列のデータに基づいて、さまざまなタイプの子コンポーネントを持つコンポーネントを作成できますか?

または、私が見逃しているこの状況に対処するためのより良い方法はありますか?私はVueの学習を始めたばかりなので、どんな助けにも感謝します!

8
Chris

OK、それで私は動的要素を調べて、これを一緒にまとめることができました:

Vue.component('form-input', {
  template: '#form-input'
});

Vue.component('form-select', {
  template: '#form-select'
});

Vue.component('form-textarea', {
  template: '#form-textarea'
});

new Vue({
  el: '#app',
  data: {
    fields: [],
    count: 0
  },

  methods: {
    addFormElement: function(type) {
      this.fields.Push({
        'type': type,
        id: this.count++
      });
    }
  }
})
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
<div id="app">
  <component v-for="field in fields" v-bind:is="field.type" :key="field.id"></component>

  <button type="button" v-on:click="addFormElement('form-input')">Add Textbox</button>
  <button type="button" v-on:click="addFormElement('form-select')">Add Select</button>
  <button type="button" v-on:click="addFormElement('form-textarea')">Add Textarea</button>
</div>

<script type="x-template" id="form-input">
  <div>
    <label>Text</label>
    <input type="text" />
  </div>
</script>

<script type="x-template" id="form-select">
  <div>
    <label>Select</label>
    <select>
      <option>Option 1</option>
      <option>Option 2</option>
    </select>
  </div>
</script>

<script type="x-template" id="form-textarea">
  <div>
    <label>Textarea</label>
    <textarea></textarea>
  </div>
</script>

したがって、fields配列の各項目に新しいform-inputコンポーネントを作成する代わりに、フィールドのcomponentプロパティを介して正しいコンポーネントに関連付けられている新しいtypeを作成しています

7
Chris

form-inputコンポーネントのプロパティとしてフィールドオブジェクトを渡し、typeを動的にすることができます。

Vue.component('form-input', {
  template: '#form-input',
  props: ['field']
})

new Vue({
  el: '#app',
  data: {
    fields: [],
    inputType: '',
    count: 0
  },
  methods: {
    addFormElement(val) {
      this.fields.Push({type: val, placeholder: 'Textbox ' + (++this.count)});
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
  <h3>Add form element</h3>
  <select size="3" v-model='inputType' @click="addFormElement(inputType)">
    <option value="text">Text</option>
    <option value="checkbox">Checkbox</option>
    <option value="radio">Radio</option>
  </select>
  <p>
    <form-input v-for="field in fields" :field="field"></form-input>
  </p>
</div>

<template id="form-input">
  <div>
    <label>{{ field.type }}</label>
    <input :type="field.type" />
  </div>
</template>
1
Sovalina

回答のコードに基づいて、フォームコントロールのそれぞれに動的コンテンツを追加することもできます(完全な概念は、次の site で確認できます)。

   Vue.component('form-input', {
  template: '#form-input'
  , props: ['label','cnt']
   });

Vue.component('form-select', {
 template: '#form-select'
 , props: ['label','cnt']
});

Vue.component('form-textarea', {
   template: '#form-textarea'
   , props: ['label','cnt']
   });
new Vue({
  el: '#app',
  data: {
    fields: [],
    count: 0
  }
  , mounted() {
    // fetch those from back-end
    this.addFormElement('form-input','lbl', "form-input-content")
    this.addFormElement('form-textarea','lbl', "form-textarea-content")
    var select_cnt = [
      {'value': 1, 'text': 'item-01'},
      {'value': 2, 'text': 'item-02'}
    ]
    this.addFormElement('form-select','some-label',select_cnt)
  }
  , methods: {
    addFormElement: function(type,label,cnt) {
     this.fields.Push({
       'type': type
       , id: this.count++
       , 'label':label
       , 'cnt':cnt
     });
   }
  }
})
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
<div id="app">
 <component v-for="field in fields" v-bind:is="field.type" :key="field.id" :cnt="field.cnt" :label="field.label"></component>
</div>

<script type="x-template" id="form-input">
  <div v-on:keyup.tab="this.document.execCommand('selectAll',false,null);">
<label>{{label}}</label>
<input type="text" :value="cnt"/>
  </div>
</script>

<script type="x-template" id="form-textarea">
  <div v-on:keyup.tab="this.document.execCommand('selectAll',false,null);">
<label>{{label}}</label>
<textarea :value="cnt"></textarea>
  </div>
</script>

<script type="x-template" id="form-select">
  <div>
<label>Select</label>
<select>
  <option v-for="oitem in cnt" :value="oitem.value">{{oitem.text}}</option>
</select>
  </div>
  <div v-html="cnt"></div>
</script>
0
Yordan Georgiev