vue3封装elementui组件table

239 阅读1分钟
<!-- 子组件 -->
<template>
  <div>
    <!-- form -->
    <el-form inline :model="state.formData" :rules="state.formRules" ref="form">
      <el-form-item v-for="item in formItems" :key="item.prop" :label="item.label" :prop="item.prop">
        <template v-if="item.type === 'input'">
          <el-input v-model="state.formData[item.prop]" :placeholder="item.placeholder" :disabled="item.disabled" :style="{width: item.width, marginLeft: item.marginLeft}" />
        </template>
        <template v-else-if="item.type === 'select'">
          <el-select :style="{width: item.width}" v-model="state.formData[item.prop]" :value="'male'" :placeholder="item.placeholder" :disabled="item.disabled">
            <el-option v-for="option in item.options" :key="option.value" :label="option.label" :value="option.value" />
          </el-select>
        </template>
        <template v-else-if="item.type === 'date'">
          <el-date-picker
            v-model="state.formData[item.prop]"
            type="daterange"
            range-separator="To"
            start-placeholder="Start date"
            end-placeholder="End date"
            :style="{width: item.width, marginLeft: item.marginLeft}"
            :default-value="[new Date('2023-00-00-00'), new Date('2023-10-00-00')]"
          />
        </template>
        <template v-else-if="item.type === 'btn'" >
            <el-button v-for="(btn, i) in item.btnArr"  :key="btn.id" size:small :type="btn.color" @click="formBtnClick(btn, i)">{{
              btn.label }}</el-button>
          </template>
      </el-form-item>
    </el-form>


    <!-- table -->
    <el-table border :data="tableData" :loading="loading" @selection-change="handleSelectionChange">
      <el-table-column v-if="showCheckbox" type="selection" width="55">
      </el-table-column>
      <el-table-column v-for="(column, index) in columns" :key="column.prop" :label="column.label" :width="column.width">
        <template #default="{ row }">
          <!-- input -->
          <template v-if="column.type === 'input'">
            <el-input v-model="row[column.prop]" />
          </template>
          <!-- select -->
          <template v-else-if="column.type === 'select'">
            <el-select v-model="row[column.prop]">
              <el-option v-for="option in column.options" :key="option.value" :label="option.label"
                :value="option.value" />
            </el-select>
          </template>
          <!-- btn -->
          <template v-else-if="column.type === 'btn'" >
            <el-button style="width: 50px;" v-for="btn in column.btnArr"  :key="btn.id" size:small text :type="btn.color" @click="tableBtnClick(btn, row)">{{
              btn.label }}</el-button>
          </template>
          <!-- 默认 -->
          <template v-else>
            {{ row[column.prop] }}
          </template>
        </template>
      </el-table-column>
    </el-table>
    <el-pagination v-if="pagination" :current-page="pagination.currentPage" :page-size="pagination.pageSize"
      :total="pagination.total" @current-change="handlePageChange" />
  </div>
</template>

<script setup>
import { ref, reactive } from 'vue';

const props = defineProps(['columns', 'tableData', 'loading', 'pagination', 'showCheckbox', 'selectedRows', 'formItems'],
  {
    // 参数校验函数
    columns: {
      type: Array,
      required: true,
      validator: (value) => {
        // 在这里进行自定义的校验逻辑
        // 返回 true 表示校验通过,返回 false 表示校验不通过
        // 例如,你可以检查 columns 是否是一个数组,并且其中的每个元素是否具有正确的结构
        return Array.isArray(value) && value.every(item => item.prop && item.label && (item.type === 'input' || item.type === 'select' || item.type === 'btn'))
      }
    },
    tableData: {
      type: Array,
      required: true,
      default: () => []
    },
    loading: {
      type: Boolean,
      default: false,
    },
    pagination: {
      type: Object,
      default: () => ({
        currentPage: 1,
        pageSize: 10,
        total: 0,
      }),
      validator: (value) => {
        // 在这里进行自定义的校验逻辑
        // 返回 true 表示校验通过,返回 false 表示校验不通过
        // 例如,你可以检查 pagination 是否具有正确的结构和值的范围是否合理
        return value.currentPage > 0 && value.pageSize > 0 && value.total >= 0
      }
    },
    showCheckbox: {
      type: Boolean,
      default: false,
    },
    selectedRows: {
      type: Array,
      default: () => [],
      validator: (value) => {
        // 在这里进行自定义的校验逻辑
        // 返回 true 表示校验通过,返回 false 表示校验不通过
        // 例如,你可以检查 selectedRows 是否是一个数组,并且数组中的元素是否符合你的预期
        return Array.isArray(value) && value.every(item => typeof item === 'object' && item !== null)
      }
    }
  }
)


const state = reactive({
  formData: {},
  formRules: {}
})


const formBtnClick = (item) => {
  if (item.label === '提交') {
    emit('formSubmit', state.formData);
  } else {
    onReset()
    emit('formReset', state.formData);
  }
};

const onReset = () => {
  state.formData = {}
  emit('reset');
};

for (const item of props.formItems) {
  state.formData[item.prop] = item.value || ''; // 将默认值加入到formData中
  state.formRules[item.prop] = item.rules || [];
}

const emit = defineEmits()

// const internalSelectedRows = ref([...props.selectedRows])

const handlePageChange = (page) => {
  emit('page-change', page)
}

const handleSelectionChange = (selectedRows) => {
  emit('update:selected-rows', selectedRows)
}

const tableBtnClick = (btn, rowData) => {
  emit('tableBtnClick', btn, rowData)
}
</script>

<!-- /*
 *                        _oo0oo_
 *                       o8888888o
 *                       88" . "88
 *                       (| -_- |)
 *                       0\  =  /0
 *                     ___/`---'\___
 *                   .' \\|     |// '.
 *                  / \\|||  :  |||// \
 *                 / _||||| -:- |||||- \
 *                |   | \\\  - /// |   |
 *                | \_|  ''\---/''  |_/ |
 *                \  .-\__  '-'  ___/-. /
 *              ___'. .'  /--.--\  `. .'___
 *           ."" '<  `.___\_<|>_/___.' >' "".
 *          | | :  `- \`.;`\ _ /`;.`/ - ` : | |
 *          \  \ `_.   \_ __\ /__ _/   .-` /  /
 *      =====`-.____`.___ \_____/___.-`___.-'=====
 *                        `=---='
 *
 *
 *      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 *            佛祖保佑       永不宕机     永无BUG
 */ -->

 <!-- 使用方法 -->

 <template>
  <div>
    <TableComponent
        :formItems="state.formItems"
        :columns="state.colums"
        :tableData="state.tableData"
        :loading="state.loading"
        :pagination="state.pagination"
        :showCheckbox="state.showCheckbox"
        :selectedRows="state.selectedRows"
        @formSubmit="onSubmitHandler"
        @formReset="onResetHandler"
        @tableBtnClick="tableBtnClick"
        @page-change="handlePageChange"
        @update:selected-rows="handleSelectedRowsUpdate"
      />
  </div>
</template>

<script setup>
import TableComponent from '@/components/table/table.vue';
import { reactive, onMounted } from 'vue';

const state = reactive({
    formItems: [
      {
        type: 'select', prop: 'a', value: 0, options: [
          { label: 0, value: 0 },
          { label: 1, value: 1 }
        ],
        width: '200px'
      },
      { type: 'input', prop: 'a', marginLeft: '-12px' },
      {
        type: 'select', label: '1', prop: 'a', value: '', options: [
          { label: '全部', value: '' },
          { label: '1', value: 0 },
          { label: '2', value: 1 },
        ],
        width: '200px'
      },
      {
        type: 'select', prop: 'b', value: '', options: [
          { label: '1', value: '' },
          { label: '1', value: 1 }
        ],
        width: '200px'
      },
      {
        prop: 'date', type: 'date',
        defaultValue: [new Date(2023, 0, 1), new Date(2023, 1, 1)], marginLeft: '-12px'
      },
      {
        type: 'select', label: '1', prop: 'b1', value: '', options: [
          { label: '1', value: '' },
          { label: '2', value: 0 },
          { label: '3', value: 1 },
        ],
        width: '200px'
      },
      {type: 'btn', btnArr: [
        {label: '提交', color: 'primary', id: 0},
        {label: '重置', color: 'primary', id: 1},
      ]}
  ],
  colums: [
    { prop: 'name', label: '1', width: '120' },
    { prop: 'age', label: '1', width: '120' },
    { prop: 'age', label: '1', width: '120' },
    { prop: 'age', label: '1', width: '120' },
    { prop: 'age', label: '1111\n222', width: '120' },
    {
      prop: 'age', label: '操作', type: 'btn', width: '300', btnArr: [
        {
          label: '22',
          color: 'primary',
          id: 0
        },
        {
          label: '22',
          color: 'success',
          id: 1
        },
        {
          label: '11',
          color: 'primary',
          id: 2
        },
      ]
    },
  ],
  tableData: [],
  loding: false,
  pagination: {
    currentPage: 1,
    pageSize: 1,
    total: 0,
  },
  selectedRows: [],
  dummyData: [
    { name: 'John Doe', age: 25, gender: 0 },
    { name: 'Jane Smith', age: 30, gender: 1 },
  ]
})

onMounted(() => {
  loadData()
})

const onSubmitHandler = (formData) => {
  console.log('Form submitted!', formData);
  // Your custom logic to handle form submit event
};

const onResetHandler = (formData) => {
  console.log('Form reset!', formData);
  // Your custom logic to handle form reset event
};

const loadData = () => {
  state.loading = true;
  setTimeout(() => {
    const startIndex = (state.pagination.currentPage - 1) * state.pagination.pageSize;
    const endIndex = startIndex + state.pagination.pageSize;
    const newData = state.dummyData.slice(startIndex, endIndex);
    state.tableData = newData;
    state.loading = false;
    // 更新pagination的total属性
    state.pagination.total = state.dummyData.length;
  }, 1000);
};

const handlePageChange = (page) => {
  state.pagination.currentPage = page;
  loadData();
};

const tableBtnClick = item => {
  console.log('当前点击的按钮', item);
}

const handleSelectedRowsUpdate = (selectedRows) => {
  selectedRows = selectedRows;
  console.log('选中的数据', selectedRows);
};
</script>