下载&l_umy-ui">
当前位置:   article > 正文

umy-ui使用手册

umy-ui

可支持大批量table长列表虚拟表格(几万行数据渲染是没问题的)
项目直接安装
npm install umy-ui
在main.js中引用

import UmyUi from 'umy-ui'
import 'umy-ui/lib/theme-chalk/index.css'// 引入样式
Vue.use(UmyUi)
  • 1
  • 2
  • 3

实列:

<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>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486

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


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

效果图
在这里插入图片描述
封装的时间范围组件(因为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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/115397
推荐阅读
相关标签