Element-ui 之 repeat-click 长按功能指令源码分析

此篇文章分析一下 element-ui 组件库中,repeat-click 指令的作用和源代码。

一. repeat-click 指令的应用

repeat-click 指令用于在用户在长按鼠标左键时,持续的执行其绑定的方法,直到用户抬起鼠标左键。

element-ui 组件库中,有两处应用到了:

  1. InputNumber 组件,在长按控制按钮(加号、减号)时,执行连续增加或减少。

在这里插入图片描述

  1. TimePicker 时间选择器组件,在长按上下箭头时,执行时间的切换。
    在这里插入图片描述

二. repeat-click 指令源码分析

2.1 repeat-click 源码实现思路

实现思路:

设定一个目标时间,用鼠标左键按下和抬起的持续时间与这个目标时间做对比:

  • 第一种情况是小于目标时间,那么就执行一次绑定的方法。
  • 第二种情况是大于目标时间,那么就以目标时间为间隔,持续的执行绑定的方法。

具体实现步骤:

  1. 在 vue 自定义指令的 bind 钩子中做处理,先设置间隔的时间,mac 为 100 毫秒,其余为 200 毫秒,然后将绑定的方法取出。
  2. 增加 mousedown 事件的监听,先去判断点击的是否为鼠标左键,如果不是,直接 return;如果是鼠标左键,则记录按下鼠标左键的时间,并且设置计时器,以目标时间为间隔持续的执行绑定的方法。
  3. 绑定鼠标的 mouseup 事件,判断如果鼠标抬起时间减去按下时间小于间隔时间,则执行一次绑定的方法。并且在 mouseup 时,还需要清除计时器,停止执行绑定的方法。

2.2 repeat-click 源码分析

export default {
  bind(el, binding, vnode) {
    // 设置计时器
    let interval = null;
    let startTime;
    // 每隔多长时间执行一次方法
    const maxIntervals = isMac() ? 100 : 200;
    // 绑定的方法
    const handler = () => vnode.context[binding.expression].apply();
    // 清除方法
    const clear = () => {
      // 小于间隔时间,则执行方法
      if (Date.now() - startTime < maxIntervals) {
        handler();
      }
      // 并且在鼠标抬起时清除计时器
      clearInterval(interval);
      interval = null;
    }
    on(el, 'mousedown', (e) => {
      // 如果点击的不是鼠标左键,则直接 return 
      if (e.button !== 0) return;
      // 变量 startTime 记录当前鼠标 mousedown 的时间
      startTime = Date.now();
      // 绑定鼠标 mouseup 事件,在 mouseup 事件时执行清除方法
      once(document, 'mouseup', clear);
      clearInterval(interval);
      // 每隔 maxIntervals 时间执行一次方法
      interval = setInterval(handler, maxIntervals);
    })
  }
}

涉及到的封装监听事件、以及移除监听事件的相关方法:

(1)on 方法:用于绑定监听事件,兼容 IE 浏览器

export const on = (function() {
  if (!isServer && document.addEventListener) {
    // 判断 document.addEventListener 是否存在,
    return function(element, event, handler) {
      // 如果元素、事件、回调方法都存在则绑定监听事件
      if (element && event && handler) {
        element.addEventListener(event, handler, false);
      }
    };
  } else {
    // 不存在,使用 attachEvent 兼容IE浏览器
    return function(element, event, handler) {
      if (element && event && handler) {
        element.attachEvent('on' + event, handler);
      }
    };
  }
})();

(2)off 方法:用于取消事件监听,兼容 IE 浏览器

export const off = (function() {
  if (!isServer && document.removeEventListener) {
    // 判断 document.removeEventListener 是否存在
    return function(element, event, handler) {
      // 如果元素、事件存在,则取消监听的绑定事件
      if (element && event) {
        element.removeEventListener(event, handler, false);
      }
    };
  } else {
    // 不存在,使用 detachEvent 兼容IE浏览器
    return function(element, event, handler) {
      if (element && event) {
        element.detachEvent('on' + event, handler);
      }
    };
  }
})();

(3)once 方法:用于监听绑定事件后,回调函数只触发一次

export const once = function(el, event, fn) {
  var listener = function() {
   // 如果传入了回调函数,则执行该函数
   if (fn) {
     fn.apply(this, arguments);
   }
   // 取消事件监听
   off(el, event, listener);
  };
  // 绑定事件监听
  on(el, event, listener);
};

三. InputNumber 组件使用该指令的具体情况

<template>
  <!-- 使用自定义指令 -->
  <span
    v-repeat-click="decrease"
  >
  </span>
</template>
<script>
  // 引入自定义指令
  import RepeatClick from '../../utils/directives/repeat-click';
  // 注册自定义指令
  export default {
    directives: {
      repeatClick: RepeatClick
    },
  }
</script>
<think>我们正在讨论在Vue项目中使用Element-UI的轮播图组件(el-carousel)并实现点击切换图片的功能。根据Element-UI官方文档,el-carousel组件本身支持切换功能,包括自动切换和手动切换(通过左右箭头)。但是,用户可能想要通过自定义的点击事件(比如点击缩略图)来切换轮播图。我们可以这样实现:1.使用el-carousel组件,并给其设置一个ref属性,以便在Vue实例中访问该组件。2.在data中定义当前轮播图的索引(例如activeIndex)。3.创建自定义的缩略图列表,并为每个缩略图绑定点击事件,点击时调用切换轮播图的方法。4.在切换方法中,通过ref获取轮播图组件实例,然后调用其setActiveItem方法切换到指定索引的幻灯片。注意:我们还需要监听轮播图的change事件,以便在轮播图切换时更新activeIndex,保持缩略图与当前幻灯片同步。参考引用[2]中提到了轮播图的基本使用,包括获取数据和显示轮播图。在此基础上,我们添加点击切换功能。示例代码如下:模板部分:```html<template><div><!--轮播图--><el-carouselref="carousel":interval="5000"arrow="always"@change="handleChange"><el-carousel-itemv-for="(item,index)inbanners":key="index"><divclass="banner-image":style="`background:url(${$axios.defaults.baseURL}${item.url})centercenterno-repeat;background-size:contain;`"></div></el-carousel-item></el-carousel><!--缩略图列表--><divclass="thumbnail-list"><divv-for="(item,index)inbanners":key="index"class="thumbnail-item":class="{active:activeIndex===index}"@click="switchTo(index)"><img:src="$axios.defaults.baseURL+item.url"alt="thumbnail"></div></div></div></template>```脚本部分:```javascript<script>exportdefault{data(){return{banners:[],//轮播图数据activeIndex:0//当前激活的轮播图索引};},mounted(){//获取轮播图数据this.$axios.get(&#39;/banner/list&#39;).then(res=>{this.banners=res.data.data;});},methods:{//轮播图切换时触发handleChange(index){this.activeIndex=index;},//切换轮播图switchTo(index){//通过ref获取轮播图组件实例,并调用setActiveItem方法切换this.$refs.carousel.setActiveItem(index);}}};</script>```样式部分(可根据需要调整):```css<stylescoped>.banner-image{height:300px;/*设置轮播图高度*/}.thumbnail-list{display:flex;justify-content:center;margin-top:20px;}.thumbnail-item{width:60px;height:60px;margin:05px;cursor:pointer;border:2pxsolidtransparent;}.thumbnail-item.active{border-color:#409EFF;}.thumbnail-itemimg{width:100%;height:100%;object-fit:cover;}</style>```说明:-我们给el-carousel添加了一个ref="carousel",这样可以通过this.$refs.carousel访问到轮播图组件实例。-轮播图组件的change事件会在切换时触发,我们将当前激活的索引赋值给activeIndex。-缩略图列表使用v-for循环生成,并绑定点击事件switchTo,传入索引。-switchTo方法中,通过this.$refs.carousel.setActiveItem(index)来切换轮播图。这样,点击缩略图时,轮播图就会切换到对应的图片,并且当前激活的缩略图会有边框高亮。注意:如果轮播图数据是通过异步请求获取的,确保在数据加载完成后再进行操作。相关问题:1.Element-UI的轮播图组件还有哪些常用的属性和事件?2.如何实现轮播图的自动播放和暂停?3.Vue中如何优雅地处理图片加载失败的情况?</think>在 Vue使用 Element-UI 实现点击切换轮播图图片的功能,可以通过以下方法实现: ### 解决方案 1. **使用 `ref` 获取轮播图实例** 通过给 `<el-carousel>` 添加 `ref` 属性,在 Vue 实例中访问轮播图组件的方法 2. **调用 `setActiveItem` 方法切换** Element-UI 的轮播图组件提供了 `setActiveItem(index)` 方法,通过索引直接切换指定图片 3. **绑定点击事件** 在自定义控件(如缩略图)上绑定 `@click` 事件触发切换 --- ### 代码示例 ```html <template> <div> <!-- 轮播图主体 --> <el-carousel ref="myCarousel" :interval="5000" indicator-position="outside" > <el-carousel-item v-for="(item, index) in banners" :key="index"> <div class="banner-image" :style="`background:url(${$axios.defaults.baseURL}${item.url}) center/contain no-repeat`" ></div> </el-carousel-item> </el-carousel> <!-- 自定义缩略图控制 --> <div class="thumbnail-container"> <div v-for="(item, index) in banners" :key="&#39;thumb-&#39;+index" class="thumbnail-item" :class="{ active: currentIndex === index }" @click="switchTo(index)" > <img :src="$axios.defaults.baseURL + item.url" alt="缩略图" > </div> </div> </div> </template> <script> export default { data() { return { banners: [], // 轮播图数据 currentIndex: 0 // 当前激活索引 }; }, mounted() { // 获取轮播图数据 this.$axios.get(&#39;/banner/list&#39;).then(res => { this.banners = res.data.data; }); // 监听轮播图切换事件 this.$refs.myCarousel.$on(&#39;change&#39;, (index) => { this.currentIndex = index; }); }, methods: { // 切换轮播图 switchTo(index) { this.$refs.myCarousel.setActiveItem(index); } } }; </script> <style scoped> /* 轮播图样式 */ .banner-image { height: 400px; } /* 缩略图容器 */ .thumbnail-container { display: flex; justify-content: center; margin-top: 20px; } /* 单个缩略图 */ .thumbnail-item { width: 80px; height: 60px; margin: 0 5px; cursor: pointer; border: 2px solid transparent; opacity: 0.7; transition: all 0.3s; } .thumbnail-item:hover, .thumbnail-item.active { opacity: 1; border-color: #409EFF; } .thumbnail-item img { width: 100%; height: 100%; object-fit: cover; } </style> ``` ### 关键点说明 1. **`ref` 获取组件实例** `ref="myCarousel"` 允许通过 `this.$refs.myCarousel` 访问轮播图组件 2. **切换方法 `setActiveItem`** 直接调用组件方法跳转到指定索引:`this.$refs.myCarousel.setActiveItem(index)` 3. **同步当前索引** 通过监听轮播图的 `change` 事件更新 `currentIndex`,实现缩略图高亮同步 4. **图片路径处理** 使用 `$axios.defaults.baseURL + item.url` 确保图片路径完整[^2] --- ### 相关问题 1. 如何在 Element-UI 轮播图中实现自定义指示器样式? 2. 轮播图自动播放和手动控制如何动态切换? 3. 如何优化轮播图在大数据量下的性能? [^1]: 快速上手 VueElement-UI 组件库 [^2]: 闲云旅游项目开发-使用Element-ui实现主页轮播图
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值