element ui 表格组件与分页组件的二次封装

目录

组件封装

parseTime函数

[debounce 函数](#debounce 函数)

页面使用

[【扩展】vue 函数式组件](#【扩展】vue 函数式组件)

函数式组件特点:

函数式组件的优点:

【扩展】vue中的render函数

一、初步认识render函数

二、为什么使用render函数

三、render函数的解析


组件封装

这段代码是一个封装的分页表格组件。它使用了Vue.js框架,并结合了Element UI中的el-table和el-pagination组件来实现。该组件接受一系列属性作为数据源,包括列表数据(list)、表格列(columns)、操作按钮列(operates)、总数(total)、分页参数(pagination)等。

在模板中,使用el-table组件来展示表格数据,使用el-pagination组件来实现分页功能。el-table-column用来定义每列的样式和展示内容。组件中还包括其他的一些方法和事件处理函数,如handleSizeChange用于切换每页显示的数量,handleIndexChange用于切换页码,handleSelectionChange处理多行选中等。

此外,还定义了一些样式规则来美化表格的显示效果,如设置表头颜色、调整列的样式、设置操作按钮组的布局、设置筛选弹窗和表格操作弹窗的样式等。

最后,使用了scss来编写样式表,通过设置类名来控制样式的展示。

  1. <template>标签中,定义了一个表格组件,包括表格本身,列定义,按钮操作组,和分页控件。

  2. <script>标签中,导入了必要的依赖,并定义了组件的属性(props)、数据(data)、生命周期钩子(activated、beforeDestroy、deactivated、created、mounted)和方法(methods)。

  3. props属性用于接受从父组件传递进来的数据,如数据列表 list、列定义 columns、按钮操作 operates、总数 total、分页参数 pagination 等。

  4. data数据属性包括一些内部状态,如表格高度 height、监听窗口调整大小的回调函数 $_resizeHandler、当前页码 pageIndex、表格分页信息 tableCurrentPagination、多行选中数据 multipleSelection 等。

  5. 在生命周期钩子中,组件监听窗口大小调整事件,自动调整表格高度,并在适当的生命周期中初始化和销毁事件监听器。

  6. methods包括一系列方法,如计算表头宽度的方法 headSpanFit、初始化事件监听器的方法 initListener、销毁事件监听器的方法 destroyListener、调整表格高度的方法 resize、处理每页显示数量变化的方法 handleSizeChange、处理页码变化的方法 handleIndexChange、处理多行选中的方法 handleSelectionChange 等。

  7. 最后,在<style>标签中定义了一些样式,包括表格样式、分页样式、按钮样式、筛选和操作弹窗样式等。

parseTime函数

复制代码
// 日期格式化
export function parseTime(time, pattern) {
  if (arguments.length === 0 || !time) {
    return null
  }
  const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}'
  let date
  if (typeof time === 'object') {
    date = time
  } else {
    if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
      time = parseInt(time)
    } else if (typeof time === 'string') {
      time = time.replace(new RegExp(/-/gm), '/').replace('T', ' ').replace(new RegExp(/\.[\d]{3}/gm), '');
    }
    if ((typeof time === 'number') && (time.toString().length === 10)) {
      time = time * 1000
    }
    date = new Date(time)
  }
  const formatObj = {
    y: date.getFullYear(),
    m: date.getMonth() + 1,
    d: date.getDate(),
    h: date.getHours(),
    i: date.getMinutes(),
    s: date.getSeconds(),
    a: date.getDay()
  }
  const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
    let value = formatObj[key]
    // Note: getDay() returns 0 on Sunday
    if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] }
    if (result.length > 0 && value < 10) {
      value = '0' + value
    }
    return value || 0
  })
  return time_str
}

debounce 函数

复制代码
export function debounce(func, wait, immediate) {
  let timeout, args, context, timestamp, result

  const later = function() {
    // 据上一次触发时间间隔
    const last = +new Date() - timestamp

    // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
    if (last < wait && last > 0) {
      timeout = setTimeout(later, wait - last)
    } else {
      timeout = null
      // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
      if (!immediate) {
        result = func.apply(context, args)
        if (!timeout) context = args = null
      }
    }
  }

  return function(...args) {
    context = this
    timestamp = +new Date()
    const callNow = immediate && !timeout
    // 如果延时不存在,重新设定延时
    if (!timeout) timeout = setTimeout(later, wait)
    if (callNow) {
      result = func.apply(context, args)
      context = args = null
    }

    return result
  }
}

页面使用

复制代码
<template>
  <div class="table-page">
    <!--region table 表格-->
    <app-table :list="list" :total="total" :otherHeight="otherHeight" :options="options" :pagination="pagination"
      :columns="columns" :operates="operates" @handleSizeChange="handleSizeChange" @handleIndexChange="handleIndexChange"
      @handleSelectionChange="handleSelectionChange">
    </app-table>
    <!--endregion-->
  </div>
</template>
<script>
import {
  parseTime,

} from "@/utils/ruoyi";
export default {
  data() {
    return {
      total: 0,
      list: [
        {
          id: 1,
          title: '标题',
          state: 0,
          author: '张三',
          phone: '12346788901',
          email: '1234556778@qq.com',
          createDate: "2023-04-23 16:11:38"
        }
      ],
      otherHeight: 208,
      columns: [
        {
          prop: 'id',
          label: '编号',
          align: 'center',
          width: 60
        },
        {
          prop: 'title',
          label: '标题',
          align: 'center',
          width: 400,
          formatter: (row, column, cellValue) => {
            return `<span style="white-space: nowrap;color: dodgerblue;">${row.title}</span>`
          }
        },
        {
          prop: 'state',
          label: '状态',
          align: 'center',
          width: '160',
          render: (h, params) => {
            return h('el-tag', {
              props: { type: params.row.state === 0 ? 'success' : params.row.state === 1 ? 'info' : 'danger' } // 组件的props
            }, params.row.state === 0 ? '上架' : params.row.state === 1 ? '下架' : '审核中')
          }
        },
        {
          prop: 'author',
          label: '作者',
          align: 'center',
          width: 120
        },
        {
          prop: 'phone',
          label: '联系方式',
          align: 'center',
          width: 160
        },
        {
          prop: 'email',
          label: '邮箱',
          align: 'center',
          width: 240
        },
        {
          prop: 'createDate',
          label: '发布时间',
          align: 'center',
          width: 180,
          formatter: (row, column, cellValue) => {
            return parseTime(row.createDate)
          }
        }
      ], // 需要展示的列
      operates: {
        width: 200,
        fixed: 'right',
        list: [
          {
            label: '编辑',
            type: 'warning',
            show: (index, row) => {
              return true
            },
            icon: 'el-icon-edit',
            plain: true,
            disabled: false,
            method: (index, row) => {
              this.handleEdit(index, row)
            }
          },
          {
            label: '删除',
            type: 'danger',
            icon: 'el-icon-delete',
            show: true,
            plain: false,
            disabled: (index, row) => {
              return false
            },
            method: (index, row) => {
              this.handleDel(index, row)
            }
          }
        ]
      }, // 操作按钮组
      pagination: {
        pageIndex: 1,
        pageSize: 20
      }, // 分页参数
      options: {
        stripe: true, // 是否为斑马纹 table
        loading: false, // 是否添加表格loading加载动画
        highlightCurrentRow: true, // 是否支持当前行高亮显示
        mutiSelect: true // 是否支持列表项选中功能
      } // table 的参数
    }
  },
  components: {
    expandDom: {
      props: {
        column: {
          required: true
        },
        row: {
          required: true
        }
      },
      render(h) {
        return h('div', {}, ([this.column.render(this.row, this.column)]))
      }
    }
  },
  mounted() {
  },
  methods: {
    // 切换每页显示的数量
    handleSizeChange(pagination) {
      this.pagination = pagination
    },
    // 切换页码
    handleIndexChange(pagination) {
      this.pagination = pagination
    },
    // 选中行
    handleSelectionChange(val) {
      console.log('val:', val)
    },
    // 编辑
    handleEdit(index, row) {
      console.log(' index:', index)
      console.log(' row:', row)
    },
    // 删除
    handleDel(index, row) {
      console.log(' index:', index)
      console.log(' row:', row)
    },

  }
}
</script>

【扩展】vue 函数式组件

函数式组件特点:

  • 没有管理任何状态
  • 没有监听任何传递给它的状态
  • 没有生命周期方法
  • 它只是接收一些prop的函

我们将这样的组件标记为functional

  • 无状态 == 无响应式数据
  • 无实例 == 无this上下文

函数式组件的优点:

  • 渲染开销低,因为函数式组件只是函数;

    {
    functional: true,
    // Props 是可选的
    props: {
    // ...
    },
    // 为了弥补缺少的实例
    // 提供第二个参数作为上下文
    render: function (createElement, context) {
    // ...
    }
    }

props: 提供所有prop的对象
children:VNode 子节点的数组
slots: 一个函数,返回了包含所有插槽的对象
scoptedSlots:(2.6.0) 一个暴露传入的作用域插槽的对象,也以函数形式暴露普通插槽
data:传递个组件的整个数据对象,作为createElement的第二个参数传入组件
parent:对父组件的引用
listeners:(2.3.0+) 一个包含了:所有父组件为当前组件祖册的事件监听器对象,是data.on的一个别名
injections:(2.3.0+) 如果使用了inject选项,则改对象包含了:应当被注入的属性;

【扩展】vue中的render函数

一、初步认识render函数

复制代码
import Vue from 'vue'
import App from './App'

Vue.config.productionTip = false

new Vue({
  el: '#app',
  render: h => h(App)
})

在使用脚手架创建vue项目的过程,我们很容易看到render这个函数,相对于其他标签,我们对于render还是比较陌生的,因此写下这篇文章你我共同理解。

二、为什么使用render函数

VUE推荐在绝大多数情况下使用template来创建我们的HTML。然而在一些场景中,我们真的需要JavaScript的完全编程的能力,这就是render函数,它比template更接近编译器。(这是官方的话)

简单来说,我们为什么要使用render函数呢?? 便是因为我们最经常使用的一个引入。

复制代码
import Vue from "vue";

这一个引入你看似没有任何问题,但问题恰恰就是出在这。在不同版本的vue中,有vue.js和vue.runtime.xxx.js这两种js文件。其中

(1)vue.js是完整版的vue,包含核心功能+模板解析器。

(2)vue.runtime.xxx.js是运行版vue,只包含核心功能,没有模板解析器。

VUE开发者为了让我们打包的文件能尽可能小一点,在上述引入的是运行版vue。因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,这时候就需要使用render函数去接收到的createElement函数去指定具体内容,创建html模板。

三、render函数的解析

render 函数即渲染函数,它是个函数,它的参数 createElement 也是个函数。

上边的代码中 render: h => h(App) ,这是 ES6的箭头函数的写法,可以把 h 当作 createElement 的别名。所以这段代码其实相当于

复制代码
render: function (createElement) {
    return createElement(App)
}

这个函数的作用就是生成一个 VNode节点,render 函数得到这个 VNode 节点之后,返回给 Vue.js 的 mount 函数,渲染成真实 DOM 节点,并挂载到根节点上。

createElement 函数的返回值是 VNode(即:虚拟节点)

createElement 函数的3个参数

  • 一个 HTML 标签字符串,组件选项对象,或者解析上述任何一种的一个 async 异步函数。类型:String | Object | Function。必需。

  • 一个包含模板相关属性的数据对象,你可以在 template 中使用这些特性。类型:Object。可选。

  • 子虚拟节点 (VNodes),由 createElement() 构建而成,也可以使用字符串来生成"文本虚拟节点"。类型:String | Array。可选

    new Vue({
    el: '#app',
    render:function (createElement) {
    //1.普通用法
    // createElement(标签,{属性},[内容])
    return createElement("h2",{class:"box"},['hello',createElement("button",["按钮"])])
    }
    })

同时createElement也可以传进去一个组件,因此

复制代码
render: h => h(App)

等同于

复制代码
render:function (createElement) {
    return createElement(App)
  }
相关推荐
#麻辣小龙虾#18 分钟前
基于vue3.0开发一款【固废与废气运维管理系统】(支持源码)
前端·vue.js·vue3
一 乐1 小时前
家政服务管理系统|基于springboot + vue家政服务管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·家政服务管理系统
烬羽2 小时前
后端返回的 JSON 字符串,浏览器怎么"看懂"的?——Ajax 全链路拆解
javascript
半个落月3 小时前
一个新手用 Bun + Axios 调通 DeepSeek API 的实践记录
javascript
不好听6133 小时前
深入理解链表:线性数据结构的另一面
javascript·数据结构
林希_Rachel_傻希希3 小时前
学React治好了我的焦虑症,1小时速通React 前20分钟。
前端·javascript·面试
小林ixn3 小时前
从 Ajax 到异步编程:JSON 序列化、Event Loop 与 XHR 请求完全解析
javascript
丷丩4 小时前
MapLibre GL JS第47课:添加动画图标
javascript·gis·动画·mapbox·maplibre
独泪了无痕4 小时前
Vue3中防御XSS攻击的“特效药”-DOMPurify
前端·vue.js·安全
快乐的哈士奇4 小时前
【Next.js实战①】Gmail API 按柜号检索邮件:OAuth 双 Cookie 与搜索 Fallback
开发语言·javascript·ecmascript