(o゜▽゜)o☆ 青椒味的Hello World
没有项目工程,没有vue脚手架,就一个HTML页面;没有干货,纯画页面,没有后台,数据写死,堆了些简单的Element UI控件,实现了前端table的增删改查的点点点操作
1.界面展示
2.Table本身
2.1 el-table的数据源
会绑定一个数据源data,data的格式是数组,所以之后在操作这个数组时,数组的下标(行索引)就比较重要了
:data="tableData"
tableData = [{
line: 1,
date: '2016-05-02',
name: '赫敏',
address: '上海市普陀区金沙江路 1518 弄',
age: 23,
num: 500,
str1: null,
str2: null,
str2laber: null,
str2dis: false,
str3: null,
str3laber: null,
str3dis: false,
str4: null
},
{
line: 2,
date: '2016-05-04',
name: '皮卡丘',
address: '上海市普陀区金沙江路 1517 弄',
age: 42,
num: 70000,
str1: null,
str2: 20,
str2laber: '我的貂蝉在哪里',
str2dis: true,
str3: null,
str3laber: null,
str3dis: false,
str4: null
}]
2.2 el-table的相关样式
一些基础的样式比如Table带边框,有斑马纹,固定表头,固定列,Table高度自适应,列宽按比例 这些都是Element UI自己就支持的,查一下官方的代码就知道怎么写
但是官方Table的行高,默认是比较高的,需要自己去调整CSS样式,这里主要是内边距属性值的调整
/* 合计行的样式(每个单元格的样式) */
.tabledata td {
padding: 0;
font-size: 13px;
}
/* 设置表头样式 */
.tabledata .el-table__header th {
padding: 0;
background-color: #F5F7FA;
}
2.3 el-table的合计
在el-table标签中加入 show-summary 即可实现合计;使用 :summary-method="getSummaries" 让其返回一个数组,这个数组中的各项就会显示在合计行的各列中,就可以实现自定义的合计;当然我这里的合计显示还是有bug的,比如日期列也会合计,但是我不想调了
用到的JS函数的说明(摘自菜鸟教程):
map() 函数返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。
Number() 函数把对象的值转换为数字。如果对象的值无法转换为数字,那么返回 NaN。
every() 函数用于检测数组所有元素是否都符合指定条件。
isNaN() 函数用于检查其参数是否是非数字值。
reduce() 函数接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。
getSummaries方法的参数param如图所示
// 合计 /代码中注释的代码 因为不兼容IE浏览器,替换成现在的代码并注视掉了
getSummaries: function (param) {
// const { columns, data } = param;
// const sums = [];
var _param = param,
columns = _param.columns,
data = _param.data;
var sums = [];
columns.forEach(
// (column, index) => {
// if (index === 0) {
// sums[index] = '合计';
// return;
// }
// const values = data.map(item => Number(item[column.property]));
// if (!values.every(value => isNaN(value))) {
// sums[index] = values.reduce((prev, curr) => {
// const value = Number(curr);
// if (!isNaN(value)) {
// return prev + curr;
// } else {
// return prev;
// }
// }, 0);
// sums[index] += '';
// } else {
// sums[index] = '';
// }
// }
function (column, index) {
if (index === 0) {
sums[index] = '合计';
return;
}
const values = data.map(
//item => Number(item[column.property]);
function (item) { return Number(item[column.property]); }
);
if (!values.every(
//value => isNaN(value)
function (value) { return isNaN(value) }
)) {
sums[index] = values.reduce(
// (prev, curr) => {
// const value = Number(curr);
// if (!isNaN(value)) {
// return prev + curr;
// } else {
// return prev;
// }
// }
function (prev, curr) {
const value = Number(curr);
if (!isNaN(value)) {
return prev + curr;
} else {
return prev;
}
}
, 0);
sums[index] += '';
} else {
sums[index] = '';
}
}
);
return sums;
}
2.4 el-table的分页
这里用到的是分页的完整功能,分页功能是独立于el-table,只是操作些数据去调整el-table的数据源,我觉得差不多可以这样理解
<div class="block" align="right">
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="pageindex"
:page-sizes="[10, 20, 30, 40]" :page-size="100" layout="total, sizes, prev, pager, next, jumper"
:total="tableData.length">
</el-pagination>
</div>
handleSizeChange: function (val) {
console.log('每页 ${val} 条');
},
handleCurrentChange: function (val) {
console.log('当前页码: ${val}');
},
2.5 el-table的事件
这里用到了 行的单击事件(row-click)(双击实现编辑) / 行的双击事件(cell-dblclick)(单击其他行取消编辑)/ 复选框选择事件(selection-change)(当选择项发生变化时会触发该事件)
<el-table class="tabledata" :data="tableData" :summary-method="getSummaries" show-summary
@row-dblclick="RowDblclick" @row-click="RowClick" @selection-change="SelectFun" stripe border
style="width: 100%">
<el-table-column type="selection" align="center" width="60"></el-table-column><!-- type="selection" 复选框 -->
2.6 el-table的插槽
这个很重要,在el-table要获得每一行的数据,那么就需要使用插槽(<template slot-scope="scope"></template>)
网上貌似还有一种插槽 slot,但还是推荐这种 slot-scope
获取当前行数据:scope.row
获取当前行的xxx字段数据:scope.row.xxx
获取当前行的索引:scope.$index
<el-table-column label="自定义列2" width="270%">
<template slot-scope="scope"><!-- 插槽 -->
<el-select v-show="doubleclick==scope.row.line" v-model="scope.row.str2" :disabled="scope.row.str2dis"
filterable remote reserve-keyword placeholder="请选择你的英雄" :remote-method="RemoteMethod"
@change="SelectStr2(scope.row.str2,scope.$index)" size="mini" clearable>
<el-option v-for="item in options_st2" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
<el-button v-show="doubleclick==scope.row.line" :disabled="scope.row.str2dis" icon="el-icon-search"
@click="dialogTable=true" size="mini"></el-button>
<span v-show="doubleclick!=scope.row.line">{{scope.row.str2laber}}</span>
</template>
</el-table-column>
2.7 el-table实现行编辑
这个是双击行触发编辑,然后是 el-table-column 中会有一个显示标签和编辑的控件标签,用双击记录的当前行索引去对比当前行的索引,满足则显示编辑的控件标签,不满足则显示显示标签;当单击其它行的时候,把记录当前行索引的变量置为空,这样就取消编辑了。这是整体的思路,网上也有说用鼠标焦点什么的,但是没有尝试成功
2.8 el-table查找框处理
在 el-table 中用了一些常用的控件标签,比如日期框,数值框,下拉选择框,Switch 开关,文本框,按钮,以及这个下拉选择框+按钮组合的查找框
在Element UI中下拉选择框很智能,可以设置成百度搜索框那样的自动完成功能,用 el-selec t和 el-option 组合使用,官方也有说明怎样使用
Element UI官方提供了一个远程搜索方法 remote-method,这个我写了,但是发现我写不写貌似都会进行搜索,但是我的搜索是基于已经有的数据源(就是el-option绑定的数组)去进行搜索,所以这个远程搜索方法还没有太明白,而且这个方法是每输入一个字就会被触发,所以感觉慎用
再说回到这个查找框,就是下拉选择框+按钮,下拉选择框上面已经说了官方有示例,是可以自动完成的;而点击按钮时是会弹出一个 el-dialog,上面会有 el-input 查找框、el-table 展示数据及按钮操作
这里遇到了四个样式的问题:
一、点击灰色部分时需要不关闭此弹框(这个是在 el-dialog 中加上 :before-close="HandleClose" 这个关闭的回调函数,然后直接return false; 就好了)
二、右上角的❌号需要隐藏(在加上了上面的方法之后,右上角的❌号就失去作用了,点击了也不会关闭,且在 el-dialog 中加上 show-close=false 也还是会显示,所以不得已用了CSS样式去控制)
/* 弹出英雄框不显示右上角X号按钮 */
.el-dialog__headerbtn .el-dialog__close {
display: none;
}
三、灰色的遮罩层在当前主题会显示为白色,然后就和 el-dialog 融为一体了,视觉效果很不好,所以这里修改了CSS样式
/* 弹出英雄选择框的背景遮罩 */
.v-modal {
background-color: rgba(0, 0, 0, 0.8);
}
四、在el-table中想实现选中行(这里会有变量在单击行的时候记录行索引),高亮,然后点击确定的操作,el-table 自己是支持选中的时候高亮的,但是颜色不太明显,所以这里用CSS修改了选中行的样式
/*弹出英雄框点击选中行的背景样式*/
.el-table__body tr.current-row>td {
background-color: #b8d0ecc9;
}
3.增删改查操作
3.1 新增
这里的新增就是在 el-table 中新增一行空的数据,也就相当于在 el-table 绑定的数组中新增一组空的数据,并将记录当前编辑行的变量赋值为新添加的行的索引
// 添加一行
AddRow: function () {
var data = {
line: this.tableData.length + 1,
date: null,
name: null,
address: null,
age: null,
num: null,
str1: null,
str2: null,
str2laber: null,
str3: null,
str4: null
}
this.tableData.push(data);
this.doubleclick = this.tableData.length;
},
3.2 删除
这里的删除会有两个操作的入口
3.2.1 el-table 中的单行删除,删除的时候会有确认框弹出(触发 Popover 的元素,使用 slot="reference" 的具名插槽)但是这里有个问题就是,删除了一行之后,下一行的 el-popover 依旧会弹出,可能使用官方的自定义指令 v-popover 能够解决这个问题,但是还不会用😂
<el-table-column label="操作" width="137%" align="center" fixed="right">
<template slot-scope="scope">
<el-popover trigger="click" placement="top" width="160">
<p>Are you sure to delete?</p>
<div align="center">
<el-button size="mini" type="danger" icon="el-icon-delete" circle @click="DeleteData(scope.$index, tableData)"></el-button>
</div>
<!-- slot="reference" 触发 Popover 的元素,使用 slot="reference" 的具名插槽 -->
<el-button size="mini" type="danger" slot="reference">删除</el-button>
</el-popover>
<!-- slot-scope="scope" 通过 Scoped slot 可以获取到 row, column, $index 和 store(table 内部的状态管理)的数据-->
<el-button size="mini" type="primary" @click="HandleEdit(scope.$index, scope.row)">编辑</el-button>
</template>
</el-table-column>
3.2.2 el-table 中的批量删除,通过前面勾选复选框,点击头上的删除按钮实现
复选框也是 el-table 中的一列,不需要绑定数据,选择事件是 selection-change ,参数是选中行的数组对象
<el-table class="tabledata" :data="tableData" :summary-method="getSummaries" show-summary
@row-dblclick="RowDblclick" @row-click="RowClick" @selection-change="SelectFun" stripe border
style="width: 100%">
<!-- type="selection" 复选框 -->
<el-table-column type="selection" align="center" width="60px"></el-table-column>
3.3 修改
整体的思路在上面 2.7 el-table实现行编辑 已经说了,这里贴一些示例代码把
v-show="doubleclick==scope.row.line" 就是判断双击事件记录的行索引是否等于当前的行索引,而单击行的时候会判断是否是单击的当前行,如果不是,则清空双击事件记录的行索引,从而实现编辑和不编辑
<el-table-column label="数值" width="120%" align="right">
<template slot-scope="scope">
<el-input v-show="doubleclick==scope.row.line" type="Number" placeholder="请输入内容"
v-model.number="scope.row.num" size="mini" clearable>
</el-input>
<span v-show="doubleclick!=scope.row.line">{{scope.row.num}}</span>
</template>
</el-table-column>
4.Element UI 主题风格
Element UI默认的主题风格是比较鲜艳活泼的,但是我想要比较克制,有灰度的主题风格(就是实现换主题风格)以适应之后工作上的需求,于是再一次偶然之中发现官网上可以自定义配置 Element UI 主题风格
5.Element UI 图标
由于没有项目工程,没有vue脚手架,引用的 Element UI 中的样式很多是需要有图标的,所以百度了很久都不知道要怎么加进来图标,直到有一天,看见别人说在请求的URL中发现了关于图标的线索,我才知道怎么去加 Element UI 图标
6.踩过的坑
6.1 行的索引
行的索引对于el-table的数据交互很重要,但是除了 slot-scope="scope" 插槽可以获得行的索引,或者官方某些少数的方法提供行索引参数外,其它的很难获取行索引,所以在此表格中 line 列就是提供了行索引的功能,但是在删除和新增操作之后,是需要动态及时的去调整的,如下代码
watch: {
// deep: true深度监听heroData(是弹出来的选择英雄框的el-table数据源)变化后重新计算行索引
heroData: {
handler: function (val, oldval) {
this.heroData = val;
for (var i = 0; i < this.heroData.length; i++) {
this.heroData[i].hero = i + 1;
}
},
deep: true
}
}
6.2 日期时间格式问题
选择时间标签,选择完时间后,返回的时间格式不是想要的,然后就需要自己再去转换时间格式
// 日期框的日期格式转换
DateFormats: function (date) {
if (date != null) {
var ss = typeof (date);
if (ss == 'string') {
return date;
}
var fmt = "yyyy-MM-dd"
var o = {
"M+": date.getMonth() + 1,//月份
"d+": date.getDate(),//日
"h+": date.getHours(),//小时
"m+": date.getMinutes(),//分
"s+": date.getSeconds(),//秒
"q+": Math.floor((date.getMonth() + 3) / 3), //季度
"S": date.getMilliseconds()//毫秒
};
if (/(y+)/.test(fmt))
fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o) {
if (new RegExp("(" + k + ")").test(fmt)) {
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
}
}
return fmt;
}
}
6.3 IE兼容问题
在快要完成的时候,发现IE上面页面是崩的,后来发现,是IE不兼容部分语法,主要是ES6中的箭头函数,及VUE中的methods中的方法的定义的问题
不兼容箭头函数 =>
// 输入字符选择英雄时触发事件,进行模糊匹配 /远程搜索方法,此方法可废除
RemoteMethod: function (query) {
if (query !== '') {
this.options_st2 = this.listStr2.filter(
// item => {
// return item.label.toLowerCase()
// .indexOf(query.toLowerCase()) > -1;
// }
function (item) {
return item.label.toLowerCase().indexOf(query.toLowerCase()) > -1;
}
);
}
else {
this.options_st2 = [];
}
}
methods中的方法必须用 : 去定义
// 选中table行的数据
SelectFun: function (val) {
this.deleteList = val;
},
6.4 loading转圈问题
在加载数据的时候模拟等待了两秒,以显示转圈的效果,结果把 this.loading = false; 写在了 setTimeout 方法外面就没有效果,写在里面就是OK的
// 数据初始化 钩子函数
mounted: function () {
setTimeout(() => { this.DataAdd(); this.loading = false; }, 2000);
}
7.写的很挫的代码
8.感受
8.1 感觉Element UI是一个非常‘牛皮’的UI框架,里面有一些很炫酷的控件标签,萌新入门难度不大,感觉比以前用过的Easy UI要好很多,不管是上手难度,还是本身提供的炫酷的控件标签
8.2 这次也初体验了一把VUE,将变量和标签双向绑定的这种方式,感觉像是把前端进行了一次内部分离,把显示的控件标签跟前端逻辑进行了分离,省去了很多Dome操作,在操作界面的时候就只需要考虑前端的逻辑,就不用再去关心取值赋值了
8.3 这么一个小小Hello World示例,中间也有搞不定的时候,这里感谢下大佬 温文的风灵行者 😳
完结撒花★,°:.☆( ̄▽ ̄)/$:.°★ 。