• 作者:老汪软件技巧
  • 发表时间:2024-10-02 00:02
  • 浏览量:

封装一个UI库,加点自己的东东,是不是就可以变成自己的UI库呢?

好吧这不是重点,重点是封装之后呢,遇到的一个问题就是,原来UI库自带的插槽怎么透露出来?总不能一个一个定义吧。其实不难,只需要一个 v-for 就可以搞定。

普通插槽

以 el-input 为例来看看如何透传。

封装一下 el-input

做一个组件 my-input.vue

<template>
  <el-input v-model="model" placeholder="">
    
    <template
      v-for="(item, key) in $slots"
      v-slot:[key]
    >
      
      <slot :name=key> slot>
    template>
  el-input>
template>

不需要写js代码,仅仅在 template 里面 v-for 一下即可。

使用方式

先 import 组件,然后按照 el-input 的插槽设置即可:

  import myInput from './slot-son.vue'
  const person = reactive({
    name: 'jyk'
  })

按照官网的例子,设置一个 suffix 插槽:

  <myInput v-model="person.name">
    <template #suffix>
      <el-icon class="el-input__icon"><calendar />el-icon>
    template>
  myInput>

当然还可以设置其他插槽,就像使用 el-input 那样。

  <myInput v-model="person.name">
    <template #suffix>
      <el-icon class="el-input__icon"><calendar />el-icon>
    template>
    <template #prefix>
      <el-icon class="el-input__icon"><search />el-icon>
    template>
    <template #prepend>Http://template>
    <template #append>
      <el-select v-model="person.name" placeholder="Select" style="width: 115px">
        <el-option label="Restaurant" value="1" />
        <el-option label="Order No." value="2" />
        <el-option label="Tel" value="3" />
      el-select>
    template>
  myInput>

作用域插槽

这个有点绕圈圈,其实只需要加了一个属性绑定即可。

封装一下 el-table

封装代码示例__封装的代码怎么实现的

input 没有作用域插槽,所以这次我们使用 el-table 来举例:

  <el-table style="width: 100%">
    <el-table-column v-for="(key) in labels" :label="key" width="180">
      <template v-if="$slots[key]"  #default="scope">
        <slot :name="key" v-bind="scope">slot>
      template>
    el-table-column>
  el-table>

table-column 只有一个匿名插槽,也就是默认插槽,对于 column 来说这就可以了,但是封装后我们只想暴露table,所以还需要定义具名插槽,就以字段名作为插槽名称。

所以我们定义一个数组来存放字段名称,这里简化设置。

  type TProps = {labels: string[]}
  const props = defineProps<TProps>()

这样就完成了一个作用域插槽的透传。

使用方式

我们先定义一个字段数组,以及模拟数据:

  import mytable from './slot-table.vue'
  interface User {
    date: string
    name: string
    address: string
  }
  const labels = [
    '日期',
    'name',
    'address',
    'Operations'
  ]
  const tableData: User[] = [
    {
      date: '2016-05-03',
      name: 'Tom1',
      address: 'No. 1, Grove St, Los Angeles',
    },
    ...
  ]

然后我们先设置一个 日期 的插槽:

  <mytable :data="tableData" :labels="labels">
    <template #日期="scope">
      <div style="display: flex; align-items: center">
        <el-icon><timer />el-icon>
        <span style="margin-left: 10px">{{ scope.row.date }}span>
      div>
    template>
  mytable>

我们还可以设置其他插槽:(代码来自于官网实例)

  <mytable :data="tableData" :labels="labels">
    <template #日期="scope">
      <div style="display: flex; align-items: center">
        <el-icon><timer />el-icon>
        <span style="margin-left: 10px">{{ scope.row.date }}span>
      div>
    template>
    
    <template #name="scope">
      <el-popover effect="light" trigger="hover" placement="top" width="auto">
        <template #default>
          <div>name: {{ scope.row.name }}div>
          <div>address: {{ scope.row.address }}div>
        template>
        <template #reference>
          <el-tag>{{ scope.row.name }}el-tag>
        template>
      el-popover>
    template>
    <template #address="scope">
      {{ scope.row.address }}
    template>
    
    <template #Operations="scope">
      <el-button size="small" @click="handleEdit(scope.$index, scope.row)">
        Edit
      el-button>
      <el-button
        size="small"
        type="danger"
        @click="handleDelete(scope.$index, scope.row)"
      >
        Delete
      el-button>
    template>  
  mytable>

小结

这样做有何意义?这是低代码的一种实现方式,借用成熟的UI库,实现基础功能,然后用JSON绑定普通的字段,最后用插槽搞定特殊的字段。

这样可以实现既方便,又灵活的效果。

和原本 el-table 有何区别?这区别可就多了。

首先这个列是由 v-for 遍历出来的,也就是说,如果想要改变列的前后顺序,那么我们不需要修改 template,只需要修改数组里的元素的先后顺序即可。

还有其他各种好处,先不说了,做过低代码的都懂。