移动端 vue table 组件简单封装

1、背景:移动端封装table组件,组件分为三部分:tableHeader、tableBody、index具体效果图如下:

2、tableHeader.vue页面代码:

<template>
  <thead>
    <tr>
      <th
        v-for="item in columns"
        :width="item.width"
        :align="item.align || 'left'"
        :key="item.prop"
        :style="{
          'min-width': `${item['min-width']}`,
          'max-width': `${item['max-width']}`
        }"
        v-html="item.label"
      ></th>
    </tr>
  </thead>
</template>

<script>
export default {
  name: 'tableHeader',
  props: {
    columns: {
      type: Array,
      default: () => []
    }
  },
  methods: {
    renderToHtml(col) {
      if (typeof col.render === 'function') {
        this.$slots[col.prop] = [col.render(row)];
        return;
      }
      return;
    }
  }
};
</script>

<style scoped>
th {
  font-weight: bold;
  padding: 0.09rem 0.02rem;
  background: #f7f9f9;
  color: #8695a1;
  word-wrap: break-word;
  word-break: break-all;
}
</style>

3、tableBody页面代码:

<template>
  <tbody>
    <tr
      v-for="(item, index) in data"
      :key="index"
      :class="[stripe && 'stripe', rowClassName]"
    >
      <td
        v-for="(cItem, cIndex) in columns"
        :width="cItem.width"
        :align="cItem.align"
        :key="cIndex"
        :style="{
          'min-width': cItem['min-width'],
          'max-width': cItem['max-width']
        }"
        >{{ item[cItem.prop] }}</td
      >
    </tr>
  </tbody>
</template>

<script>
export default {
  name: 'tableBody',
  props: {
    columns: {
      type: Array,
      default: () => []
    },
    data: {
      type: Array,
      default: () => []
    },
    stripe: {
      type: Boolean,
      default: false
    },
    rowClassName: {
      type: String,
      default: ''
    }
  }
};
</script>

<style scoped>
.stripe:nth-child(even) {
  background-color: #f8faff;
}

td {
  padding: 0.13rem 0.02rem;
  border-bottom: 0.01rem solid #e8edf0;
  color: #253440;
  word-wrap: break-word;
  word-break: break-all;
}
</style>

4、index.vue页面代码

<template>
  <div class="table">
    <table>
      <table-header
        v-if="showHeader"
        ref="tableHeader"
        :columns="columns"
      ></table-header>
      <table-body
        v-if="data.length > 0"
        ref="bodyWrapper"
        :stripe="stripe"
        :row-class-name="rowClassName"
        :row-style="rowStyle"
        :style="{
          width: bodyWidth
        }"
        :columns="columns"
        :data="data"
      >
      </table-body>
    </table>
    <p v-if="data.length == 0" class="empty-data">暂无数据</p>
  </div>
</template>

<script>
import TableHeader from './tableHeader.vue';
import TableBody from './tableBody.vue';

export default {
  name: 'yssTable',
  components: {
    TableHeader,
    TableBody
  },
  props: {
    showHeader: {
      type: Boolean,
      default: true
    },
    columns: {
      type: Array,
      default: () => []
    },
    data: {
      type: Array,
      default: () => []
    },
    stripe: {
      type: Boolean,
      default: false
    },
    rowClassName: {
      type: String,
      default: ''
    },
    rowStyle: {
      type: Object,
      default: () => {}
    },
    bodyWidth: {
      type: Number,
      default: null
    },
    emptyBlockStyle: {
      type: Object,
      default: () => {}
    },
    emptyText: {
      type: String,
      default: ''
    }
  }
};
</script>

<style scoped>
table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.14rem;
}

.empty-data {
  text-align: center;
  font-size: 14px;
  color: #666;
  margin-top: 15px;
}
</style>

5、使用

<template>
  <div class="table-demo">
    <table-demo :columns="columns" :data="tableData"></table-demo>
  </div>
</template>

<script>
import TableDemo from './tableDemo';

export default {
  name: 'tableDemo',
  components: {
    TableDemo
  },
  data() {
    return {
      columns: [
        {
          prop: 'name',
          label: '姓名',
          width: '30%',
          'min-width': '0.6rem'
        },
        {
          prop: 'age',
          label: '年龄',
          align: 'right',
          width: '20%',
          'min-width': '0.6rem'
        },
        {
          prop: 'high',
          label: '<span>身高<br>(cm)</span>',
          align: 'right',
          width: '30%',
          'min-width': '0.7rem'
        },
        {
          prop: 'gender',
          label: '性别',
          align: 'right',
          width: '20%',
          'min-width': '0.7rem'
        }
      ],
      tableData: []
    };
  }
};
</script>

<style scoped>
.table-demo {
  background-color: #fff;
  padding: 15px;
}
</style>

思考:习惯了UI库的使用,渐渐对组件背后的东西缺乏探索,在写table组件的时候,发现经常使用的组件,其实写起来并不容易,这激起了一丢丢对UI库源码的好奇心,希望我能将这份好奇心付之行动,也希望下次再进行分享时,可以是对某个UI组件源码学习的分享。