Vue-使用子组件进行添加和更新

时间:2019-04-02 18:46:42

标签: javascript vue.js

我有一个非常简单的父/子组件。我想两种方式都使用子组件-首先用于添加新条目的操作,其次用于更新实体的操作。

我已经构建了以下组件:https://codepen.io/anon/pen/bJdjyx这里我不使用道具,而是使用自定义事件将值从父级同步到子级。

添加-模板:

<div id="app">
  <v-app>
    <v-content>
      <v-container grid-list-xl>
        <my-address
          :addresscompany.sync="addressCompany"
          :addressstreet.sync="addressStreet"
          ></my-address>
        <v-btn @click="submit">Submit</v-btn>
      </v-container>
    </v-content>
  </v-app>
</div>

<script type="text/x-template" id="address-template">
    <div>
      <v-text-field
        name="company"
        v-model="addressCompany"
        @change="updateCompany()">
        </v-text-field>
      <v-text-field
        name="street"
        v-model="addressStreet"
        @change="updateStreet()">
        </v-text-field>
    </div>
</script>

添加-脚本:

let addressComponent = {
  template: '#address-template',

  data() {
    return {
      addressCompany: '',
      addressStreet: '',
    }
  },

  methods: {
    updateCompany () {
      this.$emit('update:addresscompany', this.addressCompany);
    },
        updateStreet () {
      this.$emit('update:addressstreet', this.addressStreet);
    }
  }
};


new Vue({
  el: '#app',
  components: {'my-address' : addressComponent},

  data() {
    return {
      addressCompany: '',
      addressStreet: '',
    }
  },

  methods: {
    submit () {
      console.log('Company ' + this.addressCompany);
       console.log('Street ' + this.addressStreet);
    }
  }
})

但是该模板不适用于编辑案例,因为我需要道具才能将值传递给子对象。所以我想出了这个:https://codepen.io/anon/pen/zXGLQG

更新-模板:

<div id="app">
  <v-app>
    <v-content>
      <v-container grid-list-xl>
        <my-address
          :addresscompany.sync="addressCompany"
          :addressstreet.sync="addressStreet"
          ></my-address>
        <v-btn @click="submit">Submit</v-btn>
      </v-container>
    </v-content>
  </v-app>
</div>


<script type="text/x-template" id="address-template">
    <div>
      <v-text-field
        name="company"
         :value="addressCompany"
        @change="updateCompany()">
        </v-text-field>
      <v-text-field
        name="street"
         :value="addressStreet"
        @change="updateStreet()">
        </v-text-field>
    </div>
</script>

更新-脚本:

let addressComponent = {
  template: '#address-template',
  props: ['addressCompany', 'addressStreet'],

  data() {
    return {
    }
  },

  methods: {
    updateCompany () {
      this.$emit('update:addresscompany', this.addressCompany);
    },
        updateStreet () {
      this.$emit('update:addressstreet', this.addressStreet);
    }
  }
};


new Vue({
  el: '#app',
  components: {'my-address' : addressComponent},

  data() {
    return {
      addressCompany: 'Company',
      addressStreet: 'Street',
    }
  },

  methods: {
    submit () {
      console.log('Company ' + this.addressCompany);
       console.log('Street ' + this.addressStreet);
    }
  }
})

主要区别在于,对于更新情况,我不对子元素使用v模型,因为我无法直接更改道具。但是使用:value时,不会触发更新事件。

那么使用该子组件进行添加和更新的正确方法是什么?在将Vuex用于这些目的之前,必须有一种标准的Vue方式吗?

谢谢!

1 个答案:

答案 0 :(得分:0)

我经常使用以下模式:

创建一个作为您的实体抽象的组件,在下面的示例中,我将Person.vuefirstNamelastName道具一起使用。

Vue.component('Person' , {
   template: `
    <div>
      <input type="text"
             :value="firstName"
              @input="$emit('update:firstName', $event.target.value)"/>
      <input type="text"
              :value="lastName"
              @input="$emit('update:lastName', $event.target.value)"/>
    </div>
  `,
  props: {
    firstName: String,
    lastName: String
  }
});
  

此组件的范围严格限于绑定到   Person对象,对其更改做出反应并更新父对象,并抛出sync事件修饰符。

接下来,创建一个包装组件,该包装组件将处理实际对象的状态,即Person.js。它的子组件Person.vue不在乎您是否处于“添加”或“编辑”模式。该组件仅负责对模型的更改做出反应。

此组件应从API调用或数据存储区加载Person对象(更新模式),或创建一个新的空对象,即new Person()(添加模式)。

下面是一个简单的示例,理想情况下,父组件(在这种情况下为app)将被拆分,从而减少了对helper属性的使用。

function Person (firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
}
Vue.component('Person' , {
  template: `
    <div>
      <input type="text"
             :value="firstName"
              @input="$emit('update:firstName', $event.target.value)"/>
      <input type="text"
              :value="lastName"
              @input="$emit('update:lastName', $event.target.value)"/>
    </div>
  `,
  props: {
    firstName: String,
    lastName: String
  }
});
new Vue({
  el: '#app',
  template: `
    <div>
      <!-- Add mode, should be its own component -->
      <section v-if="promptAdd">
        <Person v-bind.sync="newPerson"/>
        <button type="button" @click="onAdded">Add</button>
      </section>
      <!-- Update mode, should be its own component -->
      <section v-else>
        <p>Users:</p>
        <div v-for="(person, index) in arr" :key="index">
          <Person v-bind.sync="person"/>
        </div>
        <button type="button"
                @click="addNew">Add New User</button>
      </section>
    </div>
  `,
  data: () => ({
    promptAdd: false,
    newPerson: undefined,
    arr: [
      new Person('Bob', 'Smith')
    ]
  }),
  methods: {
    addNew() {
      this.newPerson = new Person();
      this.promptAdd = true;
    },
    onAdded () {
      this.arr.push({ ...this.newPerson });
      this.promptAdd = false;
      this.newPerson = undefined;
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app"></div>