当前位置:   article > 正文

antdv table组件封装成全局组件以及携带自定义表头展示_antvtable

antvtable
1、封装table组件
// tableBox.vue
<template>
  <div class="table-c">
    <a-table
      :expandIcon="customIcon"
      :columns="tableColumns"
      :data-source="dataSource"
      :pagination="pagination"
      :loading="loading"
      :rowSelection="rowSelection"
      @change="change"
      @expand="expand"
    >
      <template
        v-for="i in tableColumns"
        :key="i.key"
        v-slot:[i.slots?.customRender]="{ record }"
      >
        <slot :name="i.slots?.customRender" :record="record"></slot>
      </template>

      <template v-slot:[expandedRowRender]="{ record }">
        <slot name="expandedRowRender" :record="record"></slot>
      </template>
    </a-table>
    <a-modal
      title="列表设置"
      v-model:visible="visible"
      :width="800"
      :confirmLoading="tableHeadLoading"
      :bodyStyle="{
        paddingBottom: '10px',
      }"
    >
      <a-checkbox-group v-model:value="tableHead" class="checked-item">
        <a-row>
          <a-col
            :span="5"
            v-for="check in columns"
            :key="check.key"
            :offset="1"
          >
            <a-checkbox :value="check.key" :disabled="check.key == 'action'">
              <span
                v-text="check.key == 'action' ? '操作' : check.title"
              ></span>
            </a-checkbox>
          </a-col>
        </a-row>
      </a-checkbox-group>
      <template #footer>
        <div class="pop-btn-box">
          <div class="btn-left">
            <a-button @click="checkAll">全选</a-button>
            <a-button @click="checkNoAll">全不选</a-button>
          </div>
          <div class="btn-right">
            <a-button @click="handleHeadCancel">返回</a-button>
            <a-button type="primary" @click="setConfirm" class="ok-btn"
              >确定</a-button
            >
          </div>
        </div>
      </template>
    </a-modal>
  </div>
</template>
<script setup>
import { h, reactive, ref } from "vue";
import { RightOutlined, SettingOutlined } from "@ant-design/icons-vue";
import { message } from "ant-design-vue";
import { useStore } from "vuex";
const store = useStore();
const props = defineProps({
  columns: {
    // 弹窗显示的所有项
    type: Array,
    default: [],
  },
  pagination: {
    type: Object,
    default: {
      hideOnSinglePage: true,
    },
  },
  rowSelection: {
    type: Object,
    default: undefined,
  },
  dataSource: {
    type: Array,
    default: [],
  },
  expandedRowRender: {
    type: String,
    default: "",
  },
  routerName: {
    type: String,
    default: "",
  },
  loading:{
    type:Boolean,
    default:false
  }
});
let tableColumns = ref([]);
let visible = ref(false);
let tableHead = ref([]);
let initTabHead = [];
const tableHeadLoading = ref(false);
const attrsName = ref("");
attrsName.value = props.routerName;
const emit = defineEmits(["change", "expand"]);
//构造表格列
const createColumns = () => {
  const arr = props.columns.map((item) => {
    let obj = { ...item };
    obj.isShow = item.isShow != undefined ? item.isShow : true;
    obj.dataIndex = item.key;
    !obj.slots && item.isSlot ? (obj.slots = { customRender: item.key }) : "";
    item.key === "action"
      ? (obj.title = h(SettingOutlined, {
          class: "set-icon",
          onClick: () => {
            visible.value = true;
          },
        }))
      : "";
    return obj;
  });
  initTabHead = [...arr]; // 用于后续操作
  tableHead.value = arr // 控制全选以及选中的项
    .filter((i) => {
      if (i.isShow) {
        return i;
      }
    })
    .map((t) => t.key);
  return arr;
};
let showColumns = createColumns();
showColumns = showColumns.filter((i) => i.isShow == true);
tableColumns.value = showColumns; // 表格显示的所有项,isShow 为true时
const checkAll = () => {
  let showArr = [];
  initTabHead.forEach((tab) => {
    tab.isShow = true;
    showArr.push(tab);
  });
  tableHead.value = showArr
    .filter((i) => {
      if (i.isShow) {
        return i;
      }
    })
    .map((t) => t.key);
};
const checkNoAll = () => {
  let showArr = [];
  initTabHead.forEach((tab) => {
    tab.isShow = false;
    if (tab.key == "action") {
      tab.isShow = true;
      showArr.push(tab);
    }
  });
  tableHead.value = showArr
    .filter((i) => {
      if (i.isShow) {
        return i;
      }
    })
    .map((t) => t.key);
};
//设置显示那些列
const setConfirm = () => {
  tableHeadLoading.value = true;
  let showArr = [];
  let setArr = [];
  initTabHead.forEach((tab) => {
    tab.isShow = false;
    tableHead.value.forEach((el) => {
      if (tab.key == el) {
        tab.isShow = true;
        showArr.push(tab);
        setArr.push(el);
      }
    });
  });
  tableHeadLoading.value = false;
  if (showArr.length < 2) {
    message.info("至少选中两项");
  } else {
    tableColumns.value = showArr;
    let obj = Object.assign({}, store.state.tableHeadObj);
    obj[attrsName.value] = [...setArr];
    store.commit("setTableHeadObj", obj);
    message.success("设置成功");
    visible.value = false;
  }
};
const handleHeadCancel = () => {
  createColumns(); // 重置
  visible.value = false;
};
//分页改变事件
const change = (pagination, filters, sorter) => {
  emit("change", { pagination, filters, sorter });
};
const expand = (expanded, record) => {
  emit("expand", { expanded, record });
};
//自定义展开图标
const customIcon = (arg) => {
  if (
    arg.record.children?.length ||
    props.expandedRowRender == "expandedRowRender"
  ) {
    return h(RightOutlined, {
      class: arg.record.key + "expand",
      style: { transition: "all 0.3s", cursor: "pointer", padding: "5px" },
      onclick: async (e) => {
        let dom = document.getElementsByClassName(arg.record.key + "expand")[0];
        arg.expanded
          ? (dom.style.cssText = "transform:rotateZ(0)")
          : (dom.style.cssText = "transform:rotateZ(90deg)");
        arg.onExpand(arg.record, e);
      },
    });
  } else {
    return h("span", { style: { display: "inline-block", with: "14px" } });
  }
};
</script>
<style lang="less" scoped>
.table-c {
  margin-top: 0.08rem;
}
.checked-item {
  margin-left: -24px;
}
.ant-checkbox-group {
  width: 100%;
}
.ant-checkbox-wrapper {
  padding: 2px 8px;
  margin-bottom: 0.1rem;
  border-radius: 4px;
  white-space: nowrap;
  width: 100%;
  &:hover {
    background: @table-head-set-bg;
  }
}
.ant-checkbox-wrapper-checked {
  background: @table-head-set-bg;
}
.pop-btn-box {
  display: flex;
  justify-content: space-between;
  .btn-right {
    .ok-btn {
      color: @btn-primary-color;
    }
  }
}
</style>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
2、在main.js中把组件全局上
import {
  createApp
} from 'vue';
import App from './App.vue';
import router from './router/index.js';
import store from './store';
import {
  changeSize
} from './utils/common.js';
import antd from 'ant-design-vue';
import tableBox from "@/components/tableBox.vue";
import 'ant-design-vue/dist/antd.less';
import './assets/common/style.less';
import 'nprogress/nprogress.css'

changeSize()
const app = createApp(App)
app.component('table-box', tableBox);
app.use(antd).use(router).use(store).mount('#app')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
3、在组件中的使用, 因为父子组件的生命周期的原因,所以使用v-if控制子组件的渲染
// index.vue
<table-box
  v-if="isShow"
  :columns="state.columns"
  :dataSource="state.tableData"
  :pagination="pagination"
  :rowSelection="rowSelection"
  @change="handleTableChange"
  :routerName="routerName"
>
	<template v-slot:expandedRowRender="{ record }">
      <span>{{ record }}</span>
  </template>
  <template #action="{ record }">
    <a-popover title="">
      <template #content>
        <div
          class="action-box"
          style="display: flex; flex-direction: column"
        >
          <a @click="handleEdit(true, record)">修改</a>
          <a @click="handleDel(record.id)" href="javascript:void(0)"
            >删除</a
          >
        </div>
      </template>
      <MenuOutlined />
    </a-popover>
  </template>
</table-box>
<script setup>
import { useRoute } from "vue-router";
const route = useRoute();
const routerName = ref(route.name);
const isShow = ref(false);
const expandedRowRender = ref("expandedRowRender");
const state = reactive({
 tableData: [],
 columns: [
   {
     title: "厂商名称",
     key: "firmName",
     dataIndex: "firmName",
     ellipsis: true,
   },
   {
     title: "简称",
     key: "abbreviation",
     dataIndex: "abbreviation",
     ellipsis: true,
   },
   {
     title: "地址",
     key: "address",
     dataIndex: "address",
     ellipsis: true,
   },
   {
     title: "联系人",
     key: "liaison",
     dataIndex: "liaison",
   },
   {
     title: "联系电话",
     key: "liaisonPhone",
     dataIndex: "liaisonPhone",
     ellipsis: true,
   },
   {
     key: "action",
     isSlot: true,
     slots: {
       customRender: "action",
     },
   },
 ],
 selectedRowKeys: [],
});
const getTableData = (formData) => {
  for (let i = 0; i < 12; i++) {
    state.tableData.push({
      id: i,
      key: i,
      firmName: "江苏汇水创",
      abbreviation: "汇水创",
      address: "高塘石",
      liaison: "陈辉",
      liaisonPhone: "1371507698",
    });
  }
};
const rowSelection = {
  onChange: (selectedRowKeys, selectedRows) => {
    state.selectedRowKeys = selectedRowKeys;
    console.log(
      `selectedRowKeys: ${selectedRowKeys}`,
      "selectedRows: ",
      selectedRows
    );
  },
};
// 切换页
const handleTableChange = (page, filters, sorter) => {
  pagination.current = page.current;
  pagination.pageSize = page?.pageSize;
  // console.log(filters); // 选中值为数组(单选直接拿第一项,多选把数组转化成字符串拼接 - 看后台需要什么数据结构)
  if (filters.type) {
    // 必须判断,未操作切换页会报错(无type属性)
    formData.type = filters.type[0];
  }
  getTableData(formData);
};
onMounted(async () => {
 // 判断是否已经设置过表头,有则使用
  if (
    sessionStorage.tableHeadObj &&
    JSON.parse(sessionStorage.tableHeadObj)[routerName.value]
  ) {
    let arr = JSON.parse(sessionStorage.tableHeadObj)[routerName.value];
    for (let i = 0; i < state.columns.length; i++) {
      if (arr.indexOf(state.columns[i].key) == -1) {
        state.columns[i].isShow = false;
      }
    }
    isShow.value = true;
  } else {
    isShow.value = true;
  }
  getTableData(formData);
});
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
4、表头数据vuex + sessionStorage (key为路由的名称 – 唯一性)
// store.js
import {
  createStore
} from "vuex";
export default createStore({
  state: {
    tableHeadObj: sessionStorage.tableHeadObj ? JSON.parse(sessionStorage.tableHeadObj): {}
  },
  mutations: {
    setTableHeadObj(state, obj) {
      state.tableHeadObj = obj;
      sessionStorage.tableHeadObj = JSON.stringify(state.tableHeadObj);
    }
  }
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
5、效果:

![在这里插入图片描述](https://img-blog.csdnimg.cn/c7db7b608e494f2390983242dca63207.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5b-D6Iul5ZCR6ZizKCrvv6PvuLbvv6Mp,size_20,color_FFFFFF,t_70,g_se,x_16
在这里插入图片描述
在这里插入图片描述

后来者居上:脾气都给了前者,耐心都给了后者

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/897047
推荐阅读
相关标签
  

闽ICP备14008679号