文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

基于Vue实现跨表格(单选、多选表格项,单表格限制)相互拖拽

2024-12-14 01:05

关注

什么需求呢?就是多个表格之间可以实现相互拖拽,即A表格中的表格项可以拖拽到B表格,B表格的表格项可以拖拽到C表格,并且它们之间可以单选、多选表格项相互拖拽。然后,D表格加以限制,每次只能够拖入一项,需输入密码,密码正确后,被拖入的一项替换D表格中的表格项,被替换的D表格项放入A表格,只能被替换,不能被删除。

文字太枯燥,我们放一张动图来看下效果。

上面提到的A、B、C、D表格与下图游客、操作员、电工、管理员一一对应。


此图非静止~

实战

既然,我们知道了要实现怎样的效果,那么我们就开工吧!

第一步

需要确定我们这个需求需要安装哪些依赖。

初始化项目之后,安装以上依赖。你可以在package.json文件中看到:

  1. "dependencies": { 
  2.   "element-ui""^2.15.5"
  3.   "sortablejs""^1.14.0"
  4.   "vue""^2.6.11" 
  5. }, 

第二步

引入ElementUI,具体怎么引入,可以查看ElementUI官网,这里不过多阐述了。然后,我们在目录src\components(假设你有这个文件夹)文件夹下创建一个文件夹,名字姑且叫DragTables。在文件夹中,我们再创建一个utils文件夹与index.vue文件。在utils文件夹中我们再创建两个文件:data.js与index.js。

即文件目录结构为:

  1. - components 
  2. -- DragTables 
  3. --- utils 
  4. ---- data.js 
  5. ---- index.js 
  6. --- index.vue 

第三步

utils\data.js文件是存放数据的文件,而utils\index.js则是工具函数文件。

现在我们先来定义数据。

  1. // data.js 
  2. export default { 
  3.     // 游客 
  4.     guestData: [ 
  5.     { 
  6.         userId: "1"
  7.         name"a1"
  8.         account: "w"
  9.         jobTit: '1'
  10.         auth: '1' 
  11.     }, 
  12.     { 
  13.         userId: "211"
  14.         name"a0"
  15.         account: "w"
  16.         jobTit: '1'
  17.         auth: '1' 
  18.     } 
  19.     ], 
  20.     // 管理员 
  21.     managerData: [ 
  22.     { 
  23.         userId: "121"
  24.         name"a2"
  25.         account: "w"
  26.         jobTit: '1'
  27.         auth: '1' 
  28.     } 
  29.     ], 
  30.     // 电工 
  31.     electricianData: [ 
  32.     { 
  33.         userId: "12121"
  34.         name"a3"
  35.         account: "w"
  36.         jobTit: '1'
  37.         auth: '1' 
  38.     } 
  39.     ], 
  40.     // 操作员 
  41.     operatorData: [ 
  42.     { 
  43.         userId: "133e"
  44.         name"a4"
  45.         account: "w"
  46.         jobTit: '1'
  47.         auth: '1' 
  48.     } 
  49.     ] 

userId必须是唯一的。

然后,我们接着定义工具函数,这里我们需要一个深拷贝方法,我们把它定义在utils\index.js文件中。

  1. // utils\index.js 
  2.  
  3.  
  4. export function deepClone(target) { 
  5.     // 定义一个变量 
  6.     let result; 
  7.     // 如果当前需要深拷贝的是一个对象的话 
  8.     if (typeof target === 'object') { 
  9.         // 如果是一个数组的话 
  10.         if (Array.isArray(target)) { 
  11.             result = []; // 将result赋值为一个数组,并且执行遍历 
  12.             for (let i in target) { 
  13.                 // 递归克隆数组中的每一项 
  14.                 result.push(deepClone(target[i])); 
  15.             } 
  16.             // 判断如果当前的值是null的话;直接赋值为null 
  17.         } else if (target === null) { 
  18.             result = null
  19.             // 判断如果当前的值是一个RegExp对象的话,直接赋值 
  20.         } else if (target.constructor === RegExp) { 
  21.             result = target; 
  22.         } else { 
  23.             // 否则是普通对象,直接for in循环,递归赋值对象的所有值 
  24.             result = {}; 
  25.             for (let i in target) { 
  26.                 result[i] = deepClone(target[i]); 
  27.             } 
  28.         } 
  29.         // 如果不是对象的话,就是基本数据类型,那么直接赋值 
  30.     } else { 
  31.         result = target; 
  32.     } 
  33.     // 返回最终结果 
  34.     return result; 

第四步

做完了准备工作,我们就可以进入DragTables\index.vue进行最重要的实战环节。我们先把代码分区域列出来。

1. UI页面代码

  1.  
  2.             table-column
  3.           table
  4.         
 
  •       
  •  
  •       "main-r"
  • -- 管理员 --> 
  •         "top-name"
  •           

    管理员

     
  •          
  •         table 
  •           ref="managerData" 
  •           :data="managerData" 
  •           :row-key="getUserId" 
  •           style="width: 100%; border: 1px solid #002368; margin-bottom: 10px" 
  •         > 
  •           table-column 
  •             prop="name" 
  •             label="姓名" 
  •             align="center" 
  •             show-overflow-tooltip 
  •           > 
  •           table-column
  •           table-column 
  •             prop="account" 
  •             label="账号" 
  •             align="center" 
  •             show-overflow-tooltip 
  •           > 
  •           table-column
  •           table-column 
  •             prop="jobTit" 
  •             label="职务" 
  •             align="center" 
  •             style="position: relative" 
  •             show-overflow-tooltip 
  •           > 
  •             "scope"
  •               {{ scope.row.jobTit }} 
  •              
  •           table-column
  •         table
  • -- 操作员 --> 
  •         "top-name"
  •           "top-box"
  •             "top-count"
  •               人数: 
  •               {{ 
  •                 initStatus.newOperatorList 
  •                   ? operatorData.length 
  •                   : newOperatorList.length 
  •               }} 
  •              
  •            
  •           

    操作员

     
  •          
  •         "table-b"
  •           "table-box"
  •             table 
  •               ref="operatorData" 
  •               class="table-l" 
  •               :data="operatorData" 
  •               :row-key="getUserId" 
  •               style="margin-bottom: 20px" 
  •               @row-click="operatorDataSelect" 
  •               @selection-change="selectionOperatorChange" 
  •             > 
  •               table-column type="selection" width="55"table-column
  •               table-column 
  •                 prop="name" 
  •                 label="姓名" 
  •                 align="center" 
  •                 show-overflow-tooltip 
  •               > 
  •               table-column
  •               table-column 
  •                 prop="account" 
  •                 label="账号" 
  •                 align="center" 
  •                 show-overflow-tooltip 
  •               > 
  •               table-column
  •               table-column 
  •                 prop="jobTit" 
  •                 label="职务" 
  •                 align="center" 
  •                 show-overflow-tooltip 
  •               >table-column
  •               table-column align="center" label="操作"
  •                  
  •               table-column
  •             table
  •            
  •          
  • -- 电工 --> 
  •         "top-name"
  •           "top-box"
  •             "top-count"
  •               人数: 
  •               {{ 
  •                 initStatus.newElectricianList 
  •                   ? electricianData.length 
  •                   : newElectricianList.length 
  •               }} 
  •              
  •            
  •           

    电工

     
  •          
  •         "table-b"
  •           "table-box"
  •             table 
  •               ref="electricianData" 
  •               :data="electricianData" 
  •               :row-key="getUserId" 
  •               @row-click="electricianDataSelect" 
  •               class="table-l" 
  •               @selection-change="selectionElectricianChange" 
  •             > 
  •               table-column type="selection" width="55"table-column
  •               table-column 
  •                 prop="name" 
  •                 label="姓名" 
  •                 align="center" 
  •                 show-overflow-tooltip 
  •               > 
  •               table-column
  •               table-column 
  •                 prop="account" 
  •                 label="账号" 
  •                 align="center" 
  •                 show-overflow-tooltip 
  •               > 
  •               table-column
  •               table-column 
  •                 prop="jobTit" 
  •                 label="职务" 
  •                 align="center" 
  •                 show-overflow-tooltip 
  •               >table-column
  •               table-column align="center" label="操作"
  •                  
  •               table-column
  •             table
  •            
  •          
  •        
  • -- 密码弹窗 --> 
  •       "passwordView"  width="30%"
  •         "form"
  •            
  •             
  •               v-model="password" 
  •               placeholder="请输入密码" 
  •               type="password" 
  •               show-password 
  •             > 
  •            
  •          
  •         "footer" class="dialog-footer"
  •           "passwordView = false">取 消 
  •           "primary" @click="okChangeManager" 
  •             >确 定
  •           > 
  •          
  •        
  •      
  •  
  • 分为五个部分:游客表格、管理员表格、操作员表格、电工表格、密码弹窗。每个表格的左上角动态显示表格内的人数。另外,就上面的那个动图来看,如果有一个表格与其他的表格样式布局不统一怎么办?就比如这里的电工表格、操作员表格就与游客表格、管理员表格布局样式不一样,多出来一个操作项。我是这样处理的,我把它们找出相同的部分,即都有姓名、账号、职务这三个项。电工表格、操作员表格只是多出来一个操作项。那就可以把它分成两个表格,操作项单独一个表格。只要监听电工表格或者操作员表格它们对应的数据长度就可以实现同步。为什么要分成两个表格呢?是因为,如果你从游客这个表格拖入到操作员这个表格,因为在游客表格没有操作这个选项,所以当你拖入到操作员表格时,就不会有操作这个选项(这是因为使用的拖拽的插件只是复制对应Node节点)。那肯定不行啊!

    2. 逻辑代码

    1.  

    我们这里使用的拖拽插件是sortablejs,功能非常强大。我这里就简单介绍下它的使用。

    1. Sortable.create(el,{}) 

    这里,需要给Sortable对象下的create方法传入两个参数,第一个参数是el节点,这个节点是定义可拖拽的每一项,如:

    1. const el = this.$refs.guestData.$el.querySelectorAll( 
    2.   ".el-table__body-wrapper > table> tbody" 
    3. )[0]; 

    这里的意思就是游客表格中的表格项。

    第二个参数是可配置参数,可以定义配置属性与方法。详情参数与方法可以参照中文官网:http://www.sortablejs.com/。

    下面,我们将分层来讲解逻辑实现。data方法中返回的对象我们看到只是初始化了一些数据,这里先不过多阐述。然后到了watch属性,它监听了data方法中返回的对象的passwordView属性,并对应的监听方法是watchPasswordView。

    我们往下面methods属性中找到,就是简单地对密码框中的内容每次初始化(置空)。

    1. // 密码框置空 
    2. watchPasswordView(val) { 
    3.   if (!val) { 
    4.     this.password = ""
    5.   } 
    6. }, 

    然后,我们进入了created方法,我们主要做了两件事,一件事是定义了一个静态对象(没有定义在data方法中,所以没有做响应式处理,为了性能优化),另一件事是获取表格数据。

    1. created() { 
    2. // 定义静态数据 
    3. this.obj = { 
    4.   newGuestList: ["guestData", 0], 
    5.   newManagerList: ["managerData", 3], 
    6.   newOperatorList: ["operatorData", 1], 
    7.   newElectricianList: ["electricianData", 2], 
    8. }; 
    9. // 获取表格数据 
    10. this.guestData = tableData.guestData; 
    11. this.managerData = tableData.managerData; 
    12. this.electricianData = tableData.electricianData; 
    13. this.operatorData = tableData.operatorData; 
    14. }, 

    然后,我们进入mounted方法,我们看到方法中调用了这几个拖拽表格方法,为什么会放在mounted方法中呢?是因为要想使用拖拽,必须等到实例被挂载后调用。

    最后,我们将进入methods属性,这里定义了很多方法,下面我们还是分功能部分开始分析。

    1. mounted() { 
    2.     this.sortGuest(); 
    3.     this.sortOperator(); 
    4.     this.sortElectrician(); 
    5.     this.sortManager(); 

    这几个方法主要是点击对应表格项进行勾选。

    1. // 选择游客 
    2. guestDataSelect(row) { 
    3.   row.flag = !row.flag; 
    4.   this.$refs.guestData.toggleRowSelection(row, row.flag); 
    5. }, 
    6. // 选择操作员 
    7. operatorDataSelect(row) { 
    8.   row.flag = !row.flag; 
    9.   this.$refs.operatorData.toggleRowSelection(row, row.flag); 
    10. }, 
    11. // 选择电工 
    12. electricianDataSelect(row) { 
    13.   row.flag = !row.flag; 
    14.   this.$refs.electricianData.toggleRowSelection(row, row.flag); 

    将选择的表格项数据存起来。

    1. // 监听游客表格选择 
    2. selectionGuestChange(val) { 
    3.   this.selectGuestList = val; 
    4. }, 
    5. // 监听操作员表格选择 
    6. selectionOperatorChange(val) { 
    7.   this.selectOperatorList = val; 
    8. }, 
    9. // 监听电工表格选择 
    10. selectionElectricianChange(val) { 
    11.   this.selectElectricianList = val; 

    为每一表格项定义一个唯一的key。

    1. // 获取userId 
    2. getUserId(row) { 
    3.   return row.userId; 
    4. }, 

    我们进入关键部分,也就是拖拽。是不是看起来代码特别多,其实这块还可以优化,但是为了更容易分辨,先这样。我们看到这几个方法中都有一个相同的部分,就是先定义el变量,然后执行Sortable.create(el, {})方法,另外,Sortable.create()的第二个参数中,都有onStart()、onAdd()、onEnd()这几个方法。

    1. // 拖拽游客 
    2. sortGuest() { 
    3.   const el = this.$refs.guestData.$el.querySelectorAll( 
    4.     ".el-table__body-wrapper > table> tbody" 
    5.   )[0]; 
    6.   Sortable.create(el, { 
    7.     ghostClass: "sortable-ghost"
    8.     sort: false
    9.     animation: 150, 
    10.     group: { 
    11.       name"person"
    12.       pull: true
    13.       put: true
    14.     }, 
    15.     setData: function ( 
    16.        dataTransfer, 
    17.        dragEl 
    18.     ) { 
    19.       dataTransfer.setData("Text", dragEl.textContent); // `dataTransfer` object of HTML5 DragEvent 
    20.     }, 
    21.     onStart: () => { 
    22.       this.useInitData("newGuestList", this.guestData); // 初始化 
    23.     }, 
    24.     onAdd: (evt) => { 
    25.       this.useReduction(0); 
    26.       if (this[`select${this.fromItem.split("new")[1]}`].length === 0) { 
    27.         this.useAddNewData(evt, "newGuestList", this.guestData); 
    28.       } else { 
    29.         this.useAddsNewData(evt, "newGuestList", this.guestData); 
    30.       } 
    31.     }, 
    32.     onEnd: (ev) => { 
    33.       if (this[`select${this.fromItem.split("new")[1]}`].length !== 0) { 
    34.         this.useReduction(0); 
    35.         if (ev.to.outerText.indexOf("管理员") !== -1) { 
    36.           this.$nextTick(() => { 
    37.             this.newGuestList = deepClone(this.guestData); 
    38.             const data = deepClone(this.guestData); 
    39.             this.guestData = data; 
    40.           }); 
    41.         } else { 
    42.           const data = deepClone(this.guestData); 
    43.           this.newGuestList = deepClone(this.guestData); 
    44.           this.guestData = []; 
    45.           this.$nextTick(() => { 
    46.             this.guestData = data; 
    47.           }); 
    48.         } 
    49.       } else { 
    50.         this.$nextTick(() => { 
    51.           this.guestData = this.newGuestList; 
    52.         }); 
    53.       } 
    54.     }, 
    55.   }); 
    56. }, 
    57. // 拖拽操作员 
    58. sortOperator() { 
    59.   const el = this.$refs.operatorData.$el.querySelectorAll( 
    60.     ".el-table__body-wrapper > table> tbody" 
    61.   )[0]; 
    62.   Sortable.create(el, { 
    63.     ghostClass: "sortable-ghost"
    64.     sort: false
    65.     animation: 150, 
    66.     group: { 
    67.       name"person"
    68.       pull: true
    69.       put: true
    70.     }, 
    71.     setData: function ( 
    72.        dataTransfer, 
    73.        dragEl 
    74.     ) { 
    75.       dataTransfer.setData("Text", dragEl.textContent); // `dataTransfer` object of HTML5 DragEvent 
    76.     }, 
    77.     onStart: () => { 
    78.       this.useInitData("newOperatorList", this.operatorData); // 初始化 
    79.     }, 
    80.     onAdd: (evt) => { 
    81.       this.useReduction(1); 
    82.       if (this[`select${this.fromItem.split("new")[1]}`].length === 0) { 
    83.         this.useAddNewData(evt, "newOperatorList", this.operatorData); 
    84.       } else { 
    85.         this.useAddsNewData(evt, "newOperatorList", this.operatorData); 
    86.       } 
    87.     }, 
    88.     onEnd: (ev) => { 
    89.       if (this[`select${this.fromItem.split("new")[1]}`].length !== 0) { 
    90.         this.useReduction(1); 
    91.         if (ev.to.outerText.indexOf("管理员") !== -1) { 
    92.           this.$nextTick(() => { 
    93.             this.newOperatorList = deepClone(this.operatorData); 
    94.             const data = deepClone(this.operatorData); 
    95.             this.operatorData = data; 
    96.           }); 
    97.         } else { 
    98.           const data = deepClone(this.operatorData); 
    99.           this.newOperatorList = deepClone(this.operatorData); 
    100.           this.operatorData = []; 
    101.           this.$nextTick(() => { 
    102.             this.operatorData = data; 
    103.           }); 
    104.         } 
    105.       } else { 
    106.         this.$nextTick(() => { 
    107.           this.operatorData = this.newOperatorList; 
    108.         }); 
    109.       } 
    110.     }, 
    111.   }); 
    112. }, 
    113. // 拖拽电工 
    114. sortElectrician() { 
    115.   const el = this.$refs.electricianData.$el.querySelectorAll( 
    116.     ".el-table__body-wrapper > table> tbody" 
    117.   )[0]; 
    118.   Sortable.create(el, { 
    119.     ghostClass: "sortable-ghost"
    120.     sort: false
    121.     animation: 150, 
    122.     group: { 
    123.       name"person"
    124.       pull: true
    125.       put: true
    126.     }, 
    127.     setData: function ( 
    128.        dataTransfer, 
    129.        dragEl 
    130.     ) { 
    131.       dataTransfer.setData("Text", dragEl.textContent); // `dataTransfer` object of HTML5 DragEvent 
    132.     }, 
    133.     onStart: () => { 
    134.       this.useInitData("newElectricianList", this.electricianData); // 初始化 
    135.     }, 
    136.     onAdd: (evt) => { 
    137.       this.useReduction(2); 
    138.       if (this[`select${this.fromItem.split("new")[1]}`].length === 0) { 
    139.         this.useAddNewData(evt, "newElectricianList", this.electricianData); 
    140.       } else { 
    141.         this.useAddsNewData( 
    142.           evt, 
    143.           "newElectricianList"
    144.           this.electricianData 
    145.         ); 
    146.       } 
    147.     }, 
    148.     onEnd: (ev) => { 
    149.       if (this[`select${this.fromItem.split("new")[1]}`].length !== 0) { 
    150.         this.useReduction(2); 
    151.         if (ev.to.outerText.indexOf("管理员") !== -1) { 
    152.           this.$nextTick(() => { 
    153.             this.newElectricianList = deepClone(this.electricianData); 
    154.             const data = deepClone(this.electricianData); 
    155.             this.electricianData = data; 
    156.           }); 
    157.         } else { 
    158.           const data = deepClone(this.electricianData); 
    159.           this.newElectricianList = deepClone(this.electricianData); 
    160.           this.electricianData = []; 
    161.           this.$nextTick(() => { 
    162.             this.electricianData = data; 
    163.           }); 
    164.         } 
    165.       } else { 
    166.         this.$nextTick(() => { 
    167.           this.electricianData = this.newElectricianList; 
    168.         }); 
    169.       } 
    170.     }, 
    171.   }); 
    172. }, 
    173. // 拖拽管理员 
    174. sortManager() { 
    175.   const el = this.$refs.managerData.$el.querySelectorAll( 
    176.     ".el-table__body-wrapper > table > tbody" 
    177.   )[0]; 
    178.   Sortable.create(el, { 
    179.     ghostClass: "sortable-ghost"
    180.     sort: false
    181.     animation: 150, 
    182.     group: { 
    183.       name"person"
    184.       pull: false
    185.       put: true
    186.     }, 
    187.     setData: function ( 
    188.        dataTransfer, 
    189.        dragEl 
    190.     ) { 
    191.       dataTransfer.setData("Text", dragEl.textContent); // `dataTransfer` object of HTML5 DragEvent 
    192.     }, 
    193.     onAdd: (evt) => { 
    194.       console.log(evt) 
    195.       switch (this.fromItem) { 
    196.         case "newGuestList"
    197.           { 
    198.             const data = deepClone(this.guestData); 
    199.             this.guestData = []; 
    200.             this.$nextTick(() => { 
    201.               this.guestData = data; 
    202.             }); 
    203.           } 
    204.           break; 
    205.         case "newOperatorList"
    206.           { 
    207.             const data = deepClone(this.operatorData); 
    208.             this.operatorData = []; 
    209.             this.$nextTick(() => { 
    210.               this.operatorData = data; 
    211.             }); 
    212.           } 
    213.           break; 
    214.         case "newElectricianList"
    215.           { 
    216.             const data = deepClone(this.electricianData); 
    217.             this.electricianData = []; 
    218.             this.$nextTick(() => { 
    219.               this.electricianData = data; 
    220.             }); 
    221.           } 
    222.           break; 
    223.         default
    224.           break; 
    225.       } 
    226.       if (this[`select${this.fromItem.split("new")[1]}`].length < 2) { 
    227.         this.managerOldIndex = evt.oldIndex; 
    228.         this.passwordView = true
    229.       } else { 
    230.         this.$message({ 
    231.           message: "批量失败!"
    232.           type: "warning"
    233.         }); 
    234.       } 
    235.       this.$refs.managerData.$el 
    236.         .querySelectorAll(".el-table__body-wrapper > table > tbody")[0] 
    237.         .removeChild(evt.item); 
    238.     }, 
    239.   }); 
    240. }, 

    因为onStart()、onAdd()、onEnd()这几个方法在sortGuest()以及其与几个拖拽方法中逻辑都差不多,所以我们就单独摘出sortGuest()方法进行分析下。

    首先,可以看到onStart()方法中调用了this.useInitData(),意思就是当你开始拖拽的时候调用this.useInitData()方法,这个方法第一个参数传一个字符串,第二个参数传一个数组,即当前表格数据。这个方法做了两个工作,一是定义一个开始拖拽时记录当前表格的标识,二是将当前表格的数据克隆到新数组中。

    1. // 封装初始化数据 
    2. useInitData(fromItem, oldData) { 
    3.   this.fromItem = fromItem; 
    4.   this[fromItem] = this.initStatus[fromItem] 
    5.     ? deepClone(oldData) 
    6.     : deepClone(this[fromItem]); 
    7.   this.initStatus[fromItem] = false

    然后,我们再分析onAdd()方法,它的意思是当被拖入添加到当前表格时触发。这个方法中做了两项工作,一是调用了useReduction方法,二是根据旧表格项是否有选择数据来调用不同的方法。

    1. onAdd: (evt) => { 
    2.     this.useReduction(0); 
    3.     if (this[`select${this.fromItem.split("new")[1]}`].length === 0) { 
    4.       this.useAddNewData(evt, "newGuestList", this.guestData); 
    5.     } else { 
    6.       this.useAddsNewData(evt, "newGuestList", this.guestData); 
    7.     } 

    以下是useReduction方法。

    1. // 还原初始状态 
    2. useReduction(i) { 
    3.   const arr = [ 
    4.     { 
    5.       data: "guestData"
    6.       sletData: "selectGuestList"
    7.     }, 
    8.     { 
    9.       data: "operatorData"
    10.       sletData: "selectOperatorList"
    11.     }, 
    12.     { 
    13.       data: "electricianData"
    14.       sletData: "selectElectricianList"
    15.     }, 
    16.   ]; 
    17.  
    18.   this.$refs[arr[i].data].clearSelection(); // 将选中的勾选框置空 
    19.   this[arr[i].sletData] = []; // 将选择数据置空 

    接着,我们来看下useAddNewData()方法,这个方法是封装了一个拖拽添加单项的方法。第一个参数是onAdd()方法中的第一个参数,第二个参数是一个字符串,即新数据的标识,第三个参数是当前被添加的表格数据对象。

    首先,我们取到需要添加的表格项,然后使用this.$loading()方法首先一个数据加载动画。更新新旧数据,将当前项添加到当前表格,并且删除旧表格中的数据,使用removeChild方法删除页面元素。

    useAddsNewData方法同理,只不过遍历选择数据。

    1. // 封装添加数据 
    2. useAddNewData(evt, newData, oldData) { 
    3.   const item = this[this.fromItem][evt.oldIndex]; // 添加项 
    4.  
    5.   const loading = this.$loading({ 
    6.     lock: true
    7.     text: "加载中"
    8.     spinner: "el-icon-loading"
    9.     background: "rgba(0, 0, 0, 0.7)"
    10.   }); 
    11.  
    12.   setTimeout(() => { 
    13.     loading.close(); 
    14.     this.$message({ 
    15.       message: "拖拽成功!"
    16.       type: "success"
    17.     }); 
    18.   }, 1000); 
    19.  
    20.   this[newData] = this.initStatus[newData] 
    21.     ? deepClone(oldData) 
    22.     : deepClone(this[newData]); 
    23.   this.initStatus[newData] = false
    24.   oldData.push(item); 
    25.   this[newData].push(item); 
    26.   this[this.fromItem].splice(evt.oldIndex, 1); 
    27.   this.$refs[this.obj[newData][0]].$el 
    28.     .querySelectorAll(".el-table__body-wrapper > table > tbody")[0] 
    29.     .removeChild(evt.item); 
    30. }, 
    31.  
    32. // 封装添加(多)数据 
    33. useAddsNewData(evt, newData, oldData) { 
    34.   const arr = []; 
    35.   for ( 
    36.     let index = 0; 
    37.     index < this[`select${this.fromItem.split("new")[1]}`].length; 
    38.     index++ 
    39.   ) { 
    40.     const element = this[`select${this.fromItem.split("new")[1]}`][index]; 
    41.     arr.push(element.userId); 
    42.   } 
    43.   const loading = this.$loading( 
    44.     lock: true
    45.     text: "加载中"
    46.     spinner: "el-icon-loading"
    47.     background: "rgba(0, 0, 0, 0.7)"
    48.   }); 
    49.  
    50.   setTimeout(() => { 
    51.     loading.close(); 
    52.     this.$message({ 
    53.       message: "批量拖拽成功!"
    54.       type: "success"
    55.     }); 
    56.   }, 1000); 
    57.   this[newData] = this.initStatus[newData] 
    58.     ? deepClone(oldData) 
    59.     : deepClone(this[newData]); 
    60.   this.initStatus[newData] = false
    61.   this[newData].push(...this[`select${this.fromItem.split("new")[1]}`]); 
    62.   this[this.obj[newData][0]].push( 
    63.     ...this[`select${this.fromItem.split("new")[1]}`] 
    64.   ); 
    65.   this.useDel( 
    66.     this[`select${this.fromItem.split("new")[1]}`], 
    67.     this[this.obj[this.fromItem][0]] 
    68.   ); 
    69.   this.$refs[this.obj[newData][0]].$el 
    70.     .querySelectorAll(".el-table__body-wrapper > table > tbody")[0] 
    71.     .removeChild(evt.item); 
    72. }, 

    我们在useAddsNewData方法中有一个方法是useDel方法,这个方法的作用是批量删除数组中的元素,这里旧数据删除指定项。

    1. // 批量删除(数组) 
    2. useDel(data, currentData) { 
    3.   for (let i = 0; i < data.length; i++) { 
    4.     const element = data[i]; 
    5.     for (let j = 0; j < currentData.length; j++) { 
    6.       const item = currentData[j]; 
    7.       if (item === element) { 
    8.         currentData.splice(j, 1); 
    9.       } 
    10.     } 
    11.   } 
    12. }, 

    我们还有最后一个方法okChangeManager(),这个方法最外层是判断密码是否为空,我这里简化了逻辑,这里本来是需要调用接口来,但是为了好理解,所以先忽视这部分。同样,我们需要获取被添加项,因为添加项只能是一个,所以这地方我们直接看条件允许的情况下。我们需要知道被添加项添加到管理员数据表格中,原先的数据会被移到游客表格,并且被添加项从原始表格数据中删除。

    1. // 确定拖拽到管理员 
    2. okChangeManager() { 
    3.   if (this.password.trim().length > 0) { 
    4.     const item = this[this.fromItem][this.managerOldIndex]; // 添加项 
    5.     if (item) { 
    6.       this.newManagerList = this.initStatus.newManagerList 
    7.         ? deepClone(this.managerData) 
    8.         : deepClone(this.newManagerList); 
    9.       this.newGuestList = this.initStatus.newGuestList 
    10.         ? deepClone(this.guestData) 
    11.         : deepClone(this.newGuestList); 
    12.       this.initStatus.newGuestList = false
    13.       this.initStatus.newManagerList = false
    14.       this.newManagerList = [item]; 
    15.       this[this.fromItem].splice(this.managerOldIndex, 1); 
    16.       this.initStatus[this.fromItem] = false
    17.  
    18.       if (this.managerData[0]) { 
    19.         const obj = deepClone(this.managerData[0]); 
    20.         this.newGuestList.push(obj); 
    21.         this.guestData.push(obj); 
    22.       } 
    23.       this.managerData = [item]; 
    24.       switch (this.fromItem) { 
    25.         case "newGuestList"
    26.           this.guestData = deepClone(this.newGuestList); 
    27.           break; 
    28.         case "newOperatorList"
    29.           this.operatorData = deepClone(this.newOperatorList); 
    30.           break; 
    31.         case "newElectricianList"
    32.           this.electricianData = deepClone(this.newElectricianList); 
    33.           break; 
    34.         default
    35.           break; 
    36.       } 
    37.       this.$message({ 
    38.         message: "拖拽成功!"
    39.         type: "success"
    40.       }); 
    41.       this.password = ""
    42.       this.passwordView = false
    43.     } else { 
    44.       this.$message({ 
    45.         message: "拖拽失败"
    46.         type: "warning"
    47.       }); 
    48.       this.password = ""
    49.       this.passwordView = false
    50.     } 
    51.   } else { 
    52.     this.$message({ 
    53.       message: "请输入密码"
    54.       type: "warning"
    55.     }); 
    56.   } 
    57. }, 

    3. 样式代码

    1.  
    2. .top-name { 
    3.   padding: 10px; 
    4.   background: #333; 
    5.   font-size: 14px; 
    6.   position: relative
    7. .top-name > p { 
    8.   color: #00a7ff; 
    9.   text-align: center; 
    10.   font-size: 16px; 
    11. .main-box { 
    12.   display: flex; 
    13.   justify-content: space-between
    14. .main-l,.main-r { 
    15.   width: 48%; 
    16.   position: relative
    17. .table-b { 
    18.   position: relative
    19. .isdel { 
    20.   text-align: center; 
    21.   font-size: 18px; 
    22.   color: #fff; 
    23. .top-box { 
    24.   display: flex; 
    25.   height: 30px; 
    26.   justify-content: space-between
    27.   align-items: center; 
    28. .top-count { 
    29.   color: #fff; 
    30.   font-size: 14px; 
    31.   margin-left:10px ; 
    32. .utable-box { 
    33.   overflow: auto; 
    34.   height: 700px; 
    35. .table-box { 
    36.   overflow: auto; 
    37.   height: 230px; 
    38.   margin-bottom: 10px; 
    39.   border: 1px solid #333; 
    40.  

    样式在这里就不过多的分析了。

    结语

    如果想看下完整代码,看下真实操作效果,可以访问下方的源码地址:

    https://github.com/maomincoding/drag-tables

     

    来源:前端历劫之路内容投诉

    免责声明:

    ① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

    ② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

    软考中级精品资料免费领

    • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

      难度     813人已做
      查看
    • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

      难度     354人已做
      查看
    • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

      难度     318人已做
      查看
    • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

      难度     435人已做
      查看
    • 2024年上半年系统架构设计师考试综合知识真题

      难度     224人已做
      查看

    相关文章

    发现更多好内容

    猜你喜欢

    AI推送时光机
    位置:首页-资讯-后端开发
    咦!没有更多了?去看看其它编程学习网 内容吧
    首页课程
    资料下载
    问答资讯