在使用ant-design-vue中曾经使用过table组件,所以想着自己封装一个组件尝试一下,这是一个简易版本

1. 相关知识点

  • 组件传值
  • 插槽(具名插槽、作用域插槽)
  • vue3 setup
  • vant v3 部分组件使用

2.封装子组件,按照要求规定参数

封装一个名为Ttablede组件,该组件接收两个参数,分别是columns和dataSource

2.1 子组件:接收参数,按数据提取动态具名插槽名

子组件:接收父组件传入的参数,并将传入的参数进行处理,提取出slot插槽值,用于动态设置具名插槽

import {computed, defineProps} from "vue";
// 接收参数 columns,dataSource
const props = defineProps({
  columns: {
    type: Array
  },
  dataSource: {
    type: Array
  }
})
// 提取slot属性,用于设置具名插槽
ref: columnSlot = computed(() => {
  const filterColumns = props.columns.length && props.columns.map((v) => {
    return v.slot
  })
  return filterColumns
})

2.2 父组件:定义数据源column、dataSource,传给子组件

2.2.1 column数据结构

const columns = [
  {
    title: '变化信息',
    key: 'changeMsg',
    slot: 'changeMsg',
  },
  {
    title: '当前出价',
    key: 'currentPrice',
    slot: 'currentPrice',
  },
  {
    title: '最低出价',
    key: 'lowestPrice',
    slot: 'lowestPrice',
  },
  {
    title: '最高出价',
    key: 'highestPrice',
    slot: 'highestPrice',
  },
]

2.2.2 dataSource数据结构

const dataList = [
  {
    changeMsg:'课程词1',
    currentPrice:'1.11',
    lowestPrice:'0.01',
    highestPrice:'2.35',
  },
  {
    changeMsg:'课程词2',
    currentPrice:'2.22',
    lowestPrice:'1.01',
    highestPrice:'3.35',
  },
  {
    changeMsg:'课程词3',
    currentPrice:'3.33',
    lowestPrice:'3.01',
    highestPrice:'2.35',
  },
]

2.2.3 传值给子组件

    <TTable
        :columns="columns"
        :dataSource="dataList"
    >
    </TTable>

3.子组件处理数据

3.1 处理表头header

    <!--header-->
    <li class="ttable-item header">
      <p class="ttable-item-content" v-for="item in columns" :key="item.key">{{ item.title }}</p>
    </li>

3.2 处理表单内容项

    <!--content-->
    <li class="ttable-item" v-for="(item,index) in dataSource" :key="index">
      <p class="ttable-item-content" v-for="(it,idx) in columnSlot" :key="idx"> 
        <slot :content="item" :name="it"/>   // name动态设置具名插槽,content对应的数据传给外部父组件
      </p>
    </li>

3.3 父组件使用

    <TTable
        :columns="columns"
        :dataSource="dataList"
    >
      <template v-slot:changeMsg="{content}" >  // 具名插槽,接收对应的content的值
        {{content.changeMsg}}
      </template>
      <template v-slot:currentPrice="{content}">
        {{content.currentPrice}}
      </template>
      <template v-slot:lowestPrice="{content}">
        {{content.lowestPrice}}
      </template>
      <template v-slot:highestPrice="{content}">
        {{content.highestPrice}}
      </template>
    </TTable>

4.完整代码

4.1 TTable完整代码

<!--
  功能:公共组件-table
  时间:2021-04-23
  madeBy:FTT
-->
<template>
  <ul class="ttable">
    <!--横向分类-->
    <li class="ttable-item header">
      <p class="ttable-item-content" v-for="item in columns" :key="item.key">{{ item.title }}</p>
    </li>
    <!--内容-->
    <li class="ttable-item" v-for="(item,index) in dataSource" :key="index">
      <p class="ttable-item-content" v-for="(it,idx) in columnSlot" :key="idx">
        <slot :content="item" :name="it"/>
      </p>
    </li>
  </ul>
</template>
<style scoped lang="less">
.ttable {
  padding: 10px 16px;

  .header {
    margin-bottom: 8px;
  }

  &-item {
    display: flex;
    justify-content: space-between;
    margin-bottom: 4px;

    &-content {
      flex: 1;
    }
  }
}
</style>
<script setup>
import {computed, defineProps} from "vue";

const props = defineProps({
  columns: {
    type: Array
  },
  dataSource: {
    type: Array
  }
})
ref: columnSlot = computed(() => {
  const filterColumns = props.columns.length && props.columns.map((v) => {
    return v.slot
  })
  return filterColumns
})
</script>

4.2 组件的使用

    <TTable
        :columns="columns"
        :dataSource="dataList"
    >
      <template v-slot:changeMsg="{content}" >
        {{content.changeMsg}}
      </template>
      <template v-slot:currentPrice="{content}">
        {{content.currentPrice}}
      </template>
      <template v-slot:lowestPrice="{content}">
        <span class="campaignItem-canChangeNum-style">{{content.lowestPrice}}</span>
      </template>
      <template v-slot:highestPrice="{content}">
        <span class="campaignItem-canChangeNum-style">{{content.highestPrice}}</span>
      </template>
    </TTable>
<style scoped lang="less">
	.campaignItem-canChangeNum-style {
      color: #0085F8;
      text-decoration: underline;
    }
 </style>
其中columns可以自定义,dataList可以通过网络请求获取

import TTable from '../../components/common/TTable.vue';

4.呈现效果

样式可以根据需求进行调整
在这里插入图片描述

5.扩充功能

5.1 cell值修改

如上图所示,我们想要对蓝色部位进行动态修改,点击蓝色,可以编辑,失去焦点,保存内容并发送网络请求,对父组件代码进行修改

 <template v-slot:lowestPrice="{content}">
    <span
      @click="changeLowestVal(content)"
       v-if="!content.change"
       class="campaignItem-canChangeNum-style"
    >
       {{ content.lowestPrice }}
   </span>
   <van-field @blur="saveNewLowestVal(content)" v-else v-model="willChangeLowestVal"/>
</template>
<script setup>
	ref: willChangeLowestVal = '';
	// 修改表格内容
	async function changeLowestVal(content) {
	  content.change = !content.change		// 修改时,显示field组件
	  willChangeLowestVal = content.lowestPrice 	// 输入内容,赋值给willChangeLowestVal
	}
	
	// 保存表单修改内容
	async function saveNewLowestVal(content) {
	   // TODO: 可以在这里发送网络请求,将数据在远端保存
	  content.lowestPrice = willChangeLowestVal;	// 保存表单内容,并在页面直接更新,避免整个页面的刷新体验不好
	  content.change = !content.change		// 关闭field框,显示保存后的数据
	}
	// 在初始化时对于可以修改的数据进行一个标识,不同的字段可以定义不同的change
	onMounted(() => {
	  dataList.forEach((v) => {
	    v.change = false;
 	 })
	})
</script>

5.1.1 扩充后的效果

在这里插入图片描述
点击红框
在这里插入图片描述
修改红框的值
在这里插入图片描述
点击其他位置,令其失去焦点
在这里插入图片描述
如果觉得上述情况下,无法直接弹出键盘,也可以直接封装一个指令,在mounted时,获取焦点即可

5.2 增加loading效果

增加一个选项loading

  loading:{
    type:Boolean,
    default:false,
  }

根据传入的loading值,判断展示列表还是loading选项

    <template v-if="loading">
      <van-loading type="spinner" color="#1989fa" vertical>加载中...</van-loading>
    </template>
    <!--内容-->
    <template v-else>
      <template v-if="dataSource.length">
        <li class="ttable-item" v-for="(item,index) in dataSource" :key="index">
          <p class="ttable-item-content" v-for="(it,idx) in columnSlot" :key="idx">
            <slot :content="item" :name="it"/>
          </p>
        </li>
      </template>
      <template v-else>
        <TTableNull />
      </template>
    </template>

外部传入的loading可以根据网络请求进行判断,若发送网络请求中,loading值传true,网络请求结束/出错,loading传false try…catch…finally 可以实现这种判断情形。

5.2.1 扩充后效果

加载数据时效果
在这里插入图片描述

数据加载结束后的效果
在这里插入图片描述

如果有帮助的话,点个赞呗~
商用转载请标明来源哦~

总结用法,希望可以帮助到你,
我是Ably,你无须超越谁,只要超越昨天的自己就好~

Logo

前往低代码交流专区

更多推荐