在 Vue JS 中将组件作为 prop 传递

fak*_*e97 1 vue.js vue-component vuejs2 vuetify.js

简介:我正在探索Vue Js,并在尝试制作动态数据表组件时陷入困境,我面临的问题是我无法通过 props 传递组件并将其呈现在表中。

问题:所以基本上我想做的是从v-data-table中的 headers prop 传递一些自定义组件,例如:

headers = [
    { text: 'Name', value: 'name' },
    {
      text: 'Phone Number',
      value: 'phone_number',
      render: () => (
         <div>
           <p>Custom Render</p>
         </div>
     )
    },
    { text: 'Actions', value: 'actions' }
]
Run Code Online (Sandbox Code Playgroud)

所以从上面的代码我们可以看到我想从Phone Number header中的渲染函数渲染该段落,我之前在React Js中做过这件事,但是如果有人可以指点我,我找不到在Vue Js中做到这一点的方法朝着正确的方向前进会很棒。先感谢您。

IVO*_*LOV 7

您有 2 个选择 - 插槽和动态组件。

我们首先来探讨一下插槽:

<template>
  <v-data-table :items="dataItems" :headers="headerItems">
    <template slot="item.phone_number" slot-scope="{item}">
      <v-chip>{{ item.phone_number }}</v-chip>
    </template>
    <template slot="item.company_name" slot-scope="{item}">
      <v-chip color="pink darken-4" text-color="white">{{ item.company_name }}</v-chip>
    </template>
  </v-data-table>
</template>
Run Code Online (Sandbox Code Playgroud)

数据表为您提供了可以自定义内容的插槽。如果您想让您的组件更具可重用性并希望从父组件填充这些插槽 - 那么您需要将这些插槽重新公开给父组件:

<template>
  <v-data-table :items="dataItems" :headers="headerItems">
    <template slot="item.phone_number" slot-scope="props">
      <slot name="phone" :props="props" />
    </template>
    <template slot="item.company_name" slot-scope="props">
      <slot name="company" :props="props" />
    </template>
  </v-data-table>
</template>
Run Code Online (Sandbox Code Playgroud)

如果您不知道将自定义哪些槽 - 您可以重新公开所有数据表槽:

<template>
  <v-data-table
    :headers="headers"
    :items="items"
    :search="search"
    hide-default-footer
    :options.sync="pagination"
    :expanded="expanded"
    class="tbl_manage_students"
    height="100%"
    fixed-header
    v-bind="$attrs"
    @update:expanded="$emit('update:expanded', $event)"
  >
    <!-- https://devinduct.com/blogpost/59/vue-tricks-passing-slots-to-child-components -->
    <template v-for="(index, name) in $slots" v-slot:[name]>
      <slot :name="name" />
    </template>
    <template v-for="(index, name) in $scopedSlots" v-slot:[name]="data">
      <slot :name="name" v-bind="data" />
    </template>

    <v-alert slot="no-results" color="error" icon="warning">
      {{ $t("no_results", {term: search}) }}"
    </v-alert>
    <template #footer="data">
      <!-- you can safely skip the "footer" slot override here - so it will be passed through to the parent component -->
      <table-footer :info="data" @size="pagination.itemsPerPage = $event" @page="pagination.page = $event" />
    </template>
  </v-data-table>
</template>

<script>
import tableFooter from '@/components/ui/TableFooter'; // you can safely ignore this component in your own implementation

export default
{
  name: 'TeacherTable',
  components:
    {
      tableFooter,
    },
  props:
    {
      search:
        {
          type: String,
          default: ''
        },
      items:
        {
          type: Array,
          default: () => []
        },
      sort:
        {
          type: String,
          default: ''
        },
      headers:
        {
          type: Array,
          required: true
        },
      expanded:
        {
          type: Array,
          default: () => []
        }
    },
  data()
  {
    return {
      pagination:
        {
          sortDesc: [false],
          sortBy: [this.sort],
          itemsPerPageOptions: [25, 50, 100],
          itemsPerPage: 25,
          page: 1,
        },
    };
  },
  watch:
    {
      items()
      {
        this.pagination.page = 1;
      },
      sort()
      {
        this.pagination.sortBy = [this.sort];
        this.pagination.sortDesc = [false];
      },
    }
};
</script>
Run Code Online (Sandbox Code Playgroud)

动态组件可以通过 props 提供:

<template>
  <v-data-table :items="dataItems" :headers="headerItems">
    <template slot="item.phone_number" slot-scope="{item}">
      <component :is="compPhone" :phone="item.phone_number" />
    </template>
    <template slot="item.company_name" slot-scope="{item}">
      <component :is="compCompany" :company="item.company_name" />
    </template>
  </v-data-table>
</template>

<script>
export default
{
  name: 'MyTable',
  props:
  {
    compPhone:
    {
      type: [Object, String], // keep in mind that String type allows you to specify only the HTML tag - but not its contents
      default: 'span'
    },
    compCompany:
    {
      type: [Object, String],
      default: 'span'
    },
  }
}
</script>
Run Code Online (Sandbox Code Playgroud)

插槽比动态组件更强大,因为它们(插槽)使用依赖倒置原则。您可以在Markus Oberlehner 的博客中阅读更多内容