记录Element UI实现简单的Table行编辑

(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

这里遇到了四个样式的问题:

一、点击灰色部分时需要不关闭此弹框(这个是在 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.写的很挫的代码

百度云提取码:55k7

8.感受

8.1 感觉Element UI是一个非常‘牛皮’的UI框架,里面有一些很炫酷的控件标签,萌新入门难度不大,感觉比以前用过的Easy UI要好很多,不管是上手难度,还是本身提供的炫酷的控件标签

8.2 这次也初体验了一把VUE,将变量和标签双向绑定的这种方式,感觉像是把前端进行了一次内部分离,把显示的控件标签跟前端逻辑进行了分离,省去了很多Dome操作,在操作界面的时候就只需要考虑前端的逻辑,就不用再去关心取值赋值了

8.3 这么一个小小Hello World示例,中间也有搞不定的时候,这里感谢下大佬 温文的风灵行者 😳

完结撒花★,°:.☆( ̄▽ ̄)/$:.°★

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容