组件开发(二)仿ant-design-vue实现自定义CusTable组件

仿照antd-vue实现的自定义table组件,包含以下基本点

1.边框  2.斑马纹 3.全选 4.排序 5.固定表头

一.总体效果

二.基本代码

1.父组件

<!-- Discription: table组件, author: ydj, Date: 2021-01-14 09:36:34 -->
<template>
  <div>
    <h1>仿antd-vue实现自定义表格</h1>
    <span>1.边框</span>
    <span>2.斑马纹</span>
    <span>3.全选</span>
    <span>4.排序</span>
    <span>5.固定表头</span>
    {{selectedItems}}
    <cus-table
      :columns="columns"
      :data="data"
      :height="200"
      border
      stripe
      :selectedItems.sync="selectedItems"
      :orderBy.sync="orderBy"
      @sort="sort"
    ></cus-table>
  </div>
</template>

<script>
import CusTable from "@/components/Table";
export default {
  components: {
    CusTable
  },
  data() {
    return {
      orderBy: {
        name: 'asc',
        age: 'asc',
        address: 'desc'
      },
      selectedItems: [],
      columns: [
        {
          title: "Name",
          key: "name"
        },
        {
          title: "Age",
          key: "age"
        },
        {
          title: "Address",
          key: "address"
        }
      ],
      data: [
        {
          id: 1,
          name: "张三丰",
          age: 18,
          address: "北京西城",
          date: "2017-11-12"
        },
        {
          id: 2,
          name: "韦小宝",
          age: 18,
          address: "北京东城",
          date: "2018-11-12"
        },
        {
          id: 3,
          name: "乔峰",
          age: 18,
          address: "北京海定",
          date: "2019-11-12"
        },
        {
          id: 4,
          name: "蔡徐坤",
          age: 18,
          address: "北京朝阳",
          date: "2020-11-12"
        },
        {
          id: 5,
          name: "肖战",
          age: 18,
          address: "北京昌平",
          date: "2021-01-12"
        },
        {
          id: 6,
          name: "贾冰",
          age: 18,
          address: "北京昌平",
          date: "2021-01-12"
        },
        {
          id: 7,
          name: "宋小宝",
          age: 18,
          address: "北京昌平",
          date: "2021-01-12"
        },
        {
          id: 8,
          name: "齐秦",
          age: 18,
          address: "北京昌平",
          date: "2021-01-12"
        }
      ]
    };
  },

  computed: {},

  methods: {
      sort(data1,data2){
// 处理排序的逻辑
          console.log('value',data1,data2)
      }
  }
};
</script>
<style lang='scss' scoped>
</style>

2.子组件

<!-- Discription: 自定义table, author: ydj, Date: 2021-01-14 09:56:26 -->
<template>
  <div class="table-wrapper" ref="tableWrapper">
    <div :style="{'height': Height}" class="scroll-box" ref="scrollBox">
      <table class="table" :class="{border,stripe}" ref="table">
        <!-- 表头 -->
        <thead>
          <tr>
            <th style="width:50px;">
              <input type="checkbox" :checked="checkAll" ref="checkAll" @change="handCheckAll" />
            </th>
            <th v-for="column in columns" :key="column.key">
              <div class="th-head">
                {{column.title}}
                <span
                  v-if="column.key in orderBy"
                  class="th-icon"
                  @click="handleSort(column)"
                >
                  <i class="iconfont icon-up" :class="{active:orderBy[column.key]==='asc'}"></i>
                  <i class="iconfont icon-down" :class="{active:orderBy[column.key]==='desc'}"></i>
                </span>
              </div>
            </th>
          </tr>
        </thead>
        <!-- 表体 -->
        <tbody>
          <tr v-for="row in data" :key="row.id">
            <td style="width:50px;">
              <input type="checkbox" @change="handleChange(row,$event)" :checked="isChecked(row)" />
            </td>
            <td v-for="column in columns" :key="column.key">{{row[column.key]}}</td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    height: {
      type: Number,
      default: 240
    },
    orderBy: {
      type: Object,
      default: () => {}
    },
    selectedItems: {
      type: Array,
      default: () => []
    },
    columns: {
      type: Array,
      default: () => []
    },
    data: {
      type: Array,
      default: () => []
    },
    border: {
      type: Boolean,
      default: false
    },
    stripe: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {};
  },
  mounted() {
// 如果传递了高度,才会固定表头
    if (this.height) {
      const table = this.$refs.table,
        tableWrapper = this.$refs.tableWrapper,
        copyTable = this.$refs.table.cloneNode(),
        thead = table.children[0];
      // 使用appenChild之后之前的表头就没有了
      tableWrapper.style.paddingTop =
        thead.getBoundingClientRect().height + "px";
      copyTable.appendChild(thead);
      tableWrapper.appendChild(copyTable);
      copyTable.classList.add("fied-header");
    }
  },
  watch: {
// 设置全选按钮的显示,有个indeterminate 属性是关键
    selectedItems() {
      if (this.selectedItems.length !== this.data.length) {
        if (this.selectedItems.length !== 0) {
          return (this.$refs.checkAll.indeterminate = true);
        }
      }
      this.$refs.checkAll.indeterminate = false;
    }
  },
  computed: {
    checkAll() {
// 判断是否显示全选
      return this.data.length === this.selectedItems.length;
    },
    Height() {
// 设置高度
      return this.height + "px";
    }
  },

  methods: {
    handleSort(column) {
// 排序的逻辑
      let orderBy = JSON.parse(JSON.stringify(this.orderBy));
      if (orderBy[column.key] === "asc") {
        orderBy[column.key] = "desc";
      } else if (orderBy[column.key] === "desc") {
        orderBy[column.key] = true;
      } else {
        orderBy[column.key] = "asc";
      }
      this.$emit("update:orderBy", orderBy);
// 传统给父组件sort事件,可以用来调用后端接口
      this.$emit("sort", column, orderBy);
    },
    isChecked(row) {
// 全选之后,每一项的选中情况
      return this.selectedItems.some(item => item.id === row.id);
    },
    handCheckAll(e) {
// 全选时,将所有数据传给父组件
      this.$emit("update:selectedItems", e.target.checked ? this.data : []);
    },
    handleChange(row, e) {
// 选中某项,添加到数组,否则从数组中删除
      let selectArray = JSON.parse(JSON.stringify(this.selectedItems));
      if (e.target.checked) {
        selectArray.push(row);
      } else {
        const id = selectArray.findIndex(item => item.id === row.id);
        selectArray.splice(id, 1);
      }
      this.$emit("update:selectedItems", selectArray);
    }
  }
};
</script>
<style lang='scss' scoped>
* {
  margin: 0;
  padding: 0;
}
.table-wrapper {
  position: relative;
  width: 80%;
  margin: 20px auto;
  .scroll-box {
    overflow-y: scroll;
  }
// 固定表头时增加的类名
  .fied-header {
    position: absolute;
    top: 0;
    left: 0;
  }
  table {
    width: 100%;
    border-collapse: collapse;
    border-spacing: 0;
// 设置边框,主要通过选择器的权重
    &.border {
      border: 1px solid #ccc;
      th,
      td {
        border: 1px solid #ccc;
      }
    }
    th {
      background: #ccc;
    }
// 设置斑马纹也是同理
    &.stripe {
      tbody {
        tr:nth-child(even) {
          background: #ccc;
        }
      }
    }
    th,
    td {
      padding: 5px;
      border-bottom: 10px solid #ccc;
      text-align: left;
    }
    .th-head {
      display: flex;
      align-items: center;
      cursor: pointer;
      .th-icon {
        display: flex;
        margin: 0 3px;
        flex-direction: column;
        .iconfont {
          margin: 0;
          color: #aaa;
          &.active {
            color: #000;
          }
          &.icon-down {
            margin-top: -10px;
          }
        }
      }
    }
  }
}
</style>

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ant-design-vue 中,可以通过自定义校验规来进行表单的验。下面是一个简单的示例: 1. 首先,你需要在你的表单组件中引入 `Form` 和 `FormItem` 组件: ```vue <template> <a-form :form="form"> <a-form-item label="用户名" :colon="false" :validateStatus="getValidateStatus('username')" :help="getHelp('username')"> <a-input v-decorator="['username', { rules: [{ validator: validateUsername }] }]"></a-input> </a-form-item> <a-form-item> <a-button type="primary" @click="submit">提交</a-button> </a-form-item> </a-form> </template> <script> import { FormModel, Input, Button } from 'ant-design-vue'; export default { components: { 'a-form': FormModel, 'a-form-item': FormModel.Item, 'a-input': Input, 'a-button': Button, }, data() { return { form: this.$form.createForm(this), }; }, methods: { validateUsername(rule, value, callback) { // 自定义校验规则 if (value && value.length < 5) { callback(new Error('用户名长度不能小于5个字符')); } else { callback(); } }, getValidateStatus(name) { const { getFieldError, isFieldValidating } = this.form; if (isFieldValidating(name)) { return 'validating'; } else if (getFieldError(name)) { return 'error'; } else { return ''; } }, getHelp(name) { const { getFieldError } = this.form; return getFieldError(name) || ''; }, submit() { this.form.validateFields((err, values) => { if (!err) { console.log('校验通过', values); } }); }, }, }; </script> ``` 在上述示例中,我们定义了一个表单,其中的用户名字段使用了自定义的校验规则 `validateUsername`。在 `validateUsername` 方法中,我们可以自定义校验逻辑,并通过 `callback` 返回校验结果。当校验不通过时,`callback` 的参数为一个 `Error` 对象,可以指定错误信息。在 `a-form-item` 组件中,我们使用了 `:validateStatus` 和 `:help` 属性来显示校验状态和错误信息。 注意:在以上示例中,我们使用了 ant-design-vue 的 FormModel、Input 和 Button 组件,请确保已经正确引入这些组件。 这就是在 ant-design-vue 中使用自定义校验规则的方法,你可以根据自己的需求进行相应的定制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值