代码之家  ›  专栏  ›  技术社区  ›  Chris

在Vue中动态添加不同组件

  •  15
  • Chris  · 技术社区  · 6 年前

    我想用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>
    

    以及:

    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,非常感谢您的帮助!

    3 回复  |  直到 6 年前
        1
  •  19
  •   Chris    6 年前

    我设法将这些动态元素结合起来:

    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/vue@2.5.16/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>

    所以与其创造一个新的 form-input 中每个项目的组件 fields 数组,我正在创建一个新的 component 与正确的部件通过 type 场的性质

        2
  •  1
  •   Sovalina    6 年前

    你可以将场对象作为你的道具传递 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>
        3
  •  1
  •   Yordan Georgiev    4 年前

    根据答案中的代码,还可以为这些表单控件中的每一个添加动态内容(完整的概念可以从下面的内容中看到) 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/vue@2.5.16/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>