赞
踩
可支持大批量table长列表虚拟表格(几万行数据渲染是没问题的)
项目直接安装
npm install umy-ui
在main.js中引用
import UmyUi from 'umy-ui'
import 'umy-ui/lib/theme-chalk/index.css'// 引入样式
Vue.use(UmyUi)
实列:
<template> <div class="content"> <i class="el-icon-edit"></i> <i class="el-icon-minus"></i> <el-button type="primary" @click="exportData">下载</el-button> <el-button type="primary" @click="openDialog">筛选字段</el-button> <div class="content_table"> <ux-grid :key="Math.random()" :edit-config="{trigger: 'click', mode: 'cell'}" :highlight-current-row="false" show-summary :summary-method="summaryMethod" ref="plTable" :data="data" :max-height="height" use-virtual show-header-overflow="tooltip" show-footer-overflow="tooltip" show-overflow="tooltip" :stripe="true" :row-style="rowStyle" moveDownIcon="el-icon-caret-bottom" moveUpIcon="el-icon-caret-top" :showDialogIcon="true" field-title="选择展示列表" :field-sort="true" :dialog-data="dialogData" :checkbox-config="{highlight: true}" @show-field="showField" @toggle-tree-expand="toggleTreeExpand" :tree-config="{ iconOpen: 'el-icon-minus', iconClose: 'el-icon-plus',children:'children' , indent:40, line:'true'}" :header-row-style="{color:'#FFFFFF',backgroundColor:'rgba(1, 73, 95)'}" border> <ux-table-column type="expand1" width="55" title="展开" align="center" fixed="left" tree-node/> <!-- <ux-table-column type="checkbox" width="55" align="center" fixed="left"/> --> <ux-table-column type="index" width="50" title="序号" align="center" fixed="left"/> <template v-for="(item,index) in columns"> <ux-table-column v-if="item.dataIndex!='score'&&item.dataIndex!='sex'&&item.dataIndex!='avatar'&&item.dataIndex!='mtime'&&item.dataIndex!='action'&&findIndex(item.title)" :key="index" prop="date" :filters="[{ data: '' }]" :filter-method="filterNameMethod" :resizable="true" :show-overflow-tooltip="true" :field="item.dataIndex" :title="item.title" :fixed="item.fixed" :width="item.width" :min-width="item.minWidth" :align="item.align" :edit-render="['select','input'].indexOf(item.type)>-1" > <!-- 可编辑项 --> <template v-slot:edit="scope"> <a-input v-if="item.type=='input'" v-model="scope.row[item.dataIndex]"></a-input> <el-select v-if="item.type=='select'" v-model="scope.row[item.dataIndex]"> <el-option v-for="item in userList" :key="item.value" :label="item.label" :value="item.value"> </el-option> </el-select> </template> <template v-slot="{ row }"> {{ row[item.dataIndex]}} </template> <!-- 筛选功能 --> <template v-slot:filter="{ $panel, column }"> <a-input type="type" v-for="(option, index) in column.filters" :key="index" v-model="option.data" @input="$panel.changeOption($event, option.data, option)"/> </template> </ux-table-column> <!-- 将布尔值转化为数字 --> <ux-table-column :key="index" v-if="item.dataIndex=='sex'&&findIndex(item.title)" :resizable="true" :show-overflow-tooltip="true" :field="item.dataIndex" :title="item.title" :width="item.width" :align="item.align"> <template v-slot="{ row }"> <select v-if="item.type=='select'&&item.dataIndex=='USER_TYPE'" v-model="scope.row.USER_TYPE"> <option v-for="(item1,index1) in userList" :key="item1.value" :value="item1.value">{{item1.label}}</option> </select> {{ row[item.dataIndex]?'男':'女'}} </template> </ux-table-column> <!-- 将base64转体图片 --> <ux-table-column :key="index" v-if="item.dataIndex=='avatar'&&findIndex(item.title)" :resizable="true" :show-overflow-tooltip="true" :field="item.dataIndex" :title="item.title" :width="item.width" :align="item.align"> <template v-slot="{ row }"> <img :src="row[item.dataIndex]" > </template> </ux-table-column> <!-- 将数字转换为进度条 --> <ux-table-column :key="index" v-if="item.dataIndex=='score'&&findIndex(item.title)" :resizable="true" :show-overflow-tooltip="true" :field="item.dataIndex" :title="item.title" :width="item.width" :align="item.align"> <template v-slot="{ row }"> <el-progress :percentage="row[item.dataIndex]" color="#5a1216"></el-progress> </template> </ux-table-column> <!-- 筛选时间范围 --> <ux-table-column :key="index" v-if="item.dataIndex=='mtime'&&findIndex(item.title)" :filters="[{ data: [] }]" :filter-method="filterNameMethod" :show-overflow-tooltip="true" :field="item.dataIndex" :title="item.title" :width="item.width" :align="item.align"> <template v-slot="{ row }"> {{ row[item.dataIndex]}} </template> <!-- 时间筛选功能 --> <template v-slot:filter="{ $panel, column }"> <cTimeRange v-for="(option, index) in column.filters" :key="index" v-model="option.data" :defaultValue = "option.data" @input="$panel.changeOption($event, option.data, option)" ></cTimeRange> </template> </ux-table-column> <ux-table-column :key="index" v-if="item.dataIndex=='action'&&findIndex(item.title)" :resizable="true" :show-overflow-tooltip="true" :field="item.dataIndex" :title="item.title" :width="item.width" :align="item.align"> <template v-slot="{ row }"> <router-link to="{name:'detail',params:'{id:row.id}'" > <span>详情</span> </router-link> </template> </ux-table-column> </template> </ux-grid> </div> </div> </template> <script> import {umyData} from '../../utils/fakedata' import axios from 'axios' import cTimeRange from '../../component/cTimeRange.vue' import moment from 'moment' const columns = [ { title: "id", dataIndex: "id", minWidth: 200, //可用作自适应 align: "center", fixed: "left", type:'text', }, { title: "姓名", dataIndex: "nickname", width: 100, align: "center", fixed: "left", type:'input', }, { title: "头像", dataIndex: "avatar", width: 200, align: "center", fixed: "left", type:'img', }, { title: "部门", dataIndex: "dep", width: 100, align: "center", fixed: "", type:'text', }, { title: "地址", dataIndex: "address", width: 100, align: "center", fixed: "", type:'text', }, { title: "城市", dataIndex: "city", width: 220, align: "center", fixed: "", type:'text', }, { title: "性别", dataIndex: "sex", width: 70, align: "center", fixed: "", type:'text', }, { title: "时间", dataIndex: "mtime", width: 270, align: "center", fixed: "", type:'text', }, { title: "级别", dataIndex: "rank", width: 100, align: "center", fixed: "", type:'select', }, { title: "成绩", dataIndex: "score", width: 170, align: "center", fixed: "", type:'text', }, { title: "星数", dataIndex: "stars", width: 100, align: "center", fixed: "right", type:'text', }, { title: "操作", dataIndex: "action", width: 100, align: "center", fixed: "right", type:'text', } ]; export default { components:{ cTimeRange }, data() { return { moment, height: '470px', data: umyData.list,//就用了101条数据。 columns: columns, userList:[ {label:1,value:1}, {label:2,value:2}, {label:3,value:3}, ], dialogData:[ { name: 'id', state: true, disabled: true }, { name: '姓名', state: true,}, { name: '头像', state: true }, { name: '部门', state: true,}, { name: '地址', state: true, }, { name: '城市', state: true, }, { name: '性别', state: true, }, { name: '时间', state: true, }, { name: '级别', state: true, }, { name: '成绩', state: true, }, { name: '星数', state: true, }, { name: '操作', state: true, }, ] } }, created() {}, mounted() { console.log(umyData) // let objData = this.$refs.plTable.getTableData().visibleData; }, methods: { //斑马纹 rowStyle({row, rowIndex}){ if(rowIndex % 2 !== 0){ return {background: 'rgba(33, 119, 184)', color: '#FFF',height:'30px'} }else { return {background: 'rgba(65, 174, 60)', color: '#FFF',height:'30px'} } }, //表头搜索重置 filterNameMethod({ option, row ,column}){ const property = column['property']; let format = 'YYYY-MM-DD'; //判断字段是否为null、模糊查询 if(typeof row[property] === 'string'){ //时间筛选 if(property == 'mtime'){ let starT = moment(option.data[0],format); let endT = moment(option.data[1],format); let currentT = moment(row[property],format); if(moment(currentT).diff(endT,'days')<=0&&moment(currentT).diff(starT,'days')>=0){ return true }else{ return false } }else{ return row[property].indexOf(option.data) > -1?true:false } }else{ return false } }, //合计 summaryMethod ({ columns, data }) { // 平均值算法(不需要自己去掉) function cacl(arr, callback) { let ret; for (let i=0; i<arr.length;i++) { ret = callback(arr[i], ret); } return ret; } // 平均值算法(不需要自己去掉) Array.prototype.sum = function () { return cacl(this, function (item, sum) { if (typeof (sum) == 'undefined') { return item; } else { return sum += item; } }); }; const means = [] // 合计 columns.forEach((column, columnIndex) => { if (columnIndex === 0) { means.push('合计') } else if(column.title === '姓名'){ return; }else if(column.title === '头像'){ return; }else if(column.title === '时间'){ return; }else { const values = data.map(item => Number(item[column.property])); // 合计 if (!values.every(value => isNaN(value))) { means[columnIndex] = values.reduce((prev, curr) => { const value = Number(curr); if (!isNaN(value)) { return prev + curr; } else { return prev; } }, 0); // means[columnIndex] += ' 元' // 改变了ele的合计方式,扩展了合计场景 // 你以为就只有上面这样玩吗?错啦,你还可以自定义样式哦 // means[columnIndex] = '<span style="color: red">' + means[columnIndex] + '元</span>' // means[columnIndex] = '<span>' + means[columnIndex]+ '</span>' // means[columnIndex] = '<span>' + Math.round(means[columnIndex]*100)/100+ '</span>' means[columnIndex] = Math.round(means[columnIndex]*100)/100 } else { means[columnIndex] = ''; } } }) return [means] }, //展开关闭树形结构 toggleTreeExpand({ expanded, row, rowIndex, $rowIndex, column, columnIndex, $columnIndex, $event }){ console.log({ expanded, row, rowIndex, $rowIndex, column, columnIndex, $columnIndex, $event }) }, //导出 exportData(){ //获取当前表格数据(筛选后的数据) let objData = this.$refs.plTable.getTableData().visibleData; console.log(objData); axios({ method: 'post', url: '', data: objData, responseType: "blob", }).then((res)=>{ const content = res.data; const bLob = new Blob([content]); const fileName = "表格数据.xLs"; if ("download" in document.createElement("a")) { //非IE下载 const elink = document.createElement("a"); elink.download = fileName; elink.style.display = "none"; elink.href = URL.createObjectURL(bLob); document.body.appendChild(elink) ; elink.click(); URL.revokeObjectURL(elink.href); //释放URL对象 document.body.removeChild(elink) ; } else { navigator.msSaveBlob(bLob,fileName); } }) }, //筛选字段 openDialog(){ this.$refs.plTable.plDialogOpens() }, showField(e){ // console.log(e); this.dialogData = e }, //查找索引,判断是否显示 findIndex(sele){ const index = this.dialogData.indexOf(this.dialogData.filter(d => d.name === sele)[0]) if(index> -1){ return this.dialogData[index]['state'] }else{ return false } }, } }; </script> <style scoped> .content{ height: 100%; width: 100%; background: #c7d2d4; } .content_table{ padding: 10px; width: calc(100% - 20px); } ::v-deep ::-webkit-scrollbar { height: 15px; width: 15px; } ::v-deep ::-webkit-scrollbar-thumb { /* border-radius: 5px; */ box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2); background: rgba(0, 203, 255, 0.6); } ::v-deep ::-webkit-scrollbar-track { box-shadow: 0; border-radius: 0; background: rgba(0, 0, 0, 0.37);; } </style>
mock 假数据代码。
fakedata.js
// 使用 Mock var Mock = require('mockjs') var data = Mock.mock({ // 属性 list 的值是一个数组,其中含有 1 到 10 个元素 'list|10': [{ // 属性 id 是一个自增数,起始值为 1,每次增 1 'id': "@id()", // 随机生成id "mtime": "@date", //随机生成日期时间 "dep": "一级部门", "sex|1-2": true, //随机生成布尔值 "address": '@region', //随机生成区域 "city": '@county(true)', //随机生成城市 "avatar": "@dataImage('40x25','你的名字')", //生成base64图片 "score|0-100": 800, //随机生成1-100的数字 "rank|1-3": 1, //随机生成1-3的数字 "stars|1-5": '★', //随机生成1-5个★ "nickname": "@cname", //随机生成中文名字 "children|1-10": [{ 'id': "@guid", // 随机生成guid "mtime": "@date", //随机生成日期时间 "dep": "二级部门", "sex|1-2": true, //随机生成布尔值 "address": '@region', //随机生成区域 "city": '@county(true)', //随机生成城市 "avatar": "@dataImage('40x25','你的名字')", //生成base64图片 "score|1-100": 800, //随机生成1-100的数字 "rank|1-3": 1, //随机生成1-3的数字 "stars|1-5": '★', //随机生成1-5个★ "nickname": "@cname", //随机生成中文名字 }] }] }) export const umyData = data
效果图
封装的时间范围组件(因为antd DatePicker组件不支持@input事件)
<template> <div class="gtTimeRange"> <input type="date" v-model="defaultValue[0]" @input="startInput"/> <span class="gtTimeRange_splitLine">-</span> <input type="date" v-model="defaultValue[1]" @input="endInput" @focus="endMousemove"/> </div> </template> <script> import moment from "moment"; import "moment/locale/zh-cn"; export default { name: "gtTimeRange", props: { defaultValue: { type: Array, // required: true, default: () => [null,null] }, }, watch:{ defaultValue(val){ // console.log(val) } }, mounted() { }, data() { return { moment, startTime:null, endTime:null, timeRange:null, }; }, created(){ // console.log(moment().format("YYYY-MM-DD")); }, methods:{ startInput(e){ this.$emit('input',this.defaultValue); }, endInput(e){ this.$emit('input',this.defaultValue); }, endMousemove(e){ // console.log(e); }, }; </script> <style scoped> .gtTimeRange{ display: flex; height: 50px; width: 100%; } .gtTimeRange_splitLine{ color: rgb(10, 0, 0); margin: 10px; } </style>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。