Vue封装通用table组件的完整步骤记录

目录
  • 前言
  • 为什么需要封装table组件?
  • 第一步:定义通用组件
  • 第二步:父组件与子组件进行render通信
  • 第三步:使用组件
  • 总结

前言

随着业务的发展和功能的增多,我们发现不少页面都具备相似的功能,这里举几个比较俗的例子:可以多选的下拉菜单,带输入的对话框,日期选择器等等,于是我们会想办法将这些共有的功能抽取成一个个公共组件,以便能够在不同的页面或业务中使用。

为什么需要封装table组件?

后台管理系统表格使用频率高,减少关于table的业务代码,且便于后期统一修改、便于后期维护。如给table内容展示,超出单元格以省略号展示等。

对于大部分的后台管理系统,数据表格的展示大同小异,由于不想写重复的代码,所以我选择封装通用table组件,解放双手。如果你的表格有一列并不是简单dom元素,比如switch按钮,完全可以传入一个render函数,来达到目的。

第一步:定义通用组件

<!-- pro-table.vue -->
<template>
  <div>
    <el-table
      :data="tableData"
      style="width: 100%"
      :stripe="tableTitle.stripe"
      :border="tableTitle.border"
      :fit="tableTitle.fit"
      :highlight-current-row="tableTitle.highlightCurrentRow"
      @selection-change="handleSelectionChange">
      <!--表格第一列-->
      <el-table-column
        :type="firstTableCol.type"
        :width="firstTableCol.width"
        v-if="firstTableCol.select"
      >
      </el-table-column>
      <!--表格其它列-->
      <el-table-column v-for="(value,index) in tableCol" :key="index"
                       :prop="value.prop"
                       :label="value.label"
                       :width="value.width || 180">
        <template slot-scope="scope">
          <template v-if="!value.render">
            <template v-if="value.formatter">
              {{ value.formatter(scope.row, value) }}
            </template>
            <template v-else-if="value.getImgurl">
              <el-image :src="value.getImgurl(scope.row, value)" style="width: 70px; height: 70px"
                        :preview-src-list="value.previewSrcList ? value.previewSrcList(scope.row, value) : value.getImgurl(scope.row, value).split(',')"/>
            </template>
            <template v-else>
              {{ scope.row[value.prop] }}
            </template>
          </template>
          <!--扩展dom-->
          <template v-else>
            <Table :key="`cus${index}`" :render="value.render" :param="scope.row"></Table>
          </template>
        </template>
      </el-table-column>
      <!--基础操作-->
      <el-table-column label="操作">
        <template slot-scope="scope">
          <el-button type="text" v-for="(value,index) in operator" @click="value.click(scope.row, value)" :key="index">
            {{ value.text }}
          </el-button>
        </template>
      </el-table-column>
    </el-table>
    <!--分页插件-->
    <el-pagination
      v-show="total>0"
      :total="total"
      :page-size.sync="pageSize"
      :current-page.sync="currentPage"
      :page-sizes="[10, 20, 30, 50]"
      layout="total, sizes, prev, pager, next, jumper"
      @current-change="handleCurrentChange"
      @size-change="handleSizeChange"
      v-bind="$attrs">
    </el-pagination>
  </div>
</template>

<script>
// render函数
import Table from './table'
export default {
  components: {Table},
  props: {
    tableTitle: {
      type: Object,
      default: {
        stripe: false,
        border: false,
        fit: true,
        highlightCurrentRow: false
      }
    },
    firstTableCol: {
      type: Object,
      default: {
        select: false,
        width: 55,
        type: 'selection'
      }
    },
    tableCol: {
      type: Array,
      default: []
    },
    tableData: {
      type: Array,
      default: []
    },
    operator: {
      type: Array,
      default: []
    },
    total: {
      type: Number,
      default: 0
    },
    page: {
      type: Number,
      default: 1
    },
    limit: {
      type: Number,
      default: 10
    },
    autoScroll: {
      type: Boolean,
      default: true
    }
  },
  computed: {
    currentPage: {
      get () {
        return this.page
      },
      set (val) {
        this.$emit('update:page', val)
      }
    },
    pageSize: {
      get () {
        return this.limit
      },
      set (val) {
        this.$emit('update:limit', val)
      }
    }
  },
  data () {
    return {
    }
  },
  methods: {
    // 监听table选择框
    handleSelectionChange (selection) {
      // 调用父组件对应的方法 handleSelectionChange
      this.$emit('handleSelectionChange', selection)
    },
    // 监听每页多少条数据(limit)
    handleSizeChange (limit) {
      this.$emit('pagination', {page: this.currentPage, limit: limit})
      if (this.autoScroll) {
        scrollTo(0, 800)
      }
    },
    // 监听当前是第几页(page)
    handleCurrentChange (page) {
      this.$emit('pagination', {page: page, limit: this.pageSize})
      if (this.autoScroll) {
        scrollTo(0, 800)
      }
    }
  }
}
</script>
<style scoped>
</style>

第二步:父组件与子组件进行render通信

为了实现父组件render函数在子组件中生效,我们需要定义一个render函数,在子组件中引用。

// table.js
export default {
  props: {
    render: {
      type: Function
    },
    param: {
      type: Object
    }
  },
  render(h) {
    return this.render(h, this.param)
  }
}

第三步:使用组件

<template>
  <div>
    <!--
        @自定义事件="父组件方法", 子组件中,this.$emit('自定义事件名称') 触发父组件事件。
        ref="proTable",标记在子组件上,指向子组件实例
    -->
    <proTable ref="proTable" :tableTitle="tableTitle" :tableCol="tableCol" :tableData="tableData" :operator="operator"
        :firstTableCol="firstTableCol"
        @handleSelectionChange="handleSelectionChange"
        :total="total" :page.sync="queryParams.page" :limit.sync="queryParams.limit" @pagination="getList"/>

  </div>
</template>

<script>
import proTable from './pro-table'

export default {
  components: {
    proTable
  },
  data() {
    return {
      queryParams: {
        page: 1,
        limit: 10,
      },
      type: 'success',
      total: 50,
      // element-ui中对table属性的设置
      tableTitle: {
        'stripe': true,
        "highlightCurrentRow": true
      },
      // 设置table的列
      tableCol: [
        { prop:'date',label:'日期'},
        { prop:'name',label:'姓名'},
        { prop:'address',label:'地址',width: 300},
        { prop:'src',label:'图片',
        getImgurl: (row, col, cellValue) => { return this.getImgurl(row)},
        previewSrcList: (row, col, cellValue) => {return this.listImgUrl(row)}},
        { prop:'sex',label:'性别',
        formatter: (row, col, cellVaule) => {return this.sexFormatter(row)}},
        { prop:'src',label:'图片',
        getImgurl: (row, col, cellValue) => { return this.getImgurl(row)}},
        { prop:'text',label:'函数', render: (h, params) => {return  this.render(h, params)}}
      ],
      // table的基本操作
      operator: [
        {'text':'详情', click: (row, col, cellValue) => {return this.getInfo(row)}},
        {'text':'删除', click: (row, col, cellValue) => {return this.delInfo(row)}},
        {'text':'编辑', click: (row, col, cellValue) => {return this.editInfo(row)}},
      ],
      // 模拟数据
      tableData: [
        {
          date: '2016-05-02',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄',
          sex: 0,
          img:'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic2.zhimg.com%2F50%2Fv2-193cbb243dc14d3a016caaa54ba02837_hd.jpg&refer=http%3A%2F%2Fpic2.zhimg.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1628435704&t=deb5584cb9ff53fe6977f14a5e0755bb'
        }, {
          date: '2016-05-04',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1517 弄',
          sex: 1,
          img:'https://pic1.zhimg.com/80/v2-894ab624807fd4cfa33dd4e42cc90ac8_720w.jpg?source=1940ef5c'
        }, {
          date: '2016-05-01',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1519 弄',
          sex: 0,
          img:'xx.jpg'
        }, {
          date: '2016-05-03',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1516 弄',
          sex: 1,
          img:'xx.jpg'
        }],
      firstTableCol: {
        'select': true,
        'type': 'selection'
      }
    }
  },
  methods: {
    getInfo(val) {
      // 触发父方法
      console.log("获取详情",val)
    },
    delInfo(val) {
      // 触发父方法
      console.log("删除信息",val)
    },
    editInfo(val) {
      // 触发父方法
      console.log("编辑信息",val)
    },
    getImgurl(val) {
      console.log(val.img)
      return val.img
    },
    sexFormatter(val) {
      return val.sex === 0 ? '男' : '女'
    },
    handleSelectionChange(val) {
      console.log("监听选择框",val)
    },
    getList(queryParams) {
      console.log("父级方法",queryParams)
    },
    listImgUrl() {
      let array = [];
      array.push("https://pic1.zhimg.com/80/v2-894ab624807fd4cfa33dd4e42cc90ac8_720w.jpg?source=1940ef5c");
      array.push("https://cdn.pixabay.com/photo/2021/07/01/21/20/girl-6380331_960_720.jpg");
      return array;
    },
    render(h, params) {
      return h('span', null , '我是一个render组件')
    }
  }
}
</script>

总结

在引用组件的页面中,我们可以给每一个table列加方法,也可以给编辑、删除、详情添加自定义的方法,完全实现定制化。也可以自定义render函数。效果图如下:

到此这篇关于Vue封装通用table组件的文章就介绍到这了,更多相关Vue封装通用table组件内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 如何封装Vue Element的table表格组件

    在封装Vue组件时,我依旧会交叉使用函数式组件的方式来实现.关于函数式组件,我们可以把它想像成组件里的一个函数,入参是渲染上下文(render context),返回值是渲染好的HTML(VNode).它比较适用于外层组件仅仅是对内层组件的一次逻辑封装,而渲染的模板结构变化扩展不多的情况,且它一定是无状态.无实例的,无状态就意味着它没有created.mounted.updated等Vue的生命周期函数,无实例就意味着它没有响应式数据data和this上下文. 我们先来一个简单的Vue函数式组件

  • Vue封装一个简单轻量的上传文件组件的示例

    一.之前遇到的一些问题 项目中多出有上传文件的需求,使用现有的UI框架实现的过程中,不知道什么原因,总会有一些莫名其妙的bug.比如用某上传组件,明明注明(:multiple="false"),可实际上还是能多选,上传的时候依然发送了多个文件:又比如只要加上了(:file-list="fileList")属性,希望能手动控制上传列表的时候,上传事件this.refs.[upload(组件ref)].submit()就不起作用了,传不了.总之,懒得再看它怎么实现了,我

  • vue2.0 自定义组件的方法(vue组件的封装)

    一.前言 之前的博客聊过 vue2.0和react的技术选型:聊过vue的axios封装和vuex使用.今天简单聊聊 vue 组件的封装. vue 的ui框架现在是很多的,但是鉴于移动设备的复杂性,兼容性问题突出.像 Mint-UI 等说实话很不错了,但是坑也是不少,而且很多功能也是仅凭这些实现不了,这需要我们去封装自己的可复用组件 二.封装组件的步骤 1. 建立组件的模板,先把架子搭起来,写写样式,考虑你的组件的基本逻辑. os:思考1小时,码码10分钟,程序猿的准则. 2. 准备组件的好数据

  • 基于Vue如何封装分页组件

    使用Vue做双向绑定的时候,可能经常会用到分页功能 接下来我们来封装一个分页组件 先定义样式文件 pagination.css ul, li { margin: 0px; padding: 0px; } .page-bar { -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-se

  • 封装Vue Element的table表格组件的示例详解

    在封装Vue组件时,我依旧会交叉使用函数式组件的方式来实现.关于函数式组件,我们可以把它想像成组件里的一个函数,入参是渲染上下文(render context),返回值是渲染好的HTML(VNode).它比较适用于外层组件仅仅是对内层组件的一次逻辑封装,而渲染的模板结构变化扩展不多的情况,且它一定是无状态.无实例的,无状态就意味着它没有created.mounted.updated等Vue的生命周期函数,无实例就意味着它没有响应式数据data和this上下文. 我们先来一个简单的Vue函数式组件

  • 从零开始封装自己的自定义Vue组件

    想要封装好一个自己的vue组件,一定要熟练掌握这三个技能 父组件 -> 子组件传值(props) 子组件 -> 父组件传值($emit) 以及插槽(slot) 对于一个独立的组件来说 props是用来为组件内部注入核心的内容: $emit用来使这个独立的组件通过一些逻辑来融入其他组件中. 举个具体点的例子,假如你要做一辆车,车轮是要封装的一个独立组件,props指的就是根据整个车的外形你可以给轮子设置一些你想要的且符合车风格的花纹,图案等: 而$emit的作用则是让这些轮子能够和整辆车完美契合

  • vue弹出框组件封装实例代码

    新学vue,参考别人封装弹出层组件.好用! 1.你需要先建一个弹出框的模板: //首先创建一个mack.vue <template> <div class="mack" v-if="isShow"> <div class="mackWeb" :style="text.mackStyle"> <div class="title font_b" v-if="t

  • 在vue中封装可复用的组件方法

    本次封装的组件以toast组件为例 以前使用移动端ui插件时,通过一句代码比如 $.toast( ' 需要显示的内容 ' ),从而在页面上展示这段文字,并在一定时间后消失. 现在我们也尝试自己封装toast组件. 准备工作:vue-cli脚手架工程 先看一下涉及到的文件目录截图: 这次的封装主要涉及的文件是Toast.vue toast.js Hello.vue,主要思路如下: ① Toast.vue是我们要使用的toast组件: ② toast.js里面用Vue.extend()扩展一个组件构

  • Vue封装通用table组件的完整步骤记录

    目录 前言 为什么需要封装table组件? 第一步:定义通用组件 第二步:父组件与子组件进行render通信 第三步:使用组件 总结 前言 随着业务的发展和功能的增多,我们发现不少页面都具备相似的功能,这里举几个比较俗的例子:可以多选的下拉菜单,带输入的对话框,日期选择器等等,于是我们会想办法将这些共有的功能抽取成一个个公共组件,以便能够在不同的页面或业务中使用. 为什么需要封装table组件? 后台管理系统表格使用频率高,减少关于table的业务代码,且便于后期统一修改.便于后期维护.如给ta

  • Vue封装全局toast组件的完整实例

    目录 前言 一. 借助 vue-cli 1. 定义 Toast 组件 2. 在 main.js 里面配置 3. 在其他组件内使用 二.不借助 vue-cli 1. 注册 toast 组件 2. 注册 toast 插件 3. 在其他组件内使用 总结 前言 最近体验了下Vue,Toast都是前端常用组件,本文详细介绍了Vue封装全局toast组件的过程,下面话不多说了,来一起看看详细的介绍吧 一. 借助 vue-cli 1. 定义 Toast 组件 // components/Toast <temp

  • vue封装TabBar组件的完整步骤记录

    目录 实现思路: 步骤一:TabBar和TabBarItem的组件封装 步骤二:给TabBarItem传入active图片 步骤三:TabBarItem和路由的结合效果 步骤四:TabBarItem的颜色控制 用字体图标实现 引入字体图标 运用 总结 实现思路: 步骤一:TabBar和TabBarItem的组件封装 做到这,可以发现页面的基本布局已经实现了,但是item的点击活跃状态还没实现 步骤二:给TabBarItem传入active图片 为了防止替换的内容直接整个替换掉插槽,从而插槽上定义

  • vue3封装Notification组件的完整步骤记录

    目录 创建 插入 移除 在App.vue中使用 总结 跳过新手教程的小白,很多东西都不明白,不过是为了满足一下虚荣心,写代码的成就感 弹窗组件的思路基本一致:向body插入一段HTML.我将从创建.插入.移除这三个方面来说我的做法 先来创建文件吧 |-- packages |-- notification |-- index.js # 组件的入口 |-- src |-- Notification.vue # 模板 |-- notification.ts 创建 用到h,render,h是vue3对

  • Vue项目打包并发布的完整步骤记录

    目录 1.安装部署Nginx服务器.(类似Tomcat服务器) 2.Vue项目打包. 总结 如何将Vue项目打包并发布?我这边是测试发布到本地,不过步骤是一样的,步骤如下: 1.安装部署Nginx服务器.(类似Tomcat服务器) 说明:Nginx (engine x) 是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器.同时,也是一种轻量级的Web服务器,可以作为独立的服务器部署网站. (1)官方下载网址:http://nginx.org/ (2)下载之后,得到

  • vue 封装面包屑组件教程

    我看过一篇关于程序员写博客的文章,他说很多的程序员过了两年写了很多的代码,但是回想起来自己具体做了哪些技术点,遇到坑几乎没有印象,所以说文字是记录的最好方式,好记性不如烂笔头,可以方便自己以后查看,在写的过程中也会再加深一遍印象,我也来折腾折腾. 第一次写文章就写一个比较有意义的吧,18年四月末来到目前所在的这家公司,熟悉了一周环境和代码后,新的任务就是使用vue+element-ui来重构之前老版本的项目,我主要负责就是用户管理的一个模块,因为之前没有用过vue所以恶补了一周的vue了解了一些

  • vue封装可复用组件confirm,并绑定在vue原型上的示例

    如下所示: 首先我们需要创建 confirm.vue , confirm.js这两个文件,一个实现dom结构,一个实现相关逻辑 confirm.vue <template> <div class="confirm" v-if="isShow"> <div class="con_box" > <div class="context"> <h6>{{text.type}}

  • vue iview 隐藏Table组件里的某一列操作

    1.假设我要隐藏columns里的 "账户组名称" columns: [ { type: 'selection', width: 60, align: 'center' }, { title: '账号ID', key: 'accountIdString' }, { title: '账号名称', key: 'accountName' }, { title: '账户组名称', key: 'accountGroupName' }] 2.根据各自需求去判断 示例:如果是单账户表标题显示&quo

  • vue封装自定义分页器组件与使用方法分享

    前言 分页是开发各种系统时候最常用的功能,下面为本人封装的一个分页组件. 实现分页器操作需要以下参数 当前页: pageNo 每页展示条数: pageSize 数据总条数 : total 连续页码数:continues (一般为奇数,页面对称更美观) 分页器在各大项目中出现的频率较多,我们可以封装成静态组件,并全局注册这个组件. 1.全局注册组件方法:在mian.js文件中操作 import Pagination from '@/components/Pagination' // 组件路径 Vu

  • vue封装一个弹幕组件详解

    目录 前言 功能实现 1.获取随机颜色 随机数生成 随机颜色编码生成 2.随机生成弹幕出现的高度坐标 3.格式化弹幕对象 颜色 定位 4.创建弹幕对象 滚动动画定义 创建弹幕dom对象实例 弹幕销毁 弹幕循环 5.实时弹幕发送 html JavaScript 源码地址 前言 现在很多地方都有使用到弹幕,最近在捣鼓自己的个人博客网站,也想着在里面加入一个弹幕模块,所以在这里封装了一个可复用的弹幕组件,目前已经实现了基本的功能,可能还会有存在缺陷,后续会继续优化.这里给大家介绍分享一下实现的过程.

随机推荐