keen-slider | 如何实现一个H5滑动卡片?

2,252 阅读10分钟

背景

在日常的工作中,有很多卡片滑动的需求。如:弹窗广告位分享弹窗、卡片动画等。

之前尝试过Swiper,但是感觉这个库有点大...

选择keen-slider的原因

1. 体积小

  • keen-slider打包压缩后的大小为28kb。
  • 而swiper打包压缩后的体积有364kb。

2. 文档易于阅读

keen-slider.io/examples

swiperjs.com/react#usage…

3. 依赖的第三方库

  • keen-slider 只依赖React,升级,兼容性会比较好

keen-slider的使用

keen-slider中提供了一个hook供react使用。像所有react hook一样,useKeenSlider 只能在组件的顶层被调用(不能写在if else中)。接收两个参数,Options(第一个参数)、Plugins(第二个参数)。调用 useKeenSlider 返回一个数组。数组的第一个元素是绑定在 slider 容器上的回调函数,第二个元素是幻灯片的实例,或者说是包含了幻灯片的具体属性的变量。

import React from 'react'
import 'keen-slider/keen-slider.min.css'
import { useKeenSlider } from 'keen-slider/react' // import from 'keen-slider/react.es' for to get an ES module

export default () => {
  // 1. 第一个参数最终绑定在了 keen-slider 的最外层
  // 2. 通过第二个参数可以 slider 可以访问 slider 实例
  const [refCallback, slider] = useKeenSlider(
	// Options
    {
      rtl: true,
      slideChanged() {
        console.log('slide changed')
      },
    },
	// Plugins
    [
      // add plugins here
    ]
  )

  return (
    <div ref={refCallback} className="keen-slider">
      <div class="keen-slider__slide">1</div>
      <div class="keen-slider__slide">2</div>
      <div class="keen-slider__slide">3</div>
    </div>
  )
}

keen-slider的Options属性

你可以通过传递Options(其中包括了一些事件钩子),来定制不同效果的幻灯片。如果你想在初始化之后改变配置,你可以调用 update 方法来实现。

1. breakpoints:object

在某个特定的条件下,覆盖options和Event hooks的属性值。每个特定条件必须是媒体查询的字符串。比如 (orientation: portrait) and (min-width: 500px) 。注意:如果多个媒体查询同时生效,那么已最后一次的为准。

new KeenSlider('#my-slider', {
  loop: true,
  breakpoints: {
    // 当宽度小于500px的时候,loop属性变为 false。
    '(min-width: 500px)': {
      loop: false,
    },
  },
})

官方breakpoint例子

2. defaultAnimation:object

nextprevmoveToIdx操作设置动画函数。

  • duration: number - 动画的持续时间(毫秒)
  • easing: function - 变化函数 (time: number) => number

3. disabled: boolean

如果这个属性为true,滑块就被禁用了。任何事件和样式都不会失效。默认值为false

4. drag: boolean

开启或关闭mouse和touch事件的响应。默认为true

5. dragSpeed: number | function

设置被拖拽时候的移动速度。可以是一个特定的数字,也可以是一个函数。负值会反转滑动方向。默认值为1

6. initial: number

设置幻灯片的初始索引。默认值为1(下标从1开始)。

7.loop: boolean | object

启用/禁用幻灯片的循环模式。当然,你也可以传递minmax指定循环的次数。

8. mode: 'snap' | 'free' | 'free-snap'

设置拖拽结束后的动画模式。默认为snap

9. range: object

无论视口中包括了几个滑块, 你都可以指定可访问的滑块。

  • min: number: 设置最小可访问的下标
  • max:number:设置最大可访问的下标
  • align:boolean: 将最大位置对齐到最后一个 slider 的末尾

10. renderMode: 'precision' | 'preformance' | 'custom'

如果你的 slider 带有一些复杂的标记和CSS,那么浏览器的呈现性能可能会变慢。为了解决这个问题,您可以将此选项设置为performance。如果你想创建自己的渲染器,你可以将这个选项设置为custom。默认设置是precision

11. rtl: boolean

改变滑块的展示位置。将从左到右改成从右到左。默认值为false

12. rubberband: boolean

启用或禁用滑块拖动行为和拖动后的动画。默认是true

13. selector: string | HTMLElement[] | NodeList | function | null

指定如何接收来自DOM的滑块 。可以是 css 选择器、HTMLElements的集合、获取containers的函数、null。如果你不希望滑块定位或缩放幻灯片,可以将该属性设置为null。

14. slides: object | number | function | null

指定幻灯片的配置。每次更新、调整大小或更改配置时,幻灯片配置都会更新。因此,再次调用所有函数。默认为null

  • number - 将幻灯片的数量设置为指定的数量。

  • object - 该对象用于指定幻灯片配置。

    • origin: 'auto' | 'center' | 'number' - 设置滑块的原点。

      auto: 调整所有幻灯片的原点,使第一张幻灯片向左对齐,最后一张幻灯片向右对齐。

      center:将所有幻灯片居中。

      number: 相对于视口???

    • number: number | function | null - 如果值为数字或null,则与幻灯片类似。也可以是一个返回数字或null的函数。默认为空。

    • perView: number | function | 'auto' - 确定幻灯片应与视口/容器相关的大小。如果设置为自动,则基于相应的HTML元素的大小确定幻灯片尺寸。因此,选择器选项不得为空。也可以是一个函数,返回数字或'auto'。默认为1。

    • spacing: number | function -以像素定义幻灯片之间的间距。可以是一个返回数字的函数。默认值为0

  • function - 使用返回幻灯片配置数组的函数指定幻灯片配置。幻灯片配置具有以下可选属性。

    • origin: number - 确定幻灯片的原点在视口中的位置。默认值为 0
    • size: number - 确定幻灯片相对于视口的相对大小。 默认值为1
    • spacing: number - 确定与一个滑块的距离。默认为0.

函数的第一个参数是容器的大小,第二个参数是HTML元素数组的幻灯片。

  • null - 滑块的样式将由`selector属性确定。

15. vertical: boolean

将滑块的方向从水平更改为垂直。默认值为false

事件函数(Event Hooks)

事件钩子是滑块在其生命周期中调用的函数。函数获取Properties作为唯一的参数。事件钩子是Option参数(useKeenSlider的第一个参数)的一部分。以下是触发的事件函数。

1. animationStarted

动画开始时调用的声明周期函数。动画发生在拖动结束后或当调用moveToIdx() 或者 animator.start()时触发。

2. animationStop

动画停止时调用。

3. animationEnded

动画结束时调用。

4. created

滑块被创建时调用。

5. destroyed

滑块被销毁时调用

6. detailsChanged

当 details 属性变化时触发。每次移动滑块,或者幻灯片的配置有变动,初始化或改变大小后都会触发。

7. dragged

滑块被拖动的时候调用。

8. dragStarted

滑块开始拖动时调用。

9. dragChecked

拖动的方向是check过的,并且是有效的。

10. dragEnded

滑块开始拖动结束时调用。

11. optionsChanged

幻灯片的配置发生了变化,例如由于更新、调整大小(当幻灯片的数量发生变化时)或breakpoints的变化。

12. slideChanged

当前的滑块或大多数的滑块都发生了变化时候触发。

13. updated

由于尺寸变化或其他变化导致 update 函数被触发的时候会调用。

方法 && 属性

无论滑块是通过react hook还是普通的javascript创建的,它都会返回一个实例或一个属性对象来进行进一步的操作。下面描述了这些属性。

Animator:object

animator 是负责轨迹的运动动画的模块。它具有以下属性:

  • active: boolean - 指示动画是否处于运行状态。

  • start: function - 开始一个新的动画。需要一个关键帧数组。关键帧按顺序处理。

    slider.animator.start([keyframe1, keyframe2])
    

    一个keyframe包含以下属性:

    • distance: number - 动画中的移动距离。
    • duration: number - 动画的持续时间(毫秒)。
    • earlyExit: number - 可选地设置一个更早的关键帧终止。
    • easing: function - 动画函数 (time: number) => number。
  • stop: function - 停止当前活动的动画(如果有的话)。

  • targetIdx: number | null - 在动画结束时处于active状态的索引。

container: HTMLElement

HTML元素,幻灯片的容器。

destroy: function

销毁函数,当被调用时销毁滑动块,所有事件和应用样式将被移除。

on: function

slider.on(eventName, callback, remove)

调用时注册一个事件钩子。

  • eventName: string - 指定事件名称。
  • callback: function - 当这个事件被触发了,该函数会被执行。
  • remove: boolean - 是否应该设置或删除函数。默认是false

emit: function

slider.emit(eventName)

调用时发出事件。需要一个eventName: string作为参数。

moveToIdx: function

slider.moveToIdx(index, absolute, animation)

调用时用动画更改 active 的幻灯片。

  • index: number - 指定 active 的滑块下标
  • absolute: boolean - 定义索引是否为绝对值。默认是 false
  • animation: object - 修改默认动画。对象可以具有以下属性
    • duration: number - 设置动画持续时间为毫秒。默认是500。
    • easing: function - 设置缓和函数。默认是 t => 1 +——t * t * t * t。

next: function

调用时将当前 active 的幻灯片更改为前一个(如果存在的话)。

prev: function

调用时将当前 active 的幻灯片更改为后一个(如果存在的话)。

size: number

视口的宽度/高,取决于该幻灯片是横/竖排列的。

slides: HTMLElement[]

幻灯片作为HTML元素的数组。

track: object

  • absToRel: function - 将绝对索引转换为相应的相对索引。

  • add: function - 将传递的值添加到跟踪位置。

  • details: object | null - 当前滑块的位置,长度,尺寸和距离相对于容器/视口大小。如果滑块被禁用或未准备就绪,则设置为null。

    • abs: number - active 滑块的绝对下标。
    • length: number - 当前滑块长度与视口大小的关系???。
    • min: number - 根据range/loop变量计算出的最小位置。
    • max: number - 根据range/loop变量计算出的最大位置。
    • minIdx: number - 根据range/loop变量计算出的最小下标。
    • maxIdx: number - 根据range/loop变量计算出的最大下标。
    • position: number - 根据range/loop变量计算出的的当前位置。
    • progress: number - 滑块与长度的相对位置。
    • rel: number - 当前active滑块的相对索引。
    • slides: array - 作为对象数组的每个滑块的详细信息。每个对象具有以下属性。
      • abs: number - active 滑块的绝对下标。
      • distance: number - 滑块到视口开始的距离。
      • portion: number - 表示视口中可见的幻灯片是多少。
      • size: number - 滑块相对于视口的大小。
    • distToIdx: function - 将传递的距离转换为相应的索引。
    • idxToDist: function - 返回传递的索引的距离。第二个参数是可选的,它是一个布尔值,指定传入的索引是否为绝对值。第三个参数是可选的,用于指定引用位置。
    • init: function - 重新初始化轨道。可以在这里重新设置 active 滑块。
    • to: function - 将传递的值设置为滑块位置。
    • velocity: function - 返回滑块的当前速度。

update: function

slider.update(options, idx)

如果触发调整大小或需要更改配置,可以调用update 函数, 强行更新幻灯片。

  • options: object - 指定滑动块应被重新初始化的新配置。默认值 undefined
  • idx: number - 将当前活动幻灯片设置为给定索引。默认为 undefined

内置的CSS属性

  • data-keen-slider-clickable - 将此属性设置在每个滑块上,可以组织滑块上的触摸/单击事件。
  • data-keen-slider-scrollable - 将此属性设置在每个滑块上,允许滑块在水平/垂直方向上滑动。overflow需要设置成scroll

keen-slider中的插件

为了使自定义滑块函数的集成、结构和版本更容易,你可以创建插件。Keen-Slider本身也部分基于插件。

插件本质上是一个函数,它接收滑块实例作为其唯一参数,并在滑块启动期间初始化。使用 onemit 函数可以在幻灯片的声明周期函数中做一些事情。

扩展拖控件

如果你想扩展滑块的拖动控件,你可以发出自定义事件ksDragStart, ksDragksDragEnd的位置,官方例子

实现一个h5轮播弹窗

1. 引入相关依赖

这里以 React + TS 为例。

import * as React from "react";
import "keen-slider/keen-slider.min.css";
import "./styles.css";
import { useKeenSlider, TrackDetails } from "keen-slider/react";

2. 使用 useKeenSlider 创建实例

const [details, setDetails] = React.useState<TrackDetails | null>(null);

  const [sliderRef] = useKeenSlider<HTMLDivElement>({
    loop: true,
    detailsChanged(s) {
      setDetails(s.track.details);
    },
    initial: 2,
    slides: {
      origin: "center",
      perView: 2,
      spacing: 0
    }
  });

3. 将 sliderRef 挂载特定的 DOM 上

<div
      ref={sliderRef}
      className="keen-slider zoom-out"
      style={{ width: "375px" }}
    >
      {images.map((src, idx) => (
        <div key={idx} className="keen-slider__slide zoom-out__slide">
          <div style={scaleStyle(idx)}>
            <img src={src} />
          </div>
        </div>
      ))}
    </div>

4. 在滑动过程中,控制滑块的大小

写一个 scaleStyle 函数,实时回去滑动过程中的参数。

function scaleStyle(idx: number) {
    if (!details) return {};
    const slide = details.slides[idx];
    const scale_size = 0.7;
    const scale = 1 - (scale_size - scale_size * slide.portion);
    return {
      transform: `scale(${scale})`,
      WebkitTransform: `scale(${scale})`
    };
  }

5. 在线demo地址

在线demo