el-table点击表格某一行添加到URL参数,访问带参URL加载表格内容并滚动到选中行位置 [Vue3] [Element-plus 2.3]

Vue3+Element-Plus实现点击表格行更新URL并自动滚动
文章讲述了在Vue3和Element-Plus2.3的环境下,如何实现在表格中点击行数据时更新URL参数,以便于分享,并在页面加载时根据URL参数选中对应行。当表格数据过多出现滚动条时,还能自动滚动到选中行的位置。

写在最前

需求:有个表格列出了一些行数据,每个行数据点击后会加载出对应的详细数据,想要在点击了某一行后,能够将该点击反应到URL中,这样我复制这个URL发给其他人,他们打开时也能看到同样的行数据。

url会根据点击动态更新,大概是这样 xxx.com?param1=var1&param2=var2

主要版本:vue3,element-plus 2.3 (element-plus版本2.0就不行,已踩坑issue)

实现

URL参数的动态更新与访问加载

下面封装了更新URL参数获取URL参数的方法

// 更新URL参数
function updateURLWithParams(paramsObj: any) {
    // 入参检查
    if (typeof paramsObj !== 'object' || paramsObj === null) {
        console.error('Invalid input. params must be an object.');
        return;
    }
    // 获取当前URL
    const url = new URL(window.location.href);
    // 创建基于当前URL的不含参数的URL对象
    const newUrl = new URL(url.origin + url.pathname);
    // 创建新的URLSearchParams
    const params = new URLSearchParams();
    // 添加搜索参数
    for (const key in paramsObj) {
        params.set(key, paramsObj[key]);
    }
    // 更新到新URL对象
    newUrl.search = params.toString();
    // 更新到浏览器history(地址栏改变)
    window.history.pushState('', '', newUrl.toString());
}

// 获取URL参数
function getQueryParamsFromURL() {
    const urlObj = new URL(window.location.href);
    const queryParams = urlObj.searchParams;
    const params: { [key: string]: string } = {};

    for (const [key, value] of queryParams.entries()) {
        params[key] = value;
    }

    return params;
}

然后在监听点击行数据的方法中调用即可。

handleRowClick(row: any, event: any, column: any) {
      // 加载数据的code...

      // 更新参数到URL,这里假设把row的id放到参数里面
      updateURLWithParams({ "row_id": row.id});
    },

在初始化页面后,需要根据URL中参数加载出对应的行数据。对应的代码如下:

created() {
  // 从URL中拿到搜索参数
  const row_id = getQueryParamsFromURL()["row_id"];
  // 如果参数不为空,遍历表格数据找到对应的行
  if (!!row_id) {
  // tableData是el-table绑定的表格数据,tableRef是绑定的引用对象
  // <el-table :data="tableData" ref="tableRef">
  for (let index = 0; index < this.tableData.length; index++) {
     if (this.tableData[index].id==row_id) {
         // 设置表格当前行为参数中指定的行,如果表格设置了高亮,则同时会高亮当前行
         this.$refs.tableRef.setCurrentRow(this.tableData[index]);
         // 然后可以加载对应的行数据
         // coding...
         break;
     }
  }
}

至此已经实现了,点击行数据更新URL参数,访问带参的URL会选中指定的行并加载对应数据。

但是如果表格数据过多,有滚动条了,这时候还不能自动滚动到当前选中的行。

所以需要手动实现。

获取选中行的偏移高度并滚动到该处

el-table提供了滚动到指定位置的方法,但是需要输入坐标或者偏移量。

Table 表格 | Element Plus (element-plus.org)

 这里使用setScrollTop方法,所以我们需要获取当前已选中行的偏移高度并设置为滚动位置,代码如下:

// 获取偏移高度, tableRef是table的引用对象,index是行的索引
const offsetTop = this.$refs.tableRef.$el.getElementsByClassName('el-table__row')[index].offsetTop;
// 设置滚动位置
this.$refs.tableRef.setScrollTop(offsetTop);
           

结合上面找到并选中参数中指定行的代码,最终实现如下:

created() {
  // 从URL中拿到搜索参数
  const row_id = getQueryParamsFromURL()["row_id"];
  // 如果参数不为空,遍历表格数据找到对应的行
  if (!!row_id) {
  // tableData是el-table绑定的表格数据,tableRef是绑定的引用对象
  // <el-table :data="tableData" ref="tableRef">
  for (let index = 0; index < this.tableData.length; index++) {
     if (this.tableData[index].id==row_id) {
         // 设置表格当前行为参数中指定的行,如果表格设置了高亮,则同时会高亮当前行
         this.$refs.tableRef.setCurrentRow(this.tableData[index]);
         // 获取偏移高度, tableRef是table的引用对象,index是行的索引
         const offsetTop = this.$refs.tableRef.$el.getElementsByClassName('el-table__row') [index].offsetTop;
         // 设置滚动位置
         this.$refs.tableRef.setScrollTop(offsetTop);
                    
         // 然后可以加载对应的行数据
         // coding...
         break;
     }
  }
}

总结

element-plus虽然很方便,但有时候不能直接满足需求,需要多查资料多摸索。另外本人不是专业前端,这里只是记录了一次有趣的解决问题的过程,如果有更优雅的解决方案,欢迎分享噢。

<template> <div class="all"> <div class="head"> <!-- <i class="el-icon-search"></i> --> <el-button plain icon="el-icon-search" type="success" size="mini" @click="searchByDataCode">查询</el-button> <el-button plain icon="el-icon-circle-plus-outline" type="success" size="mini" @click="dialogFormVisible = true">新增</el-button> <!-- 新增的弹出框 --> <el-dialog title="新增数据字典" :visible.sync="dialogFormVisible"> <el-form :model="formSub" label-width="80px"> <el-row> <el-col :span="8"> <el-form-item label="字典编码"> <el-input v-model="formSub.data_code" style="width:150px;"></el-input> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="字典名称"> <el-input v-model="formSub.data_name" style="width:150px;"></el-input> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="参数级别" > <el-input v-model="formSub.parameter_level" style="width:150px;"></el-input> </el-form-item> </el-col> </el-row> </el-form> <!-- 子项目表格 --> <el-button type="primary" size="mini" @click="addRow()">新增</el-button> <el-table :data="tableData2" border style="margin-top:5px;"> <el-table-column prop="item" label="编号" width="165"> <template slot-scope="scope"> <el-input ref="item" v-model="scope.row.item_id" style="width:150px;"></el-input> </template>> </el-table-column> <el-table-column prop="item" label="item编码" width="165"> <template slot-scope="scope"> <el-input ref="item" v-model="scope.row.item_code" style="width:150px;"></el-input> </template>> </el-table-column> <el-table-column prop="item" label="item状态" width="165"> <template slot-scope="scope"> <el-input ref="item" v-model="scope.row.item_state" style="width:150px;"></el-input> </template>> </el-table-column> <el-table-column prop="item" label="字典编码" width="180"> <template slot-scope="scope"> <el-input ref="item" v-model="scope.row.data_code" style="width:150px;"></el-input> </template>> </el-table-column> </el-table> <div slot="footer" class="dialog-footer"> <el-button @click="dialogFormVisible = false">取 消</el-button> <el-button type="primary" @click="addDataDictionary">确 定</el-button> </div> </el-dialog> <!-- <el-button type="warning" size="mini" @click="dialogFormVisible1 = true">修改</el-button> <el-button type="danger" size="mini">删除</el-button> --> </div> <el-form ref="form" :model="form" label-width="80px" style="margin-top:20px;"> <el-form-item label="字典编码:"> <el-input v-model="form.codeInput" placeholder="请输入" style="width:150px;"></el-input> </el-form-item> </el-form> <!-- 表格 --> <el-table ref="singleTable" :data="tableData" highlight-current-row @current-change="handleCurrentChange" @expand-change="listAllItemByDataCode" style="width: 100%;" border> <el-table-column type="expand"> <template slot-scope="props"> <!-- 展示子项目 --> <el-table :data="tableData1" max-height="800" border> <el-table-column prop="item_id" label="编号" ></el-table-column> <el-table-column prop="item_code" label="item编码" ></el-table-column> <el-table-column prop="item_state" label="item状态" ></el-table-column> <el-table-column prop="create_person" label="建档人" ></el-table-column> <el-table-column prop="create_time" label="建档时间" width="190"></el-table-column> <el-table-column prop="update_person" label="修改人" ></el-table-column> <el-table-column prop="update_time" label="修改时间" width="190"></el-table-column> <el-table-column prop="data_code" label="字典编码" ></el-table-column> </el-table> </template> </el-table-column> <el-table-column prop="data_code" label="字典编码" width="150"></el-table-column> <el-table-column prop="data_name" label="字典名称" ></el-table-column> <el-table-column prop="parameter_level" label="参数级别" ></el-table-column> <el-table-column prop="create_person" label="建档人" ></el-table-column> <el-table-column prop="create_time" label="建档时间" width="190" ></el-table-column> <el-table-column prop="update_person" label="修改人" ></el-table-column> <el-table-column prop="update_time" label="修改时间" width="190"></el-table-column> <el-table-column label="操作" width="200" fixed="right"> <template slot-scope="scope" > <el-button plain type="warning" size="small" @click="handleEdit(scope.$index, scope.row)">编辑</el-button> <el-button plain type="danger" size="small" @click="open(scope.row)">删除</el-button> <!-- deleteDataDictionary(scope.row) --> </template> </el-table-column> </el-table> <!-- 编辑弹出框 --> <el-dialog title="编辑数据字典" :visible.sync="editFormVisible" :height="800"> <el-form :model="formEdit" label-width="80px">· <el-row> <el-col :span="8"> <el-form-item label="字典编码"> <el-input v-model="formEdit.data_code" :readonly="true" ></el-input> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="字典名称"> <el-input v-model="formEdit.data_name" ></el-input> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="参数级别" > <el-input v-model="formEdit.parameter_level" ></el-input> </el-form-item> </el-col> </el-row> </el-form> <!-- 子项目表格 --> <el-button type="primary" size="mini" @click="addRow1()">新增</el-button> <el-button type="danger" size="mini" @click="deleteItem()">删除</el-button> <el-table :data="tableData3" ref="multipleTable" @selection-change="handleSelectionChange" border style="margin-top:5px;"> <el-table-column type="selection" width="55"> </el-table-column> <el-table-column prop="item" label="编号" > <template slot-scope="scope"> <el-input ref="item" v-model="scope.row.item_id" :readonly="true" style="width:150px;"></el-input> </template> </el-table-column> <el-table-column prop="item" label="item编号" > <template slot-scope="scope"> <el-input ref="item" v-model="scope.row.item_code" style="width:150px;"></el-input> </template> </el-table-column> <el-table-column prop="item" label="item状态" > <template slot-scope="scope"> <el-input ref="item" v-model="scope.row.item_state" style="width:150px;"></el-input> </template> </el-table-column> <el-table-column prop="item" label="字典编码" > <template slot-scope="scope"> <el-input ref="item" v-model="scope.row.data_code" style="width:150px;"></el-input> </template> </el-table-column> </el-table> <div slot="footer" class="dialog-footer"> <el-button @click="editFormVisible = false">取 消</el-button> <el-button type="primary" @click="updateDataDictionary()">确 定</el-button> </div> </el-dialog> <!-- 分页 --> <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange1" :current-page="page" :page-sizes="[5, 10, 20]" :page-size="limit" layout="total, sizes, prev, pager, next, jumper" :total="count"> </el-pagination> </div> </template> <script> import axios from &#39;axios&#39;; import { request } from "../../network/request"; export default { name: "DataDictionary", data() { return { //codeInput: &#39;&#39;, tableData: [],//外层表格初始值 tableData1:[],//子项表格初始值 tableData2:[{ item_id: &#39;&#39;, item_code: &#39;&#39;, item_state: &#39;&#39;, data_code: &#39;&#39; }],//新增表格初始值 page:1, limit:5, count: 0, form: { codeInput: &#39;&#39; }, dialogFormVisible: false,//弹出层初始为false formSub: { data_code:&#39;&#39;, data_name:&#39;&#39;, parameter_level:&#39;&#39; }, //编辑初始值设置 editFormVisible:false, formEdit:{ data_code:&#39;&#39;, data_name:&#39;&#39;, parameter_level:&#39;&#39; }, tableData3: [{ item_id: &#39;&#39;, item_code: &#39;&#39;, item_state: &#39;&#39;, data_code: &#39;&#39; }], dialogDelVisible: false, multipleSelection: [], deleteItemsIds:&#39;&#39; } }, mounted() { // 发ajax请求,用以获取表格初始数据 const url = &#39;http://localhost:9091/systemmanagement/dataDictionary/selectAll/&#39;+this.page+&#39;/&#39;+this.limit; axios.get(url).then( response => { //alert("查询成功"); //初始数据 this.tableData = response.data.data.dataDictionaryList; this.count = response.data.data.count; } ).catch( response => { console.log(err); }, ); }, methods: { // 初始页currentPage、初始每页数据数pagesize和数据data handleSizeChange: function (size) { this.limit = size; console.log(this.limit) //每页下拉显示数据 //发送请求新的数据 this.getDataByPagination(); }, handleCurrentChange1: function(page){ this.page = page; console.log(this.page) //点击第几页 this.getDataByPagination(); }, //分页修改后的查询 getDataByPagination(){ const url = &#39;http://localhost:9091/systemmanagement/dataDictionary/selectAll/&#39;+this.page+&#39;/&#39;+this.limit; axios.get(url).then( response => { //alert("查询成功"); //初始数据 this.tableData = response.data.data.dataDictionaryList; this.count = response.data.data.count; } ).catch( response => { console.log(err); }, ); }, // 中当前行 setCurrent(row) { this.$refs.singleTable.setCurrentRow(row); }, handleCurrentChange(val) { this.currentRow = val; }, // 根据DataCode查询数据 searchByDataCode(){ request({ url: "/systemmanagement/dataDictionary/searchByDataCode", method: "post", data: { data_code: this.form.codeInput } }) .then(response => { //成功 this.tableData = response.data.data.dataDictionaryList; this.count = response.data.data.count; }) .catch(err => { //失败 console.log(err); }); }, //查询子项目数据 listAllItemByDataCode(row,expandedRows){ request({ url: "/systemmanagement/dataDictionaryItem/selectAll/"+row.data_code // method: "post", // data: { // data_code: row.data_code // } }) .then(response => { //成功 this.tableData1 = response.data.data; }) .catch(err => { //失败 console.log(err); }); }, //添加数据字典 addDataDictionary(){ //var token = window.localStorage.getItem("token"); request({ url: "/systemmanagement/dataDictionary/addDataDictionary", method:"post", //headers:{"token":token}, data: { data_code: this.formSub.data_code, data_name: this.formSub.data_name, parameter_level: this.formSub.parameter_level } }) .then(response => { //成功 this.addDataItem(); }) .catch(err => { //失败 console.log(err); }); }, //添加子项目 addDataItem(){ //var token = window.localStorage.getItem("token");//获取登陆token this.dialogFormVisible = false; console.log(this.tableData2); request({ url: "/systemmanagement/dataDictionaryItem/addDataItem", method:"post", //headers:{"token":token}, data: { dataDictionaryItems: this.tableData2 } }) .then(response => { //成功 alert(response.data.message); this.tableData2=[], this.formSub.data_name = &#39;&#39;, this.formSub.data_code = &#39;&#39;, this.formSub.parameter_level = &#39;&#39; location.reload(); }) .catch(err => { //失败 console.log(err); }); }, //表格新增行 addRow() { this.tableData2.push({ item_id: &#39;&#39;, item_code: &#39;&#39;, item_state: &#39;&#39;, data_code: &#39;&#39; }); }, //点击按钮触发编辑 handleEdit(index, row) { this.editFormVisible = true; this.formEdit = Object.assign({}, row); console.log(this.formEdit); request({ url: "/systemmanagement/dataDictionaryItem/selectAll/"+row.data_code }) .then(response => { //成功 this.tableData3 = response.data.data; }) .catch(err => { //失败 console.log(err); }); }, //表格新增行 addRow1() { this.tableData3.push({ item_id: &#39;&#39;, item_code: &#39;&#39;, item_state: &#39;&#39;, data_code: &#39;&#39; }); }, //删除确认提示 open(row) { this.$confirm(&#39;此操作将永久删除该文件, 是否继续?&#39;, &#39;提示&#39;, { confirmButtonText: &#39;确定&#39;, cancelButtonText: &#39;取消&#39;, type: &#39;warning&#39; }).then(() => { //删除 this.dialogDelVisible = false; request({ url: "/systemmanagement/dataDictionary/deleteDataDictionary/"+row.data_code }) .then(response => { //成功 alert(response.data.message); location.reload(); }) .catch(err => { //失败 console.log(err); }); }).catch(() => { this.$message({ type: &#39;info&#39;, message: &#39;已取消删除&#39; }); }); }, //点击确认删除,删除DataDictionary deleteDataDictionary(row){ this.dialogDelVisible = false; request({ url: "/systemmanagement/dataDictionary/deleteDataDictionary/"+row.data_code }) .then(response => { //成功 alert(response.data.message); location.reload(); }) .catch(err => { //失败 console.log(err); }); }, //获取中的数据 handleSelectionChange(val) { this.multipleSelection = val; }, //删除编辑弹窗中的子项目 deleteItem(){ let items = this.multipleSelection; items.forEach(element => { this.deleteItemsIds = element.item_id+&#39;,&#39;; }); console.log(this.deleteItemsIds); // this.deleteItemsIds = items // .map(item => item.item_id) // .join(); request({ url: "/systemmanagement/dataDictionaryItem/deleteItem/"+this.deleteItemsIds }) .then(res => { this.$message({ message: res.data.message, type: "success" }); location.reload(); }) .catch(err => { this.$message.error(err); }); }, //修改数据 updateDataDictionary(){ //var token = window.localStorage.getItem("token"); this.editFormVisible = false; request({ url: "/systemmanagement/dataDictionary/updateDataDictionary", method:"post", //headers:{"token":token}, data: { data_code: this.formEdit.data_code, data_name: this.formEdit.data_name, parameter_level: this.formEdit.parameter_level } }) .then(response => { //成功 //location.reload(); this.updateItem(); }) .catch(err => { //失败 console.log(err); }); }, //修改子项数据 updateItem(){ //var token = window.localStorage.getItem("token"); //获取行数据 let item = this.multipleSelection; console.log(item[0].item_id); request({ url: "/systemmanagement/dataDictionaryItem/updateItem", method:"post", //headers:{"token":token}, data: { item_id: item[0].item_id, item_code: item[0].item_code, item_state: item[0].item_state, data_code: item[0].data_code } }) .then(response => { //成功 //location.reload(); }) .catch(err => { //失败 console.log(err); }); } } } </script> <style> .all{ margin-left: 20px; } .search-module{ margin-top: 20px; float: left; } .el-table td, .el-table th { text-align: center; padding: 5px 0; } </style>
08-19
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值