当前位置:   article > 正文

大屏可视化项目之vue3-seamless-scroll无缝滚动组件(二)——vue-seamless-scroll中click点击事件无效的处理方法 & 事件委托之事件捕获的具体应用

vue3-seamless-scroll

大屏可视化项目之vue3-seamless-scroll无缝滚动组件(二)——vue-seamless-scroll中click点击事件无效的处理方法 & 事件委托之事件捕获的具体应用

使用vue-seamless-scroll实现数据无缝连续滚动

1、原理

无限滚动原理:无限滚动的原理就是把之前的遍历的内容复制一份,滚动这两部分内容,达到无缝滚动效果。

基本原理是把要滚动的部分复制一份,滚动这两部分相同的内容,进而实现无缝连续滚动

在这里插入图片描述

2、遇到的问题

当ul1中的数据未滚动完时,ul2 部分的click事件不起作用,无法实现点击这行功能

(此时可见区域内一部分数据为ul1,一部分数据为ul2)

直接现象

在使用vue-seamless-scroll 自动滚屏绑定事件时,个别点击事件无效

原因

该插件为了实现无缝衔接而复制了dom渲染,不会带上事件。

解决办法

利用js事件委托机制。

1.1、结构

在这里插入图片描述

原来是在li里面绑定事件出现上述问题,现在给最外层的父级div加委托事件,让父级事件执行。

在这里插入图片描述

通过 e.target.dataset.code 获取所需值

备注:

vue中自定义属性格式为 data-xxx

获取为:e.target.dataset.xxx

id 和 name 一般为部分标签自带属性,前面不需要加data

3、解决思路

事件委托依靠的就是事件冒泡和事件捕获的机制

事件冒泡会从当前触发的事件目标一级一级往上传递,依次触发,直到document为止。

事件捕获会从document开始触发,一级一级往下传递,依次触发,直到真正事件目标为止。

所谓的事件委托就是通过监听一个父元素,来给不同的子元素绑定事件,减少监听次数,从而提升速度。

1、事件委托

2、JavaScript 运行机制详解:再谈Event Loop

4、解决问题
4.1、示例一

在项目中碰到一个走马灯需求,选择使用vue-seamless-scroll插件进行解决

<template>
  <section class="footer-info">
    <vueSeamless :data="infoList" :class-option="options">
      <p v-for="info in infoList" :key="info.id">
        <!-- handleDetailClick 点击事件绑在目标元素上  -->
        <span @click="handleDetailClick(info.id)">{{info.detail}}</span>
      </p>
    </vueSeamless>
  </section>
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

现象:实际页面渲染后会出现点击某些span没有执行事件的情况。

原因:是因为vue-seamless-scroll是用重复渲染一遍内部元素来实现滚动的,而JS的onclick只检测页面渲染时的DOM元素。

思路:在section上绑定事件handleSectionClick,捕获点击的DOM节点,若为span则执行事件。事件中需求的数据可以直接用data绑在相应的span上。

<template>
	<!-- 1.0、handleSectionClick 点击事件绑在目标元素的父元素上  -->
	<!-- @click.stop 阻止事件冒泡;也可直接写@click   -->
  <section class="footer-info" @click.stop="handleSectionClick($event)">
    <vueSeamless :data="infoList" :class-option="options">
      <p v-for="info in infoList" :key="info.id">
        <span :data-id="info.id">{{info.detail}}</span>  //将index绑定在span的数据中
      </p>
    </vueSeamless>
  </section>
</template>

<script>
export default {
  methods:{
    handleSectionClick(e){
      let target = e.target;
      if(target.tagName == "SPAN") {
          // 2.0、根据事件捕获  捕获目标元素节点,执行点击事件
        this.handleDetailClick(target.dataset.id);
      }
    },
      //3.0、执行点击事件
    handleDetailClick(e){ 
        console.log(e)
    },    
  }
}
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

保存运行,正常处理了所有span的点击事件

备注

@click.stop与@click.prevent

@click.stop 阻止事件冒泡

@click.prevent 阻止事件的默认行为,

<a href="http://www.baidu.com" @click.prevent="test4">百度一下</a>   //阻止a标签跳转,仅执行函数test4
  • 1
4.2、示例二

1.给外层div加点击事件,通过event.target获取到点击的dom元素

在这里插入图片描述

获取到eventevent.target,如下

在这里插入图片描述

获取到了button之后,因为接下来的操作还需要用到ID和name,所以要给button绑定属性

id和name是button自带的属性,vue中自定义属性时还需要添加前缀 data-,获取时要加 dataset

1、定义属性——:data-dept:data-id

在这里插入图片描述

2、获取属性——event.target.dataset.depte.target.dataset.id

在这里插入图片描述

可控制台打印数据,进行验证

现在获取到了所有想要的数据 和 要响应的事件,接下来执行事件即可。

代码如下:

 <div class="m_tableContent m_gasMonitoring" @click="handleClick($event)">
    <div class="m_tableTitle">
      <ul>
        <li>编号</li>
        <li>员工姓名</li>
        <li>一氧化碳(ppm)</li>
        <li>甲烷(%)</li>
        <li>氧气(%)</li>
        <li>温度(℃)</li>
        <li>湿度(%)</li>
        <li style="width: 30%">地点</li>
        <li>操作</li>
      </ul>
    </div>
    <vue-seamless-scroll :data="listData" :class-option="classOption" class="seamless-warp">
      <ul v-loading="loading" class="item seamless-table">
        <li v-for="(item,index) in listData" :key="index" class="seamless-row">
          <p class="m_rowItem ">{{ item.sequenceId }}</p>
          <p class="m_rowItem">{{ item.staffName }}</p>
          // 部分省略
           <p class="m_rowItem">
            <button :id="item.staffId" :name="item.staffName" :data-dept="item.deptName" type="danger" class="el-button el-button--danger el-button--mini is-plain" plain size="mini">呼叫</button>
          </p>
        </li>
      </ul>
    </vue-seamless-scroll>
      </div>
</template>
<script>
export default {
name: 'GasMonitorTable',
  methods: {
    handleClick(event) {
      console.log(event)
      console.log(event.target)
      this.staffInfo.staffId = event.target.id
      this.staffInfo.staffName = event.target.name
      this.staffInfo.deptName = event.target.dataset.dept
      this.handlePhoneStaff()
    }
}
}
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
4.3、实例

界面
在这里插入图片描述
弹框

在这里插入图片描述

index.vue

<script lang="ts" setup>
import titleHeader from '../header/titleHeader.vue'
import img from '@/assets/yfdd-bs/main/left/dqyj.png'

import { ref } from 'vue'
const dialogVisible = ref(false)
const isDialog = (e:any) => {
  console.log(e)
  dialogVisible.value = true
}
const handleSectionClick = (e:any) => {
  if (e.target.tagName === 'SPAN') {
    isDialog(e.target.dataset.id)
  }
}
const bgImg = ref('bg-dqyj-dialog')
const list = ref([
  {
    id: 1,
    txt: '001中国气象台11月8日10时继续发布橙色预警:请广大一线工作者,注意防风保暖,提前采取防护措施'
  },
  {
    id: 2,
    txt: '002中国气象台11月8日10时继续发布橙色预警:请广大一线工作者,注意防风保暖,提前采取防护措施中国气象台11月8日10时继续发布橙色预警:请广大一线工作者,注意防风保暖,提前采取防护措施'
  }

])

</script>

<template>
  <div
    class="container"
    @click="handleSectionClick($event)"
  >
    <titleHeader
      :src="img"
      :need-line="true"
      :line-width="[270, 24]"
    />
    <vue3-seamless-scroll
      :list="list"
      class="scroll"
      :limit-scroll-num="1"
      hover
    >
      <div
        class="item"
        v-for="(item) in list"
        :key="item.id"
      >
        <!-- <span>{{ item.txt }}</span> -->
        <div style="width: 100%; height: 200px;overflow:hidden">
          <div
            class="yj-count"
          >
            <img
              style="display:inline-block;margin-left: 40px;margin-bottom:10px"
              src="@/assets/yfdd-bs/main/left/baoxue.png"
              alt=""
            >
            <div class="yj-fgx" />
            <div
              style="display:inline-block;width: 300px;padding-left:30px;height: 90px;"
            >
              <span
                class="yi-text"
                :data-id="item.id"
              >
                {{ item.txt }}
              </span>
            </div>
          </div>
        </div>
      </div>
    </vue3-seamless-scroll>
    <el-dialog
      v-model="dialogVisible"
      width="1200px"
      top="120px"
      :modal="false"
      :close-on-click-modal="false"
      :custom-class="bgImg"
      :lock-scroll="false"
    >
      <template #title>
        <div class="title">
          气象预警
        </div>
      </template>
      <div class="dialogContent">
        <el-row>
          <el-col
            :span="12"
            class="yj-txt"
          >
            <span>预警级别:</span>
            <span style="color: #F0FFF0;font-size: 30px;">三级</span>
          </el-col>
          <el-col
            :span="12"
            class="yj-txt"
          >
            <span>预警类型:</span>
            <span style="color: #F0FFF0;font-size: 30px;">暴雪天气</span>
          </el-col>
          <el-col
            :span="12"
            class="yj-txt"
          >
            <span>预警来源:</span>
          </el-col>
          <el-col
            :span="24"
            class="yj-txt"
          >
            <span style="color: #F0FFF0; display: inline-block;font-size: 30px;padding-right: 40px;">中央气象台中央气象台中央气象台中央气象台中央气象台中央气象台中央气象台中央气象台中央气象台</span>
          </el-col>
        </el-row>
      </div>
    </el-dialog>
  </div>
</template>

<style lang="scss" scoped>
  .container{
      background-image: url(@/assets/yfdd-bs/main/left/back1.png);
      background-repeat: no-repeat;
      background-size: 100% 100%;
      .scroll {
        height: 120px;
        width: 100%;
        margin: 10px auto;
        overflow: hidden;
      }

      .scroll .item {
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 3px 0;
      }
      .yj-count{
        border-bottom: 1px solid #14b6f7;
        margin: 0px 30px 30px 30px;
        padding-bottom: 20px;
        .yj-fgx{
            height: 70px;
            display:inline-block;
            border-right:1px #14b6f7 solid;
            margin-left:30px;
            margin-top:10px;
            margin-bottom:30px;
        }
        .yi-text{
            display: -webkit-box;
            -webkit-line-clamp: 4;
            -webkit-box-orient: vertical;
            overflow: hidden;
            text-overflow: ellipsis;
            height: 124px;
            font-size:24px
        }
      }
    .dialogContent{
      font-size: 20px;
    }
    .title{
      height: 90px;
      text-align: center;
      line-height: 90px;
      font-weight: 600;
      color: white;
      font-size: 26px;
    }
    .yj-txt{
      color: #fff;
      font-size: 36px;
      display: inline-block;
      padding-left: 40px;
      margin-top: 30px;

    }
      .dialogContent{
      font-size: 20px;
    }
    .title{
        height: 90px;
        text-align: center;
        line-height: 90px;
        font-weight: 600;
        color: white;
        font-size: 26px;
    }
    .yj-txt{
      color: #fff;
      font-size: 36px;
      display: inline-block;
      padding-left: 40px;
      margin-top: 30px;
    }
    :deep(.el-dialog__header){
      padding: 0;
    }
  :deep(.el-dialog__body) {
      padding: 0px !important;
    }
}
</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/空白诗007/article/detail/903971
推荐阅读
相关标签
  

闽ICP备14008679号