热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

如何封装VueElement的table表格组件

这篇文章主要介绍了如何封装VueElement的table表格组件,帮助大家更好的理解和使用vue框架,感兴趣的朋友可以了解下

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

我们先来一个简单的Vue函数式组件的例子吧,然后照着这个例子来详细介绍一下。

export default {
 functional: true,
 props: {},
 render(createElement, context) {
   return createElement('span', 'hello world')
 }
}

Vue提供了一个functional开关,设置为true后,就可以让组件变为无状态、无实例的函数式组件。因为只是函数,所以渲染的开销相对来说较小。

函数式组件中的Render函数,提供了两个参数createElement和context,我们先来了解下第一个参数createElement。

createElement说白了就是用来创建虚拟DOM节点VNode的。它接收三个参数,第一个参数可以是DOM节点字符串,也可以是一个Vue组件,还可以是一个返回字符串或Vue组件的函数;第二个参数是一个对象,这个参数是可选的,定义了渲染组件所需的参数;第三个参数是子级虚拟节点,可以是一个由createElement函数创建的组件,也可以是一个普通的字符串如:'hello world',还可以是一个数组,当然也可以是一个返回字符串或Vue组件的函数。

createElement有几点需要注意:

  • createElement第一个参数若是组件,则第三个参数可省略,即使写上去也无效;
  • render函数在on事件中可监听组件$emit发出的事件
  • 在2.3.0之前的版本中,如果一个函数式组件想要接收prop,则props选项是必须的。在2.3.0或以上的版本中,你可以省略props选项,组件上所有的attribute都会被自动隐式解析为prop。

函数式组件中Render的第二个参数是context上下文,data、props、slots、children以及parent都可以通过context来访问。

在2.5.0及以上版本中,如果你使用了单文件组件,那么基于模板的函数式组件可以这样声明:, 但是如果Vue组件中的render函数存在,则Vue构造函数不会从template选项或通过el选项指定的挂载元素中提取出的HTML模板编译渲染函数,也就是说一个组件中templete和render函数不能共存,如果一个组件中有了templete,即使有了render函数,render函数也不会执行,因为template选项的优先级比render选项的优先级高。

到这里,Vue函数式组件介绍的就差不多了,我们就来看看Element的表格组件是如何通过函数式组件来实现封装的吧。

效果图:

1、所封装的table组件:



2、汇总表格每一列的cell.js:

import * as Components from './components';
let empty = '-'
export default {
 props: {
  config: Object,
  data: Object,
 },
 functional: true,
 render: (h, c) => {
  let {props: {cOnfig= {}, data = {}}} = c, {prop, type = 'Default'} = config, value = data[prop] || config.value, isEmpty = value === '' || value === undefined;
  return isEmpty ? h(Components.Default, {props: {value: empty}}) : h(Components[type], {props: {value, empty, data, ...config}});
 }
}

3、本次封装将每一列的渲染单独分开成多个vue组件,最后再合并在一个components.js文件中一起进行匹配。

1)整合文件components.js:

import Date     from './Date';
import Default   from './Default';
import Currency   from './Currency';
import Enum     from './Enum';
import Action    from './Action';
import Link     from './Link';
import Format    from './Format';
import Popover   from './Popover';

export {
 Default,
 Date,
 Currency,
 Enum,
 Action,
 Link,
 Format,
 Popover,
}

2)日期列Date.vue

3)默认列Default.vue

4)金额千分位列Currency.vue

5)映射列Enum.js

let mapIdAndKey = list => list.reduce((c, i) => ({...c, [i.key]: i}), {});

let STATUS = {
  order: mapIdAndKey([
    {
      id: 'draft',
      key: 'CREATED',
      val: '未提交',
    },
    {
      id: 'pending',
      key: 'IN_APPROVAL',
      val: '审批中',
    },
    {
      id: 'reject',
      key: 'REJECT',
      val: '审批驳回',
    },
    {
      id: 'refuse',
      key: 'REFUSE',
      val: '审批拒绝',
    },
    {
      id: 'sign',
      key: 'CONTRACT_IN_SIGN',
      val: '合同签署中',
    },
    {
      id: 'signDone',
      key: 'CONTRACT_SIGNED',
      val: '合同签署成功',
    },
    {
      id: 'lendDone',
      key: 'LENDED',
      val: '放款成功',
    },
    {
      id: 'lendReject',
      key: 'LOAN_REJECT',
      val: '放款驳回',
    },
    {
      id: 'cancel',
      key: 'CANCEL',
      val: '取消成功',
    },
    {
      id: 'inLend',
      key: 'IN_LOAN',
      val: '放款审批中',
    },
  ]),
  monitor: mapIdAndKey([
    {
      key: '00',
      val: '未监控',
    },
    {
      key: '01',
      val: '监控中',
    },
  ]),
}

export default {
  functional: true,
  render(h, {props: {value, Enum, empty}, parent}){
    let enums = Object.assign({}, STATUS, parent.$store.getters.dictionary),
      {name = '', getVal = (values, v) => values[v]} = Enum, _value = getVal(enums[name], value);
      
    if( _value === undefined) return h('span', _value === undefined ? empty : _value);

    let {id, val} = _value;
    return h('span', {staticClass: id}, [h('span', val)]);
  }
}

6)操作列Action.js

const getAcitOns= (h, value, data) => {
 let result = value.filter(n => {
  let {filter = () => true} = n;
  return filter.call(n, data);
 });

 return result.map(a => h('span', {class: 'btn', on: {click: () => a.click(data)}, key: a.prop}, a.label))
}

export default {
 functional: true,
 render: (h, {props: {value, data}}) => {
  return h('div', {class: 'action'}, getAcitons(h, value, data))
 },
}

7)带有可跳转链接的列Link.vue



8)自定义想要展示的数据格式Format.vue

9)当内容过多需要省略并在鼠标移入后弹出一个提示窗显示全部内容的列Popover.vue


从以上代码中可以看出,我既使用了基于render函数类型的函数式组件也使用了基于模板的函数式组件,主要是为了在封装时的方便,毕竟使用render这个最接近编译器的函数还是有点麻烦的,不如基于模板的函数式组件来的方便。

4、使用封装后的表格table组件

1)不使用插槽:




2)使用插槽:

 

在两个不太相同的使用方式中,第一种是不基于插槽实现的,第二种是基于插槽实现的。通过两种方式的对比,可以看出在第二种使用方式中,但凡是使用了插槽的列,在headers数组中其已经不再定义type字段了,即使定义了type,它也不起作用,起作用的是插槽,而且也不再使用concat去拼接一个操作列了,操作列也是通过插槽来渲染的,只是如果很多列都通过插槽的形式实现,私心觉得页面看起来就不那么整洁了。

多说一句,既然我们已经对大部分场景的实现进行了封装,那么大家在使用时就没必要再通过插槽的形式去多此一举了,尽量保持页面的整洁。如果你实在觉得在headers数组后边再concat一个操作列的方式有点别扭,那么就只需将操作列通过插槽的形式去实现就OK了。本博客中提到的插槽实现形式,只是为了给大家多一种选择而已。

最后,关于金额千分位和时间戳格式化的实现,这里就不再贴代码了,可自行实现。

最近又想了一下封装的这个table组件,想着说在原来封装的基础上还有没有其他的实现方法,比如我不想在原来定义的headers数组后边再concat一个操作列,再比如表格的某一列的数据处理方法不包含在我们之前所封装的那些方法当中,或者说作为第一次使用这个table组件的前端开发人员,我不太习惯你的那种写法,那我可不可以在你封装的基础上自己写一些处理方法呢,答案是可以的,当然我们说既然已经封装好了组件,那么大家就按照一个套路来,省时又省力,何乐而不为呢?但有一说一,我们本着学习的态度,本着艺多不压身的出发点来看的话,多学多思考多动手,总归是有益于进步的。只是在实际的开发过程中,我们尽量要选择一种封装方式,然后大家一起遵守这个约定就好了。

其实说了这么多废话,这次变更也是没有多大力度的,只是在原来封装的基础上增加了插槽而已。看过本篇博客的你一定还记得我封装的代码中有一段专门用来处理每一列数据的代码吧:

对,就是它。对于它,我不想再多说了,上边已经做了介绍了。本次变更,我们主要用到的是插槽。

插槽这个API,VUE的官网和网上的各种文章介绍已经讲的很清楚了,它大概分为:默认插槽(也有人管它叫匿名插槽)、具名插槽和作用域插槽。关于它们的介绍,请自行查阅官网或网上的各种文章资料。本次变更主要用到的就是具名插槽和作用域插槽。具名插槽,顾名思义就是带有名称的插槽,我们本次封装所使用的插槽的名称来自于table的每一列的prop。作用域插槽在本次封装中的作用主要就是通过子组件的插槽向父组件传值,其实现形式有点类似于vue父组件向子组件传值,只不过两者的接收值的方式不同。总之此次变更实现起来还是很简单的,就是在的外边再包一层具名插槽就可以了。

就酱。

接下来,我们就可以回答上边我们提出的那些问题了。来看答案:

以上就是对某些特殊情况,而你又不想使用我最开始封装的那些方法来实现,那么可以,我就再为你提供一个其他的“特殊服务”。这里要注意,如果你使用插槽来自己渲染数据,那么在headers数组中,你需要提供表格头部的渲染,而不需要再加入type字段即可。
比如最开始渲染表格的日期列时我们是这么写的:
{prop: 'payTime', label: '付款时间', type: "Date", format: 'yyyy-MM-dd hh:mm:ss'}
那么如果你使用插槽来自己渲染数据,这里的写法就要变成了这样:
{prop: 'payTime', label: '付款时间'}
还有之前我们定义操作列是在headers数组的后边再concat了一个数组,如果你使用插槽来自己渲染数据,那么就不需要再concat一个数组了,而是在headers数组中再加一个{prop: 'opt', label: '操作'}就可以了。

其实,这次变更说的是在原来的基础上重新包装了一层插槽,那么对于那些不需要我们自行处理数据,只需直接展示接口返回的数据的情况,我们在使用这个封装的table组件时也不需要进行什么特殊处理,更不需要像上边使用插槽那样去定义,只要还是跟之前一样在headers数组中正常定义就可以了。因为插槽嘛,你不定义具名插槽,也不定义默认插槽,那么插槽中显示的就是包裹在插槽标签slot中的
明白了吧。

多说一句,你说我不想使用插槽去处理日期、金额千分位这些列,那么你依旧可以根据上边我介绍的插槽的原理,在headers数组中依旧这样定义就OK了:

{prop: 'tradeAmt', label: '付款金额', type: 'Currency'},
{prop: 'payTime', label: '付款时间', type: "Date"},

写到这里,其实我想说,即使加上了插槽,那么对之前的那些使用方法来说,基本没啥影响,你该怎么用还怎么用,我只是给你提供了更多的选择而已。

如果你实在不想用插槽,想保持页面的整洁,那你在这段代码的外面包裹不包裹一层插槽都无所谓,直接使用上文中我介绍的第一种使用方法就可以了。

作者:小坏

出处:http://tnnyang.cnblogs.com

以上就是如何封装Vue Element的table表格组件的详细内容,更多关于封装Vue Element的table表格组件的资料请关注其它相关文章!


推荐阅读
  • 在使用STM32Cube进行定时器配置时,有时会遇到延时不准的问题。本文探讨了可能导致延时不准确的原因,并提供了解决方法和预防措施。 ... [详细]
  • 阿里云ecs怎么配置php环境,阿里云ecs配置选择 ... [详细]
  • 在尝试更新Microsoft Edge浏览器时遇到“检查更新时出错:无法连接到Internet”的问题。本文将详细介绍可能的原因及解决方案,包括防火墙设置和证书缺失的处理方法。 ... [详细]
  • 本文探讨了如何利用jQuery在客户端实现页面跳转,并详细介绍了如何确保页面在浏览器的顶层窗口中打开,而不是局限于当前框架内。 ... [详细]
  • 本文将探讨Java编程语言中对象和类的核心概念,帮助读者更好地理解和应用面向对象编程的思想。通过实际例子和代码演示,我们将揭示如何在Java中定义、创建和使用对象。 ... [详细]
  • 本文详细探讨了JavaScript中的作用域链和闭包机制,解释了它们的工作原理及其在实际编程中的应用。通过具体的代码示例,帮助读者更好地理解和掌握这些概念。 ... [详细]
  • Windows 7 64位系统下Redis的安装与PHP Redis扩展配置
    本文详细介绍了在Windows 7 64位操作系统中安装Redis以及配置PHP Redis扩展的方法,包括下载、安装和基本使用步骤。适合对Redis和PHP集成感兴趣的开发人员参考。 ... [详细]
  • 雨林木风 GHOST XP SP3 经典珍藏版 V2017.11
    雨林木风 GHOST XP SP3 经典珍藏版 V2017.11 ... [详细]
  • 丽江客栈选择问题
    本文介绍了一道经典的算法题,题目涉及在丽江河边的n家特色客栈中选择住宿方案。两位游客希望住在色调相同的两家客栈,并在晚上选择一家最低消费不超过p元的咖啡店小聚。我们将详细探讨如何计算满足条件的住宿方案总数。 ... [详细]
  • 本文详细介绍了SDCMS中的全局标签和循环标签。全局标签是在任何模板页面中均可调用的标签,而循环标签用于数据查询和展示。文章解释了这些标签的功能、使用方法及参数配置。 ... [详细]
  • 本文详细介绍了在腾讯云服务器上配置 phpMyAdmin 的方法,包括安装、配置和解决常见问题。通过这些步骤,您可以轻松地在腾讯云环境中部署并使用 phpMyAdmin。 ... [详细]
  • Python 内存管理机制详解
    本文深入探讨了Python的内存管理机制,涵盖了垃圾回收、引用计数和内存池机制。通过具体示例和专业解释,帮助读者理解Python如何高效地管理和释放内存资源。 ... [详细]
  • C#设计模式学习笔记:观察者模式解析
    本文将探讨观察者模式的基本概念、应用场景及其在C#中的实现方法。通过借鉴《Head First Design Patterns》和维基百科等资源,详细介绍该模式的工作原理,并提供具体代码示例。 ... [详细]
  • JSOI2010 蔬菜庆典:树结构中的无限大权值问题
    本文探讨了 JSOI2010 的蔬菜庆典问题,主要关注如何处理非根非叶子节点的无限大权值情况。通过分析根节点及其子树的特性,提出了有效的解决方案,并详细解释了算法的实现过程。 ... [详细]
  • 目录一、salt-job管理#job存放数据目录#缓存时间设置#Others二、returns模块配置job数据入库#配置returns返回值信息#mysql安全设置#创建模块相关 ... [详细]
author-avatar
安晗夕Brooke
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有