如何使用 Vue 3 基于静态组件创建可重用组件

How do I create a reusable component based on a static component using Vue 3

我最近开始使用 Vue 3 和 Headless UI。

我创建了一个 ListBox 组件,它在 App.vue 中用于显示 People 的列表并且按预期工作。
我希望将它变成一个可重用的组件,用于显示 PeopleCountries.

的列表

如何将我的组件更改为对这两种类型都是动态的?

ListBox.vue

<template>

    <Listbox v-model="selectedPerson">

        <ListboxButton class=" bg-white shadow-sm border-gray-500 border-2 shadow-gray-200 font-bold p-4 text-left rounded-md">
            {{ selectedPerson.name }}
        </ListboxButton>

        <ListboxOptions class="mt-2">

            <ListboxOption
                as="template" v-slot="{ active }"
                v-for="person in people" :key="person"
                :value="person">
                <li :class="{
                    'bg-blue-500 text-white p-6': active,
                    'bg-white shadow-lg p-6 text-black ': !active
                }">
                    {{ person.name }}
                </li>
            </ListboxOption>

        </ListboxOptions>

    </Listbox>

</template>

<script setup>
    import { ref } from 'vue'
    import {
        Listbox,
        ListboxLabel,
        ListboxButton,
        ListboxOptions,
        ListboxOption,
    } from '@headlessui/vue'

    const people = [
        { id: 1, name: 'Durward Reynolds' },
        { id: 2, name: 'Kenton Towne' },
        { id: 3, name: 'Therese Wunsch' },
        { id: 4, name: 'Benedict Kessler' },
        { id: 5, name: 'Katelyn Rohan' },
    ]
    const selectedPerson = ref(people[0])
</script>

App.vue:

<template>
    <ListBox />
</template>

你几乎做到了你想做的,你只需要props
peoplecountries 是您的子组件 DataTable.vue 的实例,您希望在父组件 App.vue.

中使用它们

DataTable.vue :

<template>
 <div id='data-table'> 
   {{table}}
 </div>
</template>
 
<script>
export default {
  .
  .
  .
 props: ['table']
}
</script>

App.vue:

<template>
   <data-table table='people' />
   <data-table table='countries' />
</template>

而且您还必须在子组件外部定义表格,然后传递给子组件,更好的方法是使用 state management,例如 vuex

您需要接受要显示的项目列表和当前选择的项目或列表索引作为组件的道具。
下面是一个示例,编码为 on-the-fly 并且未经测试,但应该让您清楚地了解要尝试什么以及如何进行。

此外,我会重命名该组件以避免与您在 Headless UI.

中使用的 Listbox 组件混淆

App.vue

<template>
   <ItemList :items='people' :selected-index='0' />
   <ItemList :items='countries' :selected-index='0' />
</template>

<script>
const people = [
    { id: 1, name: 'Durward Reynolds' },
    { id: 2, name: 'Kenton Towne' },
    { id: 3, name: 'Therese Wunsch' },
    { id: 4, name: 'Benedict Kessler' },
    { id: 5, name: 'Katelyn Rohan' },
]
const countries = [
    { id: 1, name: 'Italy' },
    { id: 2, name: 'Switzerland' },
    { id: 3, name: 'Austria' },
    { id: 4, name: 'Germany' },
]
</script>

ItemList.vue

<template>
    <Listbox v-model="selectedItem">
        <ListboxButton class=" bg-white shadow-sm border-gray-500 border-2 shadow-gray-200 font-bold p-4 text-left rounded-md">
            {{ selectedItem.name }}
        </ListboxButton>

        <ListboxOptions class="mt-2">
            <ListboxOption
                as="template" v-slot="{ active }"
                v-for="item in items" :key="item.id"
                :value="item">
                <li :class="{
                    'bg-blue-500 text-white p-6': active,
                    'bg-white shadow-lg p-6 text-black ': !active
                }">
                    {{ item.name }}
                </li>
            </ListboxOption>
        </ListboxOptions>
    </Listbox>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import {
    Listbox,
    ListboxLabel,
    ListboxButton,
    ListboxOptions,
    ListboxOption,
} from '@headlessui/vue'

const props = defineProps({
    items: Array,
    selectedIndex: Number,
})

const selectedItem = ref(null)

onMounted(() => {
    if(items && selectedIndex >= 0 && selectedIndex < items.length) {
        selectedItem.value = items[selectedIndex]
    }
})
</script>