首页 > 解决方案 > 从多个子组件Vue js中获取数据

问题描述

几天来我一直在头疼,试图弄清楚如何从子组件中获取数据。

情况是这样的。

我有一个名为的父组件Post,用户可以在其中选择日期、标题、描述,并且可以包含多个组件实例EventEvent组件包含标题、描述、与会者等字段。

用户应该能够添加多个Event组件,这意味着我在组件Event中有多个Post组件。

所以,我不知道如何组合我的组件以Event在我的组件中包含一组对象Post,稍后我可以将其发送到我的 API。

我需要的对象的结构post是:

// Post.vue
{ 
    "date": '',
    "name": '',
    "description": '',
    "events": {
       {
        "title": '',
        "description": '',
        "attendees": ''
       },
       {
        "title": '',
        "description": '',
        "attendees": ''
       }
    }
}

所以,我不知道应该以及如何使用 vuex。我尝试使用 $emit 传递数据,但我找不到适合将数据导入Post模型的方法。

有人可以指出我应该在哪里寻找它吗?

编辑#1:添加示例代码

组件的代码:

<template>
  <v-form>
    <v-container>
      <v-row>
        <v-col
          cols="12"
          md="4"
        >
          <v-date-picker v-model="post.date" scrollable>
            <v-spacer />
            <v-btn text color="primary" @click="modal = false">
              Cancel
            </v-btn>
            <v-btn text color="primary" @click="$refs.dialog.save(date)">
              OK
            </v-btn>
          </v-date-picker>
        </v-col>

        <v-col
          cols="12"
          md="4"
        >
          <v-text-field
            v-model="post.name"
            label="name"
            required
          />
        </v-col>

        <v-col
          cols="12"
          md="4"
        >
          <v-textarea
            v-model="post.description"
            name="description"
            label="Description"
            dense
            value
            rows="4"
            hint
          />
        </v-col>
      </v-row>
      <v-row>
        <v-btn primary rounded @click="addLine">
          Add Event
        </v-btn>
        <v-expansion-panels accordion>
          <UserEvent
            v-for="(line, index) in lines"
            :key="index"
            @addLine="addLine"
            @removeLine="removeLine(index)"
          />
        </v-expansion-panels>
      </v-row>
    </v-container>
  </v-form>
</template>

<script>
import UserEvent from './partials/event'
export default {
  name: 'Post',
  components: { UserEvent },
  data () {
    return {
      post: [],
      lines: [],
      blockRemoval: true
    }
  },
  watch: {
    lines () {
      this.blockRemoval = this.lines.length <= 1
    }
  },
  mounted () {
  },
  methods: {
    addLine () {
      const checkEmptyLines = this.lines.filter(line => line.number === null)
      if (checkEmptyLines.length >= 1 && this.lines.length > 0) { return }
      this.lines.push({
        title: null,
        description: null,
        attendees: null
      })
    },
    removeLine (lineId) {
      if (!this.blockRemoval) { this.lines.splice(lineId, 1) }
    }
  }
}
</script>

和子组件 UserEvent

// UserEvent.vue
<template>
  <v-expansion-panel>
    <v-expansion-panel-header>Event details</v-expansion-panel-header>
    <v-expansion-panel-content>
      <v-row>
        <v-col cols="12" md="6">
          <v-text-field
            v-model="event.title"
            label="Title"
            required
          />
        </v-col>

        <v-col
          cols="12"
          md="6"
        >
          <v-text-field
            v-model="event.atttendees"
            label="Atendees"
            required
          />
        </v-col>

        <v-col
          cols="12"
          md="12"
        >
          <v-textarea
            v-model="event.description"
            name="description"
            label="Description"
            dense
            value
            rows="4"
            hint
          />
        </v-col>
        <v-col
          cols="12"
          md="3"
        >
          <div class="block float-right">
            <v-btn @click="removeLine(index)" />
            <v-btn v-if="index + 1 === lines.length" @click="addLine" />
          </div>
        </v-col>
      </v-row>
    </v-expansion-panel-content>
  </v-expansion-panel>
</template>

<script>
export default {
  name: 'UserEvent',
  props: ['line', 'index'],
  data () {
    return {
      event: []
    }
  },
  methods: {
    addLine () {
      this.$emit('addLine')
    },
    removeLine (index) {
      this.$emit('removeLine', index)
    }
  }
}
</script>

标签: vue.jsvuexnuxt.js

解决方案


这是问题中提出的具有类似结构的示例:

{
  name: String,
  events: [
    title: String,
    description: String,
  ],
}

此示例允许用户打开表单以添加新事件。提交该表单时,事件数据将添加到父组件的状态中。

家长

<template>
  <div>
    <input v-model="name" />
    <ul v-if="events.length">
      <li v-for="(event, index) in events" :key="index">
        <span>{{ event.title }}</span>
        <span>{{ event.description }}</span>
      </li>
    </ul>
    <Event v-if="isNewEventFormVisible" @submit="addEvent" />
    <button v-else @click="showNewEventForm">add event</button>
  </div>
</template>
import Event from '~/components/Event';

export default {
  components: { Event },
  data() {
    return {
      name: 'Example Post',
      events: [],
      isNewEventFormVisible: false,
    };
  },
  methods: {
    addEvent({ title, description }) {
      this.isNewEventFormVisible = false;
      this.events.push({ title, description });
      // TODO: call you API here to update
    },
    showNewEventForm() {
      this.isNewEventFormVisible = true;
    },
  },
};

事件

<template>
  <form @submit.prevent="onSubmit">
    <input v-model.trim="title" type="text" />
    <br />
    <textarea v-model.trim="description" />
    <button type="submit">submit</button>
  </form>
</template>
export default {
  data() {
    return {
      title: '',
      description: '',
    };
  },
  methods: {
    onSubmit() {
      this.$emit('submit', {
        title: this.title,
        description: this.description,
      });
    },
  },
};

您可以想象一个更复杂的版本,其中事件是可编辑的。在这种情况下,每个都Event可以使用 props 并将它们作为值绑定到其输入,而不是使用v-models。


推荐阅读