javascript 在 Vue 中动态添加不同的组件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/50418651/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 09:05:32  来源:igfitidea点击:

Dynamically adding different components in Vue

javascriptvue.jscomponents

提问by Chris

I want to create a simple form builder with Vue where users click on buttons from a menu to add different form fields to a form. I know that if there was just one type of form field to add, I could do it with something like this (https://jsfiddle.net/u6j1uc3u/32/):

我想用 Vue 创建一个简单的表单构建器,用户可以在其中单击菜单中的按钮以将不同的表单字段添加到表单中。我知道如果只添加一种类型的表单字段,我可以用这样的东西来做(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>

And:

和:

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

But what if there's more than one type of form field (input, file, select, etc...)? I was thinking maybe build a different component for each type, but then how would I show multiple types of components in a single list of form elements?

但是如果有不止一种类型的表单字段(输入、文件、选择等)怎么办?我在想可能为每种类型构建一个不同的组件,但是我将如何在单个表单元素列表中显示多种类型的组件?

Could I maybe create a component with children components of different types based on the data in the fieldsarray?

我可以根据fields数组中的数据创建一个包含不同类型的子组件的组件吗?

Or is there a better way to go about this situation that I'm missing? I've just started learning Vue, so any help is appreciated!

或者有没有更好的方法来解决我错过的这种情况?我刚刚开始学习 Vue,所以非常感谢您的帮助!

采纳答案by Chris

Ok, so I looked into dynamic elements and managed to pull this together:

好的,所以我研究了动态元素并设法将其整合在一起:

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>

So instead of creating a new form-inputcomponent for each item in the fieldsarray, I'm creating a new componentthat is associated with the correct component via the typeproperty of the fields

因此,我没有form-inputfields数组中的每个项目创建一个新组件,而是component通过type字段的属性创建一个与正确组件相关联的新组件

回答by Sovalina

You can pass the field object as props of your form-inputcomponent and make the typedynamic:

您可以将字段对象作为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>

回答by Yordan Georgiev

Based on the code from the answer, one could add dynamic content for each one of those form controls as well ( the full concept could be seen from the following 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>