vue 子组件注册

Author

华丽

PublishDate

2022-12-13

category

编程

在开发的过程中,我们时常会用到类似到 element 或者 element-plus 的框架中的 el-form 或者 el-table 组件。在使用这些组件的时候,一般都是直接在组件内添加 el-form-item 或者 el-table-column 就可以了。

它们往往有一个特点,那就是不需要在父组件上增加太多的配置,直接通过添加子组件就可以完成多父组件的扩充。今天我们就简单来讨论一下,如何实现类似这样的功能。

现在我们假设,有这样的一个订单页面,需要在订单中进行分类显示,包括了「全部订单」「待支付」「待使用」「已完成」「售后/退款」这5个分类。

2022-12-13-14-11-10-image

我们希望通过之前提到的类似功能,直接通过添加子组件的方式就可以添加分类,可是使用类似以下的代码。注意,以下代码均忽略了样式。

  • 父组件
<!-- vue2 -->
<script>
export default {
  name: 'Tabs',
  data() {
    return {
      tabs: []
    }
  },
  // 重点
  provide() {
    return {
      orderTabs: this
    }
  },
  methods: {
    addTab(tabName) {
      this.tabs.push({
        name: tabName,
        // 默认选中第一项
        selected: this.tabs.length === 0
      })
    }
  }
}
</script>
<!-- vue3 -->
<script setup>
import { ref, provide } from 'vue'
const tabs = ref([])
const addTab = (tabName) => {
  tabs.value.push({
    name: tabName,
    selected: tabs.value.length === 0
  })
}
// 重点
provide('orderTabs', {
  addTab
})
</script>
<template>
  <div>
    <div>
      <div v-for="item in tabs" :key="item.name">
        {{ item.name }}
      </div>
    </div>
    <slot></slot>
  </div>
</template>
  • 子组件
<!-- vue2 -->
<script>
export default {
  name: 'TabItem',
  props: {
    name: {
      type: String,
      required: true
    }
  },
  // 重点
  inject: ['orderTabs'],
  mounted() {
    // 通过父组件的实例注册
    this.orderTabs.addTab(this.name)
  }
}
</script>
<!-- vue3 -->
<script setup>
import { defineProps, inject, onMounted } from 'vue'
const props = defineProps({
  name: {
    type: String,
    required: true
  }
})
// 重点
const orderTabs = inject('orderTabs', undefined)
onMounted(() => {
  // 通过父组件暴露的方法注册
  orderTabs && orderTabs.addTab(props.name)
})
</script>
<template>
  <div>
    <slot />
  </div>
</template>

以上代码,我们演示了,通过在父组件中暴露一个 addTab 的方法,然后子组件生成后使用 addTab(name) 向父组件中注册。然后可以这样使用两个组件

<script>
import { Tabs, TabItem } from 'components'

export default {
  components: {
    Tabs,
    TabItem,
  }
}
</script>

<template>
  <div>
    <tabs>
      <tab-item name="全部订单">
        <!-- 全部订单列表 -->
      </tab-item>
      <tab-item name="待支付">
        <!-- 待支付列表 -->
      </tab-item>
      <tab-item name="待使用">
        <!-- 待使用列表 -->
      </tab-item>
      <tab-item name="已完成">
        <!-- 已完成列表 -->
      </tab-item>
      <tab-item name="售后/退款">
        <!-- 售后/退款列表 -->
      </tab-item>
    </tabs>
  </div>
</template>

当然,这只是一个简单的示例,目前的代码会导致页面同时显示了五个列表。

解决这个问题可以有许多方法,比如直接在使用时通过 v-if 来判断是否显示列表,或者在父组件中暴露一个 selectedName 给子组件,子组件通过判断自己是不是当前选中的内容来判断是否显示,等等。

闽 ICP 备 2021009779 号 - 1 | Copyright © 2020 华丽 | Powered By Hugo