Vue项目开发 筛选组件跟表格组件结合使用,从此做一个cv工程师---水文

Vue项目开发 筛选组件跟表格组件结合使用,从此做一个cv工程师

不难发现后台管理系统列表页面长得基本都一样(特殊的不考虑),上面是筛选,下面是表格,表格下面是分页,然后在某个位置整几个按钮。


Vue项目开发 筛选组件跟表格组件结合使用,从此做一个cv工程师---水文_第1张图片


就以上面图片来说,其实可以分为四部分, 筛选 操作按钮 表格 分页

筛选组件

筛选组件常见的控件就是 输入框 下拉框 日期 ,当然也有公司内部的一些 人员选择框 部门选择框 ,其实都一样,我们试想一下,如果我们的项目里面有20个列表,每个列表里面都有4~5个筛选条件, 那我们可能会写好一份筛选的标签,进行拷贝然后修改,再想想,突然有一天老大告诉你,每一个列表都要加一个xxx筛选条件,怎么办?这样只能硬着头皮复制粘贴20次。作为一个有含量的 cv程序猿 肯定是不能这么玩的,在开发之前就要想到这些问题,应该怎么预防这些问题。
那么问题来了,我们怎么去封装筛选组件?当然在封装的时候可以根据项目的需求去进行封装,下面就开始说一下我的逻辑(不喜勿喷,不是最好,但是很香)

组件代码

g-table-filter

<template>
  <div class="table-filter">
    <el-row class="g-row" :gutter="20">
      <slot name="prefix">slot>
      <el-col
        v-for="(val, index) in data"
        :key="index"
        :xl="8"
        :lg="8"
        :md="12"
        :sm="12"
        :xs="24"
      >
        <div class="g-item">
          <p class="g-label ellipsis" :title="val.name">{{ val.name }}p>
          <component
            :is="val.type"
            :info="val"
            size="mini"
          />
        div>
      el-col>
    el-row>
    <div class="g-filter-btns">
      <div class="btns">
        <el-button size="mini" type="primary" icon="el-icon-search" @click="handleQuery">查询el-button>
        <el-button size="mini" type="primary" plain icon="el-icon-refresh" @click="handleReset">重置el-button>
      div>
    div>
  div>
template>

<script>
import {
  GInput,
  GDate,
  GSelect
} from '../types'
export default {
  name: 'TableFilter',
  components: {
    GInput,
    GDate,
    GSelect
  },
  props: {
    data: {
      type: Array,
      default: () => {
        return []
      }
    },
    // 是否有根据app进行查询 默认是有app查询
    isApp: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      arrowStatus: false
    }
  },
  mounted() {
    if (this.isApp) {
      this.$store.dispatch('getAuitSuccessAppList').then(res => {
        if (res.code === 0) {
          this.data.unshift({
            name: '所属应用',
            type: 'g-select',
            value: '',
            model: 'appId',
            placeholder: '请选择所属应用',
            options: {
              list: res.data.map(item => {
                return { label: item.name, value: item.appId }
              })
            }
          })
        } else {
          this.$message.error(res.message)
        }
      })
      .catch(err => {
        console.log(err)
      })
    }
  },
  methods: {
    // 查询
    handleQuery() {
      const params = {}
      this.data.forEach(item => { 
        switch (item.type) {
          case 'g-date':
            // 该版本先考虑范围查询
            if (item.value && item.value.length > 0) {
              params['beginTime'] = item.value[0]
              params['endTime'] = item.value[1]
            } else {
              params['beginTime'] = ''
              params['endTime'] = ''
            }
            break
          default:
            // 并未考虑下拉框多选的情况
            params[item.model] = item.value === undefined ? '' : item.value
            break
        }
      })
      this.$emit('on-query', { ...params, pageNum: 1, pageSize: 10 })
    },

    // 重置
    handleReset() {
      this.$emit('on-reset')
      this.data.forEach(val => { val['value'] = '' })
      this.$parent.getResetTableData()
    }
  }
}
script>

<style lang="scss">
@import "./index.scss";
style>

g-input

<template>
  <el-input
    v-model="info.value"
    class="g-input"
    :placeholder="info.placeholder"
    :size="size"
  />
template>

<script>
export default {
  name: 'GInput',
  props: {
    info: {
      type: Object,
      default: () => {
        return {}
      }
    },
    size: {
      type: String,
      default: 'mini'
    }
  }
}
script>

思路

先看 g-table-filter 组件代码,核心就是 component 根据传过来的数据进行动态寻找相应的组件,当然代码里面内置了开始时间,结束时间的逻辑,因为项目需求,所有查询都要有这玩意,这不是重点。然后看查询方法,其实查询方法里面可以直接去调用父组件里面的查询方法,这边就是往外暴露了一个 自定义事件 这样主要是为了可以更灵活的对数据去做特殊的处理,重置方法就没啥了,把组件的数据清空,然后直接查询列表就OK了, this.$parent.getResetTableData() 很灵魂,为什么要这么使用,下面会讲到。

使用方式

可以封装成npm包

  • template
<table-filter 
 :data="filterData" 
 @on-query="handleQuery" 
 @on-reset="handleReset"
 :isApp="false">
  
  <template v-slot:prefix>
    <el-col :xl="8" :lg="8" :md="12" :sm="12" :xs="24">
      <div class="g-item">
        <p class="g-label ellipsis">开发者p>
        <el-select size="small" style="width: 100%" placeholder="请选择开发者" v-model="filterParams.developerId" @change="handleChange">
          <el-option v-for="val in developerList" :key="val.developerId" :label="val.name" :value="val.developerId">el-option>
        el-select> 
      div>
    el-col>
    <el-col :xl="8" :lg="8" :md="12" :sm="12" :xs="24">
      <div class="g-item">
        <p class="g-label ellipsis">所属应用p>
        <el-select size="small" style="width: 100%" placeholder="请选择开发者" v-model="filterParams.appId">
          <el-option v-for="val in appList" :key="val.appId" :label="val.name" :value="val.appId">el-option>
        el-select>
      div>
    el-col>
  template>
table-filter>
  • js

看上面代码可以发现,筛选组件需要接收一个数组,下面就是关于数组的一些属性配置

filterData: [
  {
    name: '企业名称',              // label名称
    model: 'userName',            // key
    value: '',                    // value 传给后台的值
    placeholder: '请输入企业名称', 
    type: 'g-input'               // 组件类型
  },
  {
    name: '企业状态',
    model: 'status',
    value: '',
    placeholder: '请选择企业状态',
    type: 'g-select',
    options: {                    // 复杂组件的一些特殊配置,根据实际请款不过
      list: [
        { label: '正常', value: 1 },
        { label: '锁定', value: 2 },
        { label: '注销', value: 0 }
      ]
    }
  },
  {
    name: '创建时间',
    model: 'date',
    value: '',
    placeholder: '请选择创建时间',
    type: 'g-date',
    options: {
      type: 'date'
    }
  }
]

表格组件

表格组件的思路就是,表格跟筛选进行结合封装成一个组件,具体的还是看下面代码。

<template>
  <div class="page-table-card" v-loading="loading">
    <div class="top-action">
      <slot name="top-action" />
    div>
    <el-table stripe :data="tableData" border @selection-change="handleSelectionChange">
      <template slot="empty">
        <NoData />
      template>
      <el-table-column type="selection" align="center" header-align="center" width="55" />
      <slot />
    el-table>

    <el-pagination
      v-if="isPagination"
      class="pagination"
      :current-page.sync="current"
      :page-sizes="[10, 30, 40, 50]"
      layout="total, sizes, prev, pager, next, jumper"
      :total="total"
      :page-size="10"
      background
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
    />
  div>
template>

<script>
export default {
  name: 'PageTableCard', 
  props: {
    tableData: {
      type: Array,
      default: () => {
        return []
      }
    },
    
    total: {
      type: [Number, String],
      default: 0
    },
    
    // 是否支持分页
    isPagination: {
      type: Boolean,
      default: true
    },
    
    loading: {
      type: Boolean,
      default: false
    },

    // 数据的主键key
    rowIdKey: {
      type: String,
      default: 'id'
    }
  },
  data() {
    return {
      current: 1
    }
  },
  methods: {
    handleSizeChange(size) {
      this.$emit('on-size', size)
    },
    
    handleCurrentChange(page) {
      this.$emit('on-page', page)
    },

    // 列表选中的数据
    handleSelectionChange(rows) {
      this.$emit('on-check-row', rows.map(item => item[this.rowIdKey]))
    }
  }
}
script>

<style lang="scss">
@import './index';
style>

你可能感兴趣的:(前端,vue)