Vue cloning issue

时间:2018-06-04 17:17:14

标签: javascript vue.js cloning

I am learning vue and one of the things I would like to do is to clone elements. I was playing with this code:

var multiple = new Vue({
    el: '#vue',
    data: {

    },
    methods: {
        cloneWidget(e) {
            let widgets = document.getElementById('widgets');
            let widget = document.getElementById('widget');
            clone = widget.cloneNode(true);
            clone.id = Math.round(Math.random()*100);
            widgets.appendChild(clone);            
        },
        deleteClone(e) {
            e.target.parentNode.remove();            
        }
    }
});
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">    
    <link href="styles.css" rel="stylesheet" />    
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">    
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/css/materialize.min.css">
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>    
  </head>
  <body>
    <h1>Cloning</h1>

    <div id="vue">
      <form @submit.prevent>
        <div id="widgets">
          <div id="widget">
            <div>
              <label for="field1">Field 1:</label>
              <input type="text" name="field1">
            </div>
            <div>
              <label for="field2">Field 2:</label>
              <input type="text" name="field2">
            </div>
            <i class="material-icons delete" @click="deleteClone">delete</i>
          </div>          
        </div>
        <button @click="cloneWidget">Add Widget</button>
      </form>
    </div>

    <script src="app.js"></script>
  </body>
</html>

However, the deleteClone method never gets called outside the original div="widget".

I can't seem to figure out why the event listener is not getting attached to the clones. Will cloneNode() mess up Vue?

1 个答案:

答案 0 :(得分:1)

With Vue, generally you want to think in terms of data. Here is your example revised, such that a widget is rendered for each object in the widgets array.

In this case, the contents of the array don't make much sense; you would probably want to the properties of each object in the array to match your input fields, but this is just an example to get you going.

var multiple = new Vue({
    el: '#vue',
    data: {
      widgets:[{}]
    },
    methods: {
        addWidget() {
          this.widgets.push({})      
        },
        removeWidget(widget) {
           this.widgets.splice(this.widgets.findIndex(w => w === widget), 1)            
        }
    }
});
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/css/materialize.min.css" rel="stylesheet"/>

    <h1>Cloning</h1>

    <div id="vue">
      <form @submit.prevent>
        <div id="widgets">
          <div v-for="widget in widgets">
            <div>
              <label for="field1">Field 1:</label>
              <input type="text" name="field1">
            </div>
            <div>
              <label for="field2">Field 2:</label>
              <input type="text" name="field2">
            </div>
            <i class="material-icons delete" @click="removeWidget(widget)">delete</i>
          </div>          
        </div>
        <button @click="addWidget">Add Widget</button>
      </form>
    </div>

For the most part, you want to stay away from manipulating the DOM directly and let Vue do the work for you.