vue2中的简单表单和表格封装

因为我有一个这样的表单,然后我很多页面都是一样的,所以我会将他封装为一套代码进行复用。

封装的代码如下:

<!-- NavForm.vue 头部搜索框的封装-->
<template>
  <el-form :inline="true" :model="searchInfo" class="demo-form-inline" @keyup.enter.native="onSubmit">
    <el-form-item
        v-for="item in searColumns"
        :key="item.model + item.label"
        :label-width="item.labelWidth"
    >
      <el-input v-if="item.type === 'input'" v-model="searchInfo[item.model]" :placeholder="item.placeholder"
                clearable></el-input>
      <el-select v-if="item.type === 'select'" v-model="searchInfo[item.model]" :placeholder="item.placeholder"
                 clearable>
        <el-option v-for="val in item.options" :key="val.value" :label="val.label" :value="val.value"></el-option>
      </el-select>

      <el-button v-if="item.type==='onSubmit'" icon="el-icon-search" type="primary" @click="onSubmit">查询
      </el-button>

      <el-button v-if="item.type==='onReset'" @click="onReset">重置</el-button>
    </el-form-item>

    <el-form-item
        style="float: right"
        v-for="item in searColumns"
        :key="item.model"
        :label-width="item.labelWidth"
    >
      <el-button v-if="item.type === 'add'" icon="el-icon-plus" type="primary" @click="addSubmit">{{ item.label }}
      </el-button>
    </el-form-item>
  </el-form>
</template>

<script>
export default {
  props: {
    searColumns: {
      type: Array,
      required: true,
      default: () => []
    }
  },
  data() {
    return {
      searchInfo: {}
    };
  },
  methods: {
    onSubmit() {
      this.$emit('submit', this.searchInfo);
    },
    onReset() {
      this.searchInfo = {};
      this.$emit('reset');
    },
    addSubmit() {
      this.$emit('addSubmit',);
    },
  }
};
</script>

表单的使用:

<!--其中的searColumns搜索框的配置,submit为提交,reset为重置-->
      <NavForm
    :searColumns="searColumns"
    @submit="onSubmit"
    @reset="NoSubmit"
></NavForm>

<!--如何引入-->
import NavForm from "@/admin/components/NavForm.vue";

<!--searColumns搜索框的配置实例 其中需要输入框type为input select为下拉框-->
searColumns: [
{placeholder:'同步项ID', model: 'datasync_id',type: 'input'},
{placeholder: '状态', model: 'status',type: 'select', options: this.typeOptions}
],

<!--onSubmit需要获取子组件的数据 val用来赋值给父组件-->
onSubmit(val) {
this.page = 1;
if (this.searchInfo.datasync_id === "") {
this.searchInfo.datasync_id = null;
}
this.searchInfo = val;
this.GetSyncRecordList();
},

<!--上面的searColumns如果没有正确的拿到数据那么需要在mounted中赋值,示例:-->
mounted() {
this.searColumns = [
{placeholder:'同步项ID', model: 'datasync_id',type: 'input'},
{placeholder: '状态', model: 'status',type: 'select', options: this.typeOptions},
{type: 'onSubmit', label: '查询',},
{type: 'onReset', label: '重置',},
]
}

封装完了表单,那么我就开始封装表格了

表格的代码封装如下:

<template>
  <div>
    <el-table
        ref="multipleTable"
        :data="tableData"
        :header-cell-style="{ background: '#F5F7FA' }"
        tooltip-effect="dark"
        border
        @header-dragend="handleHeaderDragend"
        @selection-change="handleSelectionChange"
        :row-class-name="rowClassName"
    >
      <el-table-column
          type="selection"
          width="55">
      </el-table-column>
      <el-table-column
          v-for="column in columns"
          :key="column.prop"
          :prop="column.prop"
          :label="column.label"
          :width="column.width"
          :show-overflow-tooltip="column.showOverflowTooltip"
          :align="column.align"
      >
        <!-- 使用作用域插槽来自定义列的内容 -->
        <template v-slot="scope">
          <slot :name="`column-${column.prop}`" :row="scope.row">
            <!-- 这里是默认内容,当没有提供名为 `column-${column.prop}` 的插槽时显示 -->
            {{ scope.row[column.prop] }}
          </slot>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

<script>
export default {
  name: 'CommonTable',
  props: {
    tableData: {
      type: Array,//类型
      required: true,//必填
      default: () => []
    },
    columns: {
      type: Array,//类型
      required: true,//必填
      default: () => []
    }
  },
  data() {
    return {
      selectedRows: [] // 添加这一行
    }
  },
  methods: {
    // 选中的行
    handleSelectionChange(selection) {
      this.selectedRows = selection; // 更新被选中的行
      // console.log(selection,'selection');
    },
    // 改变选中行的颜色
    rowClassName({ row }) {
      if (this.selectedRows.includes(row)) {
        return 'row-selected';
      }
      return '';
    },
    // 拖拽表单自定义宽度的方法
    handleHeaderDragend(newWidth, oldWidth, column, event) {
      console.log(newWidth, oldWidth, column, event, 'newWidth, oldWidth, column, event')
      // console.log(this.$route.name, '$route.name')
      const columnKey = column.property;
      const columnWidths = JSON.parse(localStorage.getItem(`${this.$route.name}-columnWidths`)) || {};
      columnWidths[columnKey] = newWidth;
      localStorage.setItem(`${this.$route.name}-columnWidths`, JSON.stringify(columnWidths));
    },
    applyColumnWidths(columns) {
      // 应用列宽度的逻辑
      const columnWidths = JSON.parse(localStorage.getItem(`${this.$route.name}-columnWidths`)) || {};
      columns.forEach((column) => {
        if (columnWidths[column.prop]) {
          column.width = columnWidths[column.prop];
        }
      });
    }
  },
  watch: {
    columns: {
      immediate: true,
      handler(newColumns) {
        this.applyColumnWidths(newColumns);
      }
    }
  },
  mounted() {
    this.$nextTick(() => {
      // 应用列宽度的逻辑// 获取自定义宽度的方法
      const columnWidths = JSON.parse(localStorage.getItem(`${this.$route.name}-columnWidths`)) || {};
      this.columns.forEach((column) => {
        if (columnWidths[column.prop]) {
          column.width = columnWidths[column.prop];
        }
      });
    });
  },
  beforeDestroy() {
    // 保存自定义宽度的方法
    const columnWidths = {};
    this.$refs.multipleTable.columns.forEach((column) => {
      if (column.width) {
        columnWidths[column.property] = column.width;
      }
    });
    localStorage.setItem(`${this.$route.name}-columnWidths`, JSON.stringify(columnWidths));
  }
}
</script>

<style lang="scss">
//表格里面的边框颜色改为透明
.el-table__body-wrapper .el-table__row .el-table__cell {
  border-left-color: transparent !important;
  border-right-color:transparent !important ;
}
//选中行的颜色
.el-table .row-selected {
  background: #F5FAFA;
}
</style>

使用方法如下:

    <CommonTable
    :tableData="tableData"
    :columns="tableColumns"
    >
<!--个性化的插槽,比如给category_id添加一个tag -->
        <template v-slot:column-category_id="{ row }">
          <el-tag>{{ row.category_id }}</el-tag>
        </template>

<!--  个性化操作栏,比如我需要一个查看修改删除的操作栏-->
         <template v-slot:column-actions="{ row }">
           <el-button type="text" @click="viewItem(row)">查看</el-button>
           <el-button type="text" @click = "deleteItem(row)" > 删除 </el-button>
           <el-button type="text" @click = "editItem(row)" > 修改 </el-button>
         </template>
    </CommonTable>

<!--如何引入-->
import CommonTable from "@/admin/components/CommonTable.vue";

<!--tableData示例:-->
tableData: [],
<!--获取参数值之后:-->
this.tableData = res.data.data即可

<!--tableColumns示例:-->
tableColumns: [
{label: '同步项ID', prop: 'datasync_id', width: 'auto', showOverflowTooltip: true},
{label: '状态', prop: 'status', width: 'auto', showOverflowTooltip: true},
{label: '失败原因', prop: 'reason', width: 'auto', showOverflowTooltip: true},
// {label: '操作', prop: 'actions', width: 'auto'}
],

  • 12
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
可以参考下面的代码,这是一个基于Vue 2.0和Element UI的表格和搜索条件的公共组件: ```vue <template> <div> <el-form v-if="showFilter" :inline="true" :model="filterForm" class="demo-form-inline"> <el-form-item v-for="item in filterItems" :label="item.label" :key="item.prop"> <el-input v-if="item.type === 'input'" v-model="filterForm[item.prop]" :placeholder="item.placeholder"></el-input> <el-select v-if="item.type === 'select'" v-model="filterForm[item.prop]" :placeholder="item.placeholder"> <el-option v-for="option in item.options" :key="option.value" :label="option.label" :value="option.value"></el-option> </el-select> </el-form-item> <el-form-item> <el-button type="primary" @click="filter">查询</el-button> <el-button @click="resetFilter">重置</el-button> </el-form-item> </el-form> <el-table :data="tableData" :columns="tableColumns" :highlight-current-row="highlightCurrentRow" :row-class-name="rowClassName" :row-style="rowStyle" :row-key="rowKey" :header-cell-style="headerCellStyle" :default-sort="defaultSort" :show-header="showHeader" :show-summary="showSummary" :sum-text="sumText" :summary-method="summaryMethod" :border="border" :stripe="stripe" :size="size" :fit="fit" :empty-text="emptyText" :loading="loading" :row-selection="rowSelection" :expand-row-keys="expandRowKeys" :tree-props="treeProps" @row-click="rowClick" @row-dblclick="rowDblclick" @current-change="currentChange" @select="select" @select-all="selectAll" @selection-change="selectionChange" @cell-mouse-enter="cellMouseEnter" @cell-mouse-leave="cellMouseLeave" @cell-click="cellClick" @cell-dblclick="cellDblclick" @header-click="headerClick" @header-contextmenu="headerContextmenu" @sort-change="sortChange" @filter-change="filterChange" @expand-change="expandChange" @select-toggle-all="selectToggleAll" @select-toggle-row="selectToggleRow" @row-contextmenu="rowContextmenu" @header-dragend="headerDragend" @row-dragend="rowDragend" @row-dragenter="rowDragenter" @row-dragleave="rowDragleave" @row-dragover="rowDragover" @row-drop="rowDrop" ref="table"> <slot></slot> </el-table> <div v-if="showPagination" class="demo-pagination"> <el-pagination :page-size="pagination.pageSize" :total="pagination.total" :current-page.sync="pagination.currentPage" :page-sizes="[10, 20, 50, 100]" @size-change="handleSizeChange" @current-change="handleCurrentChange"></el-pagination> </div> </div> </template> <script> export default { name: 'TableWithFilter', props: { tableData: { type: Array, required: true }, tableColumns: { type: Array, required: true }, pagination: { type: Object, default: () => { return { pageSize: 10, total: 0, currentPage: 1 } } }, filterItems: { type: Array, default: () => [] }, showFilter: { type: Boolean, default: true }, showPagination: { type: Boolean, default: true }, highlightCurrentRow: Boolean, rowClassName: Function, rowStyle: [Object, Function], rowKey: [String, Function], headerCellStyle: [Object, Function], defaultSort: Object, showHeader: { type: Boolean, default: true }, showSummary: Boolean, sumText: String, summaryMethod: Function, border: Boolean, stripe: Boolean, size: String, fit: { type: Boolean, default: true }, emptyText: String, loading: Boolean, rowSelection: Object, expandRowKeys: Array, treeProps: Object }, data() { return { filterForm: {} } }, methods: { filter() { this.$refs.table.setCurrentRow(null) this.$emit('filter', this.filterForm) }, resetFilter() { this.filterForm = {} this.filter() }, handleSizeChange(val) { this.$emit('size-change', val) }, handleCurrentChange(val) { this.$emit('current-change', val) }, rowClick(row, column, event) { this.$emit('row-click', row, column, event) }, rowDblclick(row, event) { this.$emit('row-dblclick', row, event) }, currentChange(currentRow, oldCurrentRow) { this.$emit('current-change', currentRow, oldCurrentRow) }, select(selection, row) { this.$emit('select', selection, row) }, selectAll(selection) { this.$emit('select-all', selection) }, selectionChange(selection) { this.$emit('selection-change', selection) }, cellMouseEnter(row, column, cell, event) { this.$emit('cell-mouse-enter', row, column, cell, event) }, cellMouseLeave(row, column, cell, event) { this.$emit('cell-mouse-leave', row, column, cell, event) }, cellClick(row, column, cell, event) { this.$emit('cell-click', row, column, cell, event) }, cellDblclick(row, column, cell, event) { this.$emit('cell-dblclick', row, column, cell, event) }, headerClick(column, event) { this.$emit('header-click', column, event) }, headerContextmenu(column, event) { this.$emit('header-contextmenu', column, event) }, sortChange({ column, prop, order }) { this.$emit('sort-change', { column, prop, order }) }, filterChange(filters) { this.$emit('filter-change', filters) }, expandChange(row, expandedRows) { this.$emit('expand-change', row, expandedRows) }, selectToggleAll(selection) { this.$emit('select-toggle-all', selection) }, selectToggleRow(row, selected) { this.$emit('select-toggle-row', row, selected) }, rowContextmenu(row, event) { this.$emit('row-contextmenu', row, event) }, headerDragend(newWidth, oldWidth, column, event) { this.$emit('header-dragend', newWidth, oldWidth, column, event) }, rowDragend(newIndex, oldIndex, row, event) { this.$emit('row-dragend', newIndex, oldIndex, row, event) }, rowDragenter(dropPosition, drag, event) { this.$emit('row-dragenter', dropPosition, drag, event) }, rowDragleave(dropPosition, drag, event) { this.$emit('row-dragleave', dropPosition, drag, event) }, rowDragover(dropPosition, drag, event) { this.$emit('row-dragover', dropPosition, drag, event) }, rowDrop(dropPosition, drag, event) { this.$emit('row-drop', dropPosition, drag, event) } } } </script> <style scoped> .demo-form-inline .el-form-item { margin-right: 20px; } .demo-pagination { margin-top: 20px; text-align: right; } </style> ``` 使用方法: ```vue <template> <div> <table-with-filter :table-data="tableData" :table-columns="tableColumns" :pagination="pagination" :filter-items="filterItems"></table-with-filter> </div> </template> <script> import TableWithFilter from '@/components/TableWithFilter' export default { components: { TableWithFilter }, data() { return { tableData: [], tableColumns: [{ prop: 'name', label: '名称' }, { prop: 'age', label: '年龄' }], pagination: { pageSize: 10, total: 0, currentPage: 1 }, filterItems: [{ prop: 'name', label: '名称', placeholder: '请输入名称', type: 'input' }, { prop: 'age', label: '年龄', placeholder: '请选择年龄', type: 'select', options: [{ label: '18岁以下', value: '<=18' }, { label: '19-30岁', value: '19-30' }, { label: '31岁以上', value: '>=31' }] }] } }, methods: { fetchData() { // 获取数据并更新tableData和pagination.total }, handleFilter(params) { // 处理搜索条件 }, handleSizeChange(size) { this.pagination.pageSize = size this.fetchData() }, handleCurrentChange(page) { this.pagination.currentPage = page this.fetchData() } } } </script> ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值