我实现一个vue的table组件

1,227 阅读1分钟

💕效果

样式虽然非常丑,但是不要太在意,咱们是来学习Vue写组件的,样式这东西右手就行。。。image.png

💕需求

image.png

image.png

image.png

image.png

image.png

🐱‍🏍行,看完需求,那咱就开始!

😜组件结构

image.png 

大致是有三部分组成

  1. Ktable.vue 就是table
  2. Ktablecoloumn.vue 来存储表格标题
  3. Kline.vue 来生成每一行数据

最后再来一个 index.vue 当我们的测试用例

👏目录结构

image.png

😆index.vue

<template>
  <!-- 把tableData,表格数据传入table组件, -->
  <k-table :model="tableData" :prop="label">
    <!-- 
        sortable:是否排序,点击标题内的button触发
        table-cluomn:KtableColumn组件传来的生成的列的顺序
        prop:每个格子的属性名
        label:每个格子的中文标题
       -->
    <k-table-column
      :sortable="true"
      @table-cluomn="cluomn($event)"
      :prop="'big'"
      :label="'大小'"
    ></k-table-column>
    <k-table-column
      :sortable="true"
      @table-cluomn="cluomn($event)"
      :prop="'address'"
      :label="'地址'"
    ></k-table-column>
    <k-table-column
      :sortable="true"
      @table-cluomn="cluomn($event)"
      :prop="'name'"
      :label="'姓名'"
    ></k-table-column>
    <k-table-column
      :sortable="true"
      @table-cluomn="cluomn($event)"
      :prop="'date'"
      :label="'日期'"
    ></k-table-column>
  </k-table>
</template>

<script>
// 导入组件
import KTable from "./Ktable.vue";
// import KTableColumn from "./KtableColumn.vue";
import KTableColumn from "@/components/Ktable/KtableColumn.vue";
// import KTableColumn from "comps/Ktable/KtableColumn.vue";
export default {
  components: { KTable, KTableColumn },
  data() {
    return {
      // 动态获取表格 标题的顺序 big,address,name,date
      label: [],
      // 表格数据
      tableData: [
        {
          big: 10,
          date: "2016-05-02",
          name: "1王小虎",
          address: "上海市普陀区金沙江路 1518 弄",
        },
        {
          big: 0,
          date: "2016-05-04",
          name: "2王小虎",
          address: "上海市普陀区金沙江路 1517 弄",
        },
        {
          big: 1,
          date: "2016-05-01",
          name: "4王小虎",
          address: "上海市普陀区金沙江路 1519 弄",
        },
        {
          big: 3,
          date: "2016-05-03",
          name: "3王小虎",
          address: "上海市普陀区金沙江路 1516 弄",
        },
      ],
    };
  },
  mounted() {},
  methods: {
    // 通过KtableColumn组件的this.$emit() 把每一个列的标题传过来,不然生成列的顺序会是data 里面tableData的顺序
    cluomn(e) {
      // 每次生成一个列的标题就push一个标题到label
      this.label.push(e);
    },
  },
};
</script>

<style>
</style>

👌kTable.vue

<template>
  <table border="1">
    <tr>
      <!-- 标题行插槽 用来接收 KtableColumn组件 -->
      <slot></slot>
    </tr>
    <!-- 每一行的组件,根据index过来的数组生成行内数据 -->
    <!-- 
      model:传入每一个数组元素
      prop:标题的顺序,用来传给下一级组件,来实现标题和列的对应
     -->
    <k-line v-for="(item, index) in model" :model="item" :prop="prop"  :key="index"></k-line>
  </table>
</template>
·
<script>
import KLine from "./Kline.vue";
export default {
  components: { KLine },
  props: {
    // 绑定的tabledata
    model: {
      type: Array,
    },
    // 标题顺序
    prop: {
      type: Array,
    },
  },
  mounted() {
  },
  methods: {},
};
</script>

<style>
</style>

💋KtableColumn.vue

<template>
  <th>
    <!-- 展示列名 -->
    <span>{{ label }}</span>
    <!-- button 实现升降排序 -->
    <button @click="sort('asc')" v-if="sortable">升序</button>
    <button @click="sort('desc')" v-if="sortable">降序</button>
  </th>
</template>
<script>
export default {
  props: {
    // 当前行的标签属性名
    prop: {
      type: String,
      default: "",
    },
     // 当前行的标签属性文本
    label: {
      type: String,
      default: "",
    },
    // 是否排序
    sortable: {
      type: Boolean,
      default: true,
    },
  },
  data() {
    return {
      // 实现排序功能
      "asc-n": (a, b) => a - b,
      "desc-n": (a, b) => b - a,
      "asc-s": (a, b) => a.localeCompare(b),
      "desc-s": (a, b) => b.localeCompare(a),
    };
  },
  mounted() {
    // 传回父组件,通知父组件把字符串加入顺序数组
    this.$emit("table-cluomn", this.prop);
  },
  methods: {
    sort(type) {
      // 是否排序
      if (this.sortable) {
        // 对父父亲元素进行排序
        this.$parent.$parent.tableData.sort((a, b) => {
          // 调用排序规则,传入排序方式asc、desc,然后判断数据类型进行拼接后调用方法实现排序
          return this[type + this.getSortType(a[this.prop])](
            a[this.prop],
            b[this.prop]
          );
        });
      }
    },
    // 处理排序类型
    getSortType(val) {
      // 返回标识串进行拼接
      return typeof val === "string" ? "-s" : "-n";
    },
  },
};
</script>

<style>
</style>

😁Kline.vue

<template>
  <tr>
    <!-- 
      生成一行数据,
      遍历生成的标题顺序,
      从每一个对象中取出用户选定的标题的数据
     -->
    <td v-for="td in prop" :key="td">{{ model[td] }}</td>
  </tr>
</template>

<script>
export default {
  props: {
    // 绑定的tabledata
    model: {
      type: Object,
    },
    // 标题顺序
    prop: {
      type: Array,
    },
  },
  data() {
    return {
    };
  },
  mounted() {
  },
};
</script>

<style>
</style>

🎉至此完成

🤦‍♀️但是还是有很多的问题

🐱‍💻1. 无法实现更加自由的书写,只支持我规定的写法

🐱‍🚀2. 数值传递层级太多,在长列表时会出现问题,

👀3. 耦合很严重

🐱‍👓最后是,如果你觉得我哪里写的有问题,欢迎在评论区指出来,我们一起研究,我也是第一次写组件,还是很菜,希望各位大佬给小弟指点指点。