Vue.js 将数据从插槽传递到组件实例

Vue.js pass data from slot into component instance

我正在尝试构建一个可重复使用的组件来处理通过 AJAX 使用 Vue.js 提交的表单。理想情况下,我想要做的是有一个通用组件,可以用来代替 HTML form 元素,因为它可能包含一组未知的表单元素,例如 inputselecttextarea 等等。

我的组件有以下代码,名为 ajax-form:

<template>
    <form class="form" :action="action" :method="method" v-on:submit.prevent="ajaxSubmit">
        <slot></slot>
    </form>
</template>

<script>
module.exports = {
    props: {
        action: {
            required: true,
            type: String
        },
        method: {
            default: 'post',
            required: false,
            type: String
        }
    },
    data() {
        return {
            formData: {}
        }
    },
    methods: {
        ajaxSubmit() {
            // Do ajax
        }
    }
}
</script>

而在我的 HTML 中,我会有如下内容:

<ajax-form action="http://example.com/do/something">
    <input name="first_name" type="text">
    <textarea name="about_you"></textarea>
</ajax-form>

我最希望发生的事情是使用它的插槽将所有放置在我的组件内的表单元素映射到我的 Vue 组件实例中的 data.formData 属性。所以在这种情况下,data 属性 看起来像:

data: {
    formData: {
        first_name: '',
        about: ''
    }
}

如果我要在 HTML 中的组件中添加另一个字段,我希望它也能映射到 Vue 实例的 data 属性.

有什么办法可以实现吗?有没有一种方法可以告诉 Vue,当我通过插槽将表单元素放入组件时,我希望将此元素映射到组件 data?

中的某些内容

我尝试在每个表单元素上添加 v-modelv-bind 以查看它是否会以某种方式将数据传递到组件的数据中:

<ajax-form action="http://example.com/do/something">
    <input name="first_name" type="text" v-model="formData.first_name">
</ajax-form>

但是,Vue 抱怨反应式数据属性必须在模板中使用之前声明:

[Vue warn]: Property or method "formData" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.

您不能按照您的要求执行操作,因为插槽作用域仅限于父作用域。

您可以在全局 Vue 实例上定义 formData,因此现在可以从父范围访问它。

const app = new Vue({
    el: '#app',
    data: {
        formData : {}
    }
});

现在您可以将它作为 prop 传递给表单:

<ajax-form action="#" :form-data="formData>
    <input name="first_name" type="text" v-model="formData.first_name">
</ajax-form>

您可以使用 scopedSlots 来做到这一点。

api 看起来像这样:

<ajax-form action="http://example.com/do/something">
   <template scope="{formData}">    
   <input name="first_name" type="text" v-model="formData.first_name">
   </template>
</ajax-form>

并且在 ajax-form 组件中:

<form class="form" :action="action" :method="method" v-on:submit.prevent="ajaxSubmit">
   <slot :formData="formData">
</form>

您可以将parent的数据作为参数传递给child,如下所示:

中Parent:

<child-component ref="child">
      <h1 slot="heading">Test passing data to child</h1>
      <form slot="content">
          <input type="text" v-model="name" placeholder="Type your name" class="half">
          <input type="text" v-model="email" placeholder="Type your email" class="half">
          <div class="actions">
              <button data-role="submit" @click.prevent="callAddRep($event)">Add</button>
          </div>
      </form>
</child-component>
data() {
    return {
        name: '',
        email: ''
    }
},
methods: {
    callAddRep: function(e) {

      let name = this.name,
          email = this.email

      this.$refs.child.addRep(e, {
          name,
          email
      })
  }

中Child:

methods: {
      addRep: function(e, data) {

          //Data passed successfully
          console.log(data)

      }
  }

虽然@blockhead 的回答是正确的,但重要的是要注意插入到 ajax-form 中的插槽是否是具有自己的模板标签的单个文件组件并不重要。您仍然需要将该组件包装在外部模板标签中以拦截插槽属性,然后将它们作为属性传递到您的实际目标组件中

<modal-two modal_id="notif-modal">

    <template #default="{id_for_children}">

        <notification-alert :parent_modal_name="id_for_children" />
    </template>
</modal-two>

我在其他地方没看到这个