拖拽选择区域组件

时间:2024-01-23 08:31:34
  项目需求:选择广告的投放时段
  最终实现效果:
  
 主要总结实现点击拖拽选择区域的效果(封装成一个vue组件),具体数据请求与渲染依具体情况而定。

 主要思路:要实现鼠标拖拽选择区域的效果,主要是表格中td元素的mousedown,mouseover,mouseup事件的处理。

  1.  在mousedown事件中记录起始点,高亮当前选中元素
  2.  在mouseover事件中渲染选中区域
  3.  mouseup事件,数据的重置处理。 

需要注意的点:

  1.  在vue中,当给元素绑定三个事件后,mouseove事件会在鼠标经过元素时立即触发,所以需要设置一个标志位,在mousedown事件触发后,mouseover事件才会被触发。
  2.  拖拽过程中存在反复拖拽的问题,应该以最后一次的位置为准,之前即时渲染的区域应该及时清除,所以应该记录下拖拽的最大值,在渲染区域之前,清除无用区域。
  3.  拖拽到表格区域外的处理,如果拖拽带表格区域外,标志位不能及时重置,元素的mouseover事件会一直被触发,所以监听整个dom元素的mouseleave事件,及时重置标志位。
 
功能相关代码:
 
 1 Vue.component("drag-component",{
 2   props:['data'],
 3   template: '<table class="time_table table" v-on:mouseleave="mouseleave">'+
 4   '<thead><tr><th rowspan="2">日期/时间</th></tr><tr><th  class="unselectable" v-for="num in numData">{{num}}</th>'+
 5   '</tr></thead><tbody> <tr v-for="(options,index) in timeData" >'+
 6   '<th scope="row">{{options.date}}</th>'+
 7   '<td v-for="(timeItem,key) in options.time":class="[{ \'active_select\': timeItem.isSelected}]" v-on:mousedown="mousedown(index,key)"  v-on:mouseover="mouseover(index,key)" v-on:mouseup="mouseup"></td></tr></tbody></table>',
 8   data: function(){
 9       return {
10           numData:[0,1,2,3,4,5,6,7,8,9,10],
11         timeData:this.data,
12         selectFlag:false, //当参数为true时,mouseover事件生效
13         max:{
14               x:0,
15             y:0
16           }
17       }
18   },
19   methods:{
20       mousedown:function(index,key){
21               this.selectStart=[];
22               this.selectFlag=true;
23               if(this.timeData[index].time[key].value==false){
24                   if(this.timeData[index].time[key].isSelected){
25                       this.timeData[index].time[key].isSelected=false;
26                   }else {
27                       this.$set(this.timeData[index].time[key],"isSelected",true);
28                   }
29               }
30               this.selectStart.push({
31                   index:index,
32                   key:key
33               });
34       },
35       mouseover:function(index,key){
36           // x 垂直方向  y 水平方向
37           if(this.selectFlag){
38               if(index>=this.max.x){
39                       this.max.x=index;
40                   }
41                   if(key>=this.max.y){
42                       this.max.y=key;
43                   }
44                   var start={
45                       x:this.selectStart[0].index,
46                       y:this.selectStart[0].key
47                   };
48                   var end={
49                       x:index,
50                       y:key
51                   };
52                   for(var i=end.x;i<=this.max.x;i++){
53                       for(var j=end.y;j<=this.max.y;j++){
54                           this.$set(this.timeData[i].time[j], "isSelected", false);
55                       }
56                   }
57                   /* 渲染选中的区域 */
58                   for(var i=start.x;i<=end.x;i++){
59                       for(var j=start.y;j<=end.y;j++){
60                             this.$set(this.timeData[i].time[j], "isSelected", true);
61                       }
62                   }
63 
64               }
65       },
66       mouseup:function () {
67           this.selectFlag=false;
68           this.max={
69               x:0,
70               y:0
71           }
72       },
73       mouseleave:function () {
74           this.selectFlag=false;
75       }
76   }
77 });

调用部分:

css部分(以需求为准,简单写了下样式):
    .time_table {
            border:1px solid #ccc;
            border-collapse:collapse;
        }
        .time_table th,.time_table td {
            border: 1px solid #ccc;
            width: 30px;
            height: 40px;
        }
        .active_select {
            background: cornflowerblue;
        }