引言

在工作中遇到一个小问题,整个数据可展示的内容比较多,但可修改的只有一个备注。

想着单独做个备注页面不划算,太麻烦了,在当前页面做个弹框也比较麻烦,还需要控制显示隐藏弹框,做好之后还得刷新页面,太麻烦了。

所以干脆效果做在表格里,双击变成输入框,失去焦点的时候直接调用接口保存,就很舒服了。

效果展示

效果展示

实现步骤

我这人写教程喜欢按照思维顺序,一步一步来,如果不习惯这种方式的话,可以直接看我在最后给的源码复制。

1. 建立原始模板文件

如果你不是像我这样的demo的话,可以跳过这步,我主要是不想搭建一个vue项目那么麻烦了

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>ElementUI的示例页面</title>
  <!-- import CSS -->
  <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
</head>
<body>
  <div id="app">
    <el-button @click="visible = true">Button</el-button>
    <el-dialog :visible.sync="visible" title="Hello world">
      <p>Try Element</p>
    </el-dialog>
  </div>
</body>
  <!-- import Vue before Element -->
  <script src="https://unpkg.com/vue@2/dist/vue.js"></script>
  <!-- import JavaScript -->
  <script src="https://unpkg.com/element-ui/lib/index.js"></script>
  <script>
    new Vue({
      el: '#app',
      data: function() {
        return { visible: false }
      }
    })
  </script>
</html>

首先从ElementUI的官网把示例代码拷贝下来,资源用CDN的就可以了。

官网链接:https://element.eleme.cn/#/zh-CN

我这里给的链接是国内镜像的2.x版本,有其他需要的可以自己找

我指的是上面代码当中的这些部分:

<!-- import CSS -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">

<!-- import Vue before Element -->
<script src="https://unpkg.com/vue@2/dist/vue.js"></script>

<!-- import JavaScript -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>

2. 建立表格结构

然后把表格部分的代码复制过来,链接在这里

https://element.eleme.cn/#/zh-CN/component/table

包括<template></template>模板当中的HTML结构,还有<script></script>当中的js部分

我这里就当你不会vue,直接按照通用教程来讲哈~

拷贝过来整体结构是这样的:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>ElementUI的示例页面</title>
  <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
</head>
<body>
  <div id="app">
    <el-table
      :data="tableData"
      style="width: 100%">
      <el-table-column
        prop="date"
        label="日期"
        width="180">
      </el-table-column>
      <el-table-column
        prop="name"
        label="姓名"
        width="180">
      </el-table-column>
      <el-table-column
        prop="address"
        label="地址">
      </el-table-column>
    </el-table>
  </div>
</body>
  <script src="https://unpkg.com/vue@2/dist/vue.js"></script>
  <script src="https://unpkg.com/element-ui/lib/index.js"></script>
  <script>
    new Vue({
      el: '#app',
      data: function() {
        return {
          tableData: [{
            date: '2016-05-02',
            name: '王小虎',
            address: '上海市普陀区金沙江路 1518 弄'
          }, {
            date: '2016-05-04',
            name: '王小虎',
            address: '上海市普陀区金沙江路 1517 弄'
          }, {
            date: '2016-05-01',
            name: '王小虎',
            address: '上海市普陀区金沙江路 1519 弄'
          }, {
            date: '2016-05-03',
            name: '王小虎',
            address: '上海市普陀区金沙江路 1516 弄'
          }]
        }
      }
    })
  </script>
</html>

这时候,页面就有了基本形状,一个简单的表格输出

表格输出

3. 补充备注列和主键

然后你需要给其中一列进行处理,比如我需求是备注字段,就需要增加备注部分的代码

<el-table-column
  prop="remark"
  label="备注">
</el-table-column>

注意,底下的数据也要有对应的内容

new Vue({
  el: '#app',
  data: function() {
    return {
      tableData: [{
        date: '2016-05-02',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1518 弄',
        remark: "",
      }, {
        date: '2016-05-04',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1517 弄',
        remark: "",
      }, {
        date: '2016-05-01',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1519 弄',
        remark: "",
      }, {
        date: '2016-05-03',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1516 弄',
        remark: "小虎备注",
      }]
    }
  }
})

每一条记录都得有个remark字段,作为接口对接的话,后端会给你返回的。

实际项目当中,我们一般使用id或者uid作为处理的主键标识,在修改数据的时候,一般也是用这个作为这条数据的标识来进行修改的。

我们一并补上

new Vue({
  el: '#app',
  data: function() {
    return {
      tableData: [{
        id: 1,
        date: '2016-05-02',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1518 弄',
        remark: "",
      }, {
        id: 2,
        date: '2016-05-04',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1517 弄',
        remark: "",
      }, {
        id: 3,
        date: '2016-05-01',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1519 弄',
        remark: "",
      }, {
        id: 4,
        date: '2016-05-03',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1516 弄',
    remark: "小虎备注",
      }]
    }
  }
})

然后回到页面上来。页面此时应该有数据渲染了。

备注字段

4. 输入框制作,确定显示逻辑

然后我们开始做输入框,在上面的html结构里先动手

把备注栏的DOM结构变换一下

<el-table-column
  prop="remark"
  label="备注">
  <template slot-scope="scope">
      <span v-show="scope.row.id != editRowId">{{ scope.row.remark }}</span>
      <el-input v-model="scope.row.remark" v-show="scope.row.id == editRowId" />
  </template>
</el-table-column>

这里的<el-table-column></el-table-column>标签内,我们加了个<template></template>标签,用来替换掉原先的输出,用了个slot-scope="scope"占位符,表示要替换的位置。

里面包含一个<span></span>标签和一个<el-input />标签,分别用来输出数据的remark字段,和用来编辑这个字段。

核心在于这个v-show指令,代表可以显示隐藏这个DOM元素,这里有两个判断的表达式:

  1. scope.row.id != editRowId 当前行的id字段值不等于全局变量editRowId的值时展示
  2. scope.row.id == editRowId 当前行的id字段值等于全局变量editRowId的值时展示

这两个表达式和全局变量editRowId控制了这个页面具体显示输入框还是span标签。

下面的data部分也得把这个全局变量给声明了:

data: function() {
  return {
    // 编辑标识的id
    editRowId: 0,

    // 表格数据
    tableData: [{
      id: 1,
      date: '2016-05-02',
      name: '王小虎',
      address: '上海市普陀区金沙江路 1518 弄',
      remark: "",
    }, {
      id: 2,
      date: '2016-05-04',
      name: '王小虎',
      address: '上海市普陀区金沙江路 1517 弄',
      remark: "",
    }]
  }
}

现在你可以尝试把我这里第4行0分别改成1、2、3是什么效果了。

5. 自动修改变量值

接下来我们让程序“自己”去修改这个变量值

回到最前面,我们整个业务的需求是——“双击这一栏,输出文本变成输入框,失焦时保存并显示新文本”

那么我们就需要有两个事件,onBluronDblClick

这两个事件ElementUI都有提供给我们。

table组件底部方法

另一个是在el-input组件的文档里的。

https://element.eleme.cn/#/zh-CN/component/input

大家可以自己去看一下。

input组件文档的Events部分

实际用法是:

在顶部的DOM结构里,加入这个cell-dblclick的事件监听

<el-table
  @cell-dblclick="openRemarkEdit"
  :data="tableData"
  style="width: 100%">
  <!-- 我这里省略掉很多内容 -->
</el-table>

就是这里的第2行代码

然后输入框部分也得补充这个事件监听

<el-table-column
  prop="remark"
  label="备注">
  <template slot-scope="scope">
      <span v-show="scope.row.id != editRowId">{{ scope.row.remark }}</span>
      <el-input v-model="scope.row.remark" v-show="scope.row.id == editRowId" @blur="saveRemark(scope.row.remark)" />
  </template>
</el-table-column>

重点部分在第6行@blur="saveRemark(scope.row.remark)"

这两处补充涉及到2个方法,需要在下面methods当中定义(methods属性需要定义在跟data属性同级)

methods: {
    openRemarkEdit(row, column, cell, event) {
        if (column.property != 'remark') return ;
        this.editRowId = row.id
    },
    async saveRemark(remark) {
        if (!remark) return this.editRowId = 0;

        /*
        // 请求接口
        const resp = await this.$api.xxx(带的参数);
        if (resp.code == 200) this.$message.success('保存成功');
        else this.$message.error(resp.msg);
        */

        this.editRowId = 0;
    },
}

我这里的请求接口保存方法就省略了,看大家具体的接口方法名,为了方便,我这里的saveRemark还加了async标识,如果你的写法跟我不同,也可以省略掉

现在的功能就基本实现了,大家也可以点点看看,我这就不放演示视频了

源码展示

最后,把整个文件的源码放出来,写的不好,可以参考一下。

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>测试表格</title>
  <!-- import CSS -->
  <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
</head>
<body>
  <div id="app">
    <el-table
      @cell-dblclick="openRemarkEdit"
      :data="tableData"
      style="width: 100%">
      <el-table-column
        prop="date"
        label="日期"
        width="180">
      </el-table-column>

      <el-table-column
        prop="name"
        label="姓名"
        width="180">
      </el-table-column>

      <el-table-column
        prop="address"
        label="地址">
      </el-table-column>

      <el-table-column
        prop="remark"
        label="备注">
        <template slot-scope="scope">
            <span v-show="scope.row.id != editRowId">{{ scope.row.remark }}</span>
            <el-input v-model="scope.row.remark" v-show="scope.row.id == editRowId" @blur="saveRemark(scope.row.remark)" />
        </template>
      </el-table-column>

      <el-table-column
        prop="remark"
        label="备注">
        <template slot-scope="scope">
            <span v-show="scope.row.id != editRowId">{{ scope.row.remark }}</span>
            <el-input v-model="scope.row.remark" v-show="scope.row.id == editRowId" @blur="saveRemark(scope.row.remark)" />
        </template>
      </el-table-column>
    </el-table>
  </div>
</body>
  <!-- import Vue before Element -->
  <script src="https://unpkg.com/vue@2/dist/vue.js"></script>
  <!-- import JavaScript -->
  <script src="https://unpkg.com/element-ui/lib/index.js"></script>
  <script>
    new Vue({
        el: '#app',
        data: function() {
            return {
                // 编辑标识的id
                editRowId: 0,

                // 表格数据
                tableData: [{
                    id: 1,
                    date: '2016-05-02',
                    name: '王小虎',
                    address: '上海市普陀区金沙江路 1518 弄',
                    remark: "",
                }, {
                    id: 2,
                    date: '2016-05-04',
                    name: '王小虎',
                    address: '上海市普陀区金沙江路 1517 弄',
                    remark: "",
                }]
            }
        },
        methods: {
            openRemarkEdit(row, column, cell, event) {
                if (column.property != 'remark') return ;
                this.editRowId = row.id
            },
            async saveRemark(remark) {
                if (!remark) return this.editRowId = 0;

                /*
                // 请求接口
                const resp = await this.$api.xxx(带的参数);
                if (resp.code == 200) this.$message.success('保存成功');
                else this.$message.error(resp.msg);
                */

                this.editRowId = 0;
            },
        }
    })
  </script>
</html>

欢迎关注拓行公众号,分享各种技术博客文章

拓行——奋勇进取,开拓未来,砥砺前行

最后修改:2023 年 12 月 15 日
如果您对各种技术博客文章感兴趣,欢迎关注拓行公众号,分享各种专业技术知识~