Swiper.svelte 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. <script>
  2. import { onMount, createEventDispatcher } from 'svelte';
  3. // 事件派发器
  4. // event dispatcher
  5. const dispatch = createEventDispatcher();
  6. // 数据
  7. // data
  8. export let data = [];
  9. // 间隔时间
  10. // interval time
  11. export let interval = 4;
  12. // 过渡时间
  13. // duration time
  14. export let duration = 1000;
  15. // 是否自动播放
  16. // is autoplay
  17. export let autoplay = true;
  18. export let lazyplay = true; //是否懒轮播 is lazyplay
  19. export let initActive = 0; //初始激活索引 init active index
  20. export let indicatePosition = 'inner'; //指示器位置,'inner'/'out'/'none' indicate position
  21. export let indicateAlign = 'center'; //指示器对齐方式,'center'/'right'/'left' indicate align
  22. export let indicateStyle = 'pointLine'; //指示器样式,'point'/'line'/'pointLine'/'longLine' indicate style
  23. export let indicateRadius = true; //指示器是否圆角 indicate radius
  24. export let indicateInjClass = ''; //指示器注入 Class indicate inject class
  25. export let indicateColor = ''; //指示器颜色 indicate color
  26. export let indicateActiveColor = ''; //指示器激活颜色 indicate active color
  27. export let aspectRatio = [16, 9]; //容器宽高比 container aspect ratio
  28. export let containerWidth = 0; //容器宽度 container width
  29. export let px = '0'; //容器横向内边距,0/1/2/4/6/8/12/16/24 container padding x
  30. export let py = '0'; //容器纵向内边距,0/1/2/4/6/8/12 container padding y
  31. export let translateX = 0; //未激活容器X方向偏移值 no active container translate x
  32. export let translateZ = 0; //未激活容器Z方向偏移值 no active container translate z
  33. export let rotateX = 0; //未激活容器X轴旋转值 no active container rotate x
  34. export let rotateY = 0; //未激活容器Y轴旋转值 no active container rotate y
  35. export let rotateZ = 0; //未激活容器Z轴旋转值 no active container rotate z
  36. export let activeInjClass = ''; //激活容器注入 Class active container inject class
  37. export let notActiveInjClass = ''; //未激活容器注入 Class no active container inject class
  38. export let radius = 'none'; //容器内部区域圆角,none/base/xl/2xl/full container inner radius
  39. export let innerInjClass = ''; //容器内部元素注入 Class container inner inject class
  40. // 始终触发的滑动距离百分比
  41. // touch move distance percent
  42. export let triggerLong = 30;
  43. // 始终不触发的滑动距离百分比
  44. // not touch move distance percent
  45. export let notTriggerLong = 10;
  46. // 触发的滑动速度系数
  47. // touch move speed coefficient
  48. export let triggerSpeed = 0.5;
  49. let width = containerWidth === 0 ? document.body.clientWidth : containerWidth; //宽度 width
  50. let active = data.length > 1 ? initActive + 1 : 1; //当前激活的item current active item
  51. let currentIndicate = data.length > 1 ? initActive : 0; //当前激活的指示器 current active indicate
  52. let longTransition = true; //长线指示器过渡 long line indicate transition
  53. let long = false; //长线指示器是否较长状态 long line indicate is long
  54. let once = true; //是否是第首次轮播,处理轮播间隔与过渡时间的差异 is first time play, handle interval and duration difference
  55. let translateXTransition = true; //是否进行过渡动画 is transition animation
  56. let initialState = true; //是否是初始状态 is initial state
  57. let startX = 0; //滑动开始X坐标 when start touch x position
  58. let moveX = 0; //滑动移动X坐标 when move touch x position
  59. let startTime = 0; //滑动开始时间 when start touch time
  60. let endTime = 0; //滑动结束时间 when end touch time
  61. let isMove = false; //是否滑动 is touch move
  62. // let transition = true;
  63. let swiperDom = null; //Swiper容器
  64. $: movePercent = moveX / width; //滑动距离占总宽度的百分比 touch width percent
  65. const dataNew =
  66. data.length > 1
  67. ? [data[data.length - 1], ...data, data[0], data[1]]
  68. : data.length === 1
  69. ? [data[data.length - 1], ...data, data[0]]
  70. : data; //实现无限轮播,复制一个新数组,防止改变原数组 implement infinite loop, copy a new array to prevent change original array
  71. const indicateAlignObj = {
  72. left: 'justify-start',
  73. center: 'justify-center',
  74. right: 'justify-end',
  75. };
  76. const pxObj = {
  77. '0': '',
  78. '1': 'px-1',
  79. '2': 'px-2',
  80. '4': 'px-4',
  81. '6': 'px-6',
  82. '8': 'px-8',
  83. '12': 'px-12',
  84. '16': 'px-16',
  85. '24': 'px-24',
  86. };
  87. const pyObj = {
  88. '0': '',
  89. '1': 'py-1',
  90. '2': 'py-2',
  91. '4': 'py-4',
  92. '6': 'py-6',
  93. '8': 'py-8',
  94. '12': 'py-12',
  95. };
  96. const radiusObj = {
  97. none: 'rounded-none',
  98. base: 'rounded-base',
  99. xl: 'rounded-xl',
  100. '2xl': 'rounded-2xl',
  101. full: 'rounded-full',
  102. };
  103. //根据 indicateStyle 和是否激活生成不同样式的 indicate
  104. //generate different style indicate according to indicateStyle and isActive
  105. const indicateStyleInnerFun = (indicateStyle, isActive, indicateColor, indicateActiveColor) => {
  106. switch (indicateStyle) {
  107. case 'point':
  108. return isActive
  109. ? `w-1.5 h-1.5 ${indicateActiveColor === '' ? 'bg-white' : indicateActiveColor}`
  110. : `w-1.5 h-1.5 ${indicateColor === '' ? 'bg-white/40' : indicateColor}`;
  111. case 'line':
  112. return isActive
  113. ? `w-6 h-1 ${indicateActiveColor === '' ? 'bg-white' : indicateActiveColor}`
  114. : `w-6 h-1 ${indicateColor === '' ? 'bg-white/40' : indicateColor}`;
  115. case 'pointLine':
  116. return isActive
  117. ? `w-6 h-1 ${indicateActiveColor === '' ? 'bg-white' : indicateActiveColor}`
  118. : `w-1 h-1 ${indicateColor === '' ? 'bg-white' : indicateColor}`;
  119. case 'longLine':
  120. return isActive
  121. ? `w-16 h-1 ${indicateColor === '' ? 'bg-white/40' : indicateColor}`
  122. : `w-1 h-1 ${indicateColor === '' ? 'bg-white/40' : indicateColor}`;
  123. default:
  124. console.log('传入的indicateStyle不在备选参数之内,将使用默认值!');
  125. return isActive
  126. ? `w-6 h-1 ${indicateActiveColor === '' ? 'bg-white' : indicateActiveColor}`
  127. : `w-1 h-1 ${indicateColor === '' ? 'bg-white' : indicateColor}`;
  128. }
  129. };
  130. const indicateStyleOutFun = (indicateStyle, isActive, indicateColor, indicateActiveColor) => {
  131. switch (indicateStyle) {
  132. case 'point':
  133. return isActive
  134. ? `w-1.5 h-1.5 ${indicateActiveColor === '' ? 'bg-primary dark:bg-dark' : indicateActiveColor}`
  135. : `w-1.5 h-1.5 ${indicateColor === '' ? 'bg-black/20 dark:bg-white/40' : indicateColor}`;
  136. case 'line':
  137. return isActive
  138. ? `w-6 h-1 ${indicateActiveColor === '' ? 'bg-primary dark:bg-dark' : indicateActiveColor}`
  139. : `w-6 h-1 ${indicateColor === '' ? 'bg-black/20 dark:bg-white/40' : indicateColor}`;
  140. case 'pointLine':
  141. return isActive
  142. ? `w-6 h-1 ${indicateActiveColor === '' ? 'bg-primary dark:bg-dark' : indicateActiveColor}`
  143. : `w-1 h-1 ${indicateColor === '' ? 'bg-primary dark:bg-dark' : indicateColor}`;
  144. case 'longLine':
  145. return isActive
  146. ? `w-16 h-1 ${indicateColor === '' ? 'bg-black/5 dark:bg-white/10' : indicateColor}`
  147. : `w-1 h-1 ${indicateColor === '' ? 'bg-black/20 dark:bg-white/40' : indicateColor}`;
  148. default:
  149. console.log('传入的indicateStyle不在备选参数之内,将使用默认值!');
  150. return isActive
  151. ? `w-6 h-1 ${indicateActiveColor === '' ? 'bg-primary dark:bg-dark' : indicateActiveColor}`
  152. : `w-1 h-1 ${indicateColor === '' ? 'bg-primary dark:bg-dark' : indicateColor}`;
  153. }
  154. };
  155. //对需要处理的偏移与旋转数值进行处理
  156. //process the offset and rotate value that need to be processed
  157. const translateXFun = (i, active, translateX) => {
  158. if (i === active) {
  159. return '0px';
  160. }
  161. if (i < active) {
  162. return `${translateX}px`;
  163. }
  164. if (i > active) {
  165. return `${-translateX}px`;
  166. }
  167. };
  168. const translateZFun = (i, active, translateZ, movePercent) => {
  169. if (i === active) {
  170. return `${0 - Math.abs(translateZ * (isMove ? movePercent : 0))}px`;
  171. } else {
  172. return `${-translateZ + Math.abs(translateZ * (isMove ? movePercent : 0))}px`;
  173. }
  174. };
  175. const rotateXFun = (i, active, rotateX, movePercent) => {
  176. if (i === active) {
  177. return `${-rotateX * (isMove ? movePercent : 0)}deg`;
  178. }
  179. if (i < active) {
  180. return `${rotateX - rotateX * (isMove ? movePercent : 0)}deg`;
  181. }
  182. if (i > active) {
  183. return `${-rotateX - rotateX * (isMove ? movePercent : 0)}deg`;
  184. }
  185. };
  186. const rotateYFun = (i, active, rotateY, movePercent) => {
  187. if (i === active) {
  188. return `${-rotateY * (isMove ? movePercent : 0)}deg`;
  189. }
  190. if (i < active) {
  191. return `${rotateY - rotateY * (isMove ? movePercent : 0)}deg`;
  192. }
  193. if (i > active) {
  194. return `${-rotateY - rotateY * (isMove ? movePercent : 0)}deg`;
  195. }
  196. };
  197. const rotateZFun = (i, active, rotateZ, movePercent) => {
  198. if (i === active) {
  199. return `${-rotateZ * (isMove ? movePercent : 0)}deg`;
  200. }
  201. if (i < active) {
  202. return `${rotateZ - rotateZ * (isMove ? movePercent : 0)}deg`;
  203. }
  204. if (i > active) {
  205. return `${-rotateZ - rotateZ * (isMove ? movePercent : 0)}deg`;
  206. }
  207. };
  208. const zIndexFun = (i, active, dataNew) => {
  209. if (i === active) {
  210. return i + 2;
  211. }
  212. if (i < active) {
  213. return -(dataNew.length - i - 1) + dataNew.length;
  214. }
  215. if (i > active) {
  216. return 2 * active - i + 2;
  217. }
  218. };
  219. //定时器
  220. // timer
  221. let intervalTime = null;
  222. //定时器执行函数
  223. // timer function
  224. const intervalTimeFun = () => {
  225. intervalTime = setInterval(() => {
  226. once = false;
  227. initialState = false;
  228. active++;
  229. currentIndicate++;
  230. long = false;
  231. longTransition = false;
  232. setTimeout(() => {
  233. long = autoplay;
  234. longTransition = true;
  235. }, duration);
  236. if (active === dataNew.length - 2) {
  237. //最后一个
  238. // the last one
  239. currentIndicate = 0;
  240. setTimeout(() => {
  241. // 切换动画完成后,关闭过渡动画,同时将展示的部分偷偷替换为最开始的样子。
  242. // After the switching animation is completed, turn off the transition animation, and at the same time, the displayed part is secretly replaced with the original appearance.
  243. active = 1;
  244. // transition = false;
  245. translateXTransition = false;
  246. }, duration);
  247. } else {
  248. //开启过渡
  249. // turn on transition
  250. // transition = true;
  251. translateXTransition = !initialState;
  252. }
  253. //派发Swiper容器change事件,i表示当前容器索引值
  254. // dispatch the Swiper container change event, i indicates the current container index value
  255. dispatch('change', currentIndicate);
  256. }, interval * 1000);
  257. };
  258. //判断Swiper容器是否在可视区域内,如果在,则开启定时器,否则不开启定时器
  259. // Determine whether the Swiper container is in the visible area. If it is, start the timer, otherwise do not start the timer
  260. const io = new IntersectionObserver(entries => {
  261. entries.forEach(item => {
  262. // isIntersecting是一个Boolean值,判断目标元素当前是否可见
  263. // isIntersecting is a Boolean value that determines whether the target element is currently visible
  264. if (item.isIntersecting) {
  265. if (autoplay) {
  266. clearInterval(intervalTime); //清除定时器 clear timer
  267. intervalTimeFun();
  268. }
  269. } else {
  270. clearInterval(intervalTime); //清除定时器 clear timer
  271. }
  272. });
  273. });
  274. onMount(() => {
  275. if (duration >= interval * 1000) {
  276. console.log('间隔时间必须大于过渡时间');
  277. return false;
  278. }
  279. // 加载完成后,通过定时器使item自动轮播。
  280. // After loading, use the timer to make the item automatically rotate.
  281. if (data.length < 2 || !autoplay) return false;
  282. long = false;
  283. longTransition = false;
  284. setTimeout(() => {
  285. long = autoplay;
  286. longTransition = true;
  287. }, 0);
  288. //懒轮播
  289. if (lazyplay) {
  290. io.observe(swiperDom);
  291. } else {
  292. if (autoplay) {
  293. clearInterval(intervalTime); //清除定时器 clear timer
  294. intervalTimeFun();
  295. }
  296. }
  297. return () => clearInterval(intervalTime); //清除定时器 clear timer
  298. });
  299. //点击事件
  300. // click event
  301. const clickImgFun = () => {
  302. //派发Swiper容器点击事件,currentIndicate表示点击的容器索引值
  303. // dispatch the Swiper container click event, currentIndicate indicates the index value of the clicked container
  304. dispatch('clickimg', currentIndicate);
  305. };
  306. //滑动开始
  307. // slide start
  308. const touchstartFun = e => {
  309. // 阻止默认事件
  310. // prevent default event
  311. e.preventDefault();
  312. isMove = true;
  313. startTime = new Date().getTime();
  314. translateXTransition = false;
  315. startX = e.clientX;
  316. };
  317. //滑动中
  318. // slideing
  319. const touchmoveFun = e => {
  320. if (!isMove) return false;
  321. swiperDom.setPointerCapture(e.pointerId);
  322. clearInterval(intervalTime); //清除定时器 clear timer
  323. moveX = e.clientX - startX;
  324. };
  325. //滑动结束
  326. // slide end
  327. const touchendFun = () => {
  328. endTime = new Date().getTime();
  329. const moveXABS = Math.abs(moveX); //滑动距离,moveX绝对值。 slide distance, moveX absolute value
  330. const timeLong = endTime - startTime; //滑动时间 slide time
  331. const speed = moveXABS / timeLong; //滑动速度阈值 slide speed threshold
  332. //滑动距离大于等于容器宽度 triggerLong/100 不用考虑滑动速度,都触发切换。
  333. //滑动距离小于等于容器宽度 notTriggerLong/100,无论速度快慢都不触发切换。
  334. //滑动距离大于容器宽度 notTriggerLong/100 且小于 triggerLong/100,需要判断滑动速度,用一个速度阈值来判断。阈值大于等于 triggerSpeed 切换,否则不切换。
  335. // The sliding distance is greater than or equal to the container width triggerLong/100, and the sliding speed does not need to be considered, and the switching is triggered.
  336. // The sliding distance is less than or equal to the container width notTriggerLong/100, and the switching is not triggered regardless of the speed.
  337. // The sliding distance is greater than the container width notTriggerLong/100 and less than triggerLong/100, the sliding speed needs to be judged, and a speed threshold is used to judge. The threshold is greater than or equal to triggerSpeed to switch, otherwise it will not switch.
  338. isMove = false;
  339. translateXTransition = true;
  340. long = false;
  341. longTransition = false;
  342. setTimeout(() => {
  343. long = autoplay;
  344. longTransition = true;
  345. }, duration);
  346. if (moveX <= -(width * (triggerLong / 100))) {
  347. //左滑
  348. // slide left
  349. moveX = 0;
  350. currentIndicate++;
  351. active++;
  352. if (active === dataNew.length - 2) {
  353. //最后一个
  354. // the last one
  355. currentIndicate = 0;
  356. setTimeout(() => {
  357. // 切换动画完成后,关闭过渡动画,同时将展示的部分偷偷替换为最开始的样子。
  358. // After the switching animation is completed, turn off the transition animation, and at the same time, replace the displayed part with the original appearance.
  359. active = 1;
  360. translateXTransition = false;
  361. }, duration);
  362. }
  363. } else if (moveX >= width * (triggerLong / 100)) {
  364. moveX = 0;
  365. currentIndicate--;
  366. active--;
  367. if (active === 0) {
  368. //第0个
  369. // the first one
  370. currentIndicate = dataNew.length - 4;
  371. setTimeout(() => {
  372. // 切换动画完成后,关闭过渡动画,同时将展示的部分偷偷替换为最开始的样子。
  373. // After the switching animation is completed, turn off the transition animation, and at the same time, replace the displayed part with the original appearance.
  374. active = dataNew.length - 3;
  375. translateXTransition = false;
  376. }, duration);
  377. }
  378. } else if (moveXABS > (notTriggerLong / 100) * width && moveXABS < width * (triggerLong / 100)) {
  379. if (moveX < 0 && speed >= triggerSpeed) {
  380. //左滑
  381. // slide left
  382. moveX = 0;
  383. currentIndicate++;
  384. active++;
  385. if (active === dataNew.length - 2) {
  386. //最后一个
  387. // last one
  388. currentIndicate = 0;
  389. setTimeout(() => {
  390. // 切换动画完成后,关闭过渡动画,同时将展示的部分偷偷替换为最开始的样子。
  391. // After the switching animation is completed, turn off the transition animation, and at the same time, replace the displayed part with the original appearance.
  392. active = 1;
  393. translateXTransition = false;
  394. }, duration);
  395. }
  396. } else if (moveX > 0 && speed >= triggerSpeed) {
  397. //右滑
  398. // slide right
  399. moveX = 0;
  400. currentIndicate--;
  401. active--;
  402. if (active === 0) {
  403. //第0个
  404. // the first one
  405. currentIndicate = dataNew.length - 4;
  406. setTimeout(() => {
  407. // 切换动画完成后,关闭过渡动画,同时将展示的部分偷偷替换为最开始的样子。
  408. // After the switching animation is completed, turn off the transition animation, and at the same time, replace the displayed part with the original appearance.
  409. active = dataNew.length - 3;
  410. translateXTransition = false;
  411. }, duration);
  412. }
  413. } else {
  414. moveX = 0;
  415. }
  416. } else {
  417. moveX = 0;
  418. }
  419. if (autoplay) {
  420. clearInterval(intervalTime); //清除定时器 clear timer
  421. intervalTimeFun();
  422. } else {
  423. dispatch('change', currentIndicate); //派发Swiper容器change事件,i表示当前容器索引值 Dispatch the Swiper container change event, i indicates the current container index value
  424. }
  425. };
  426. </script>
  427. <div
  428. bind:this={swiperDom}
  429. on:pointerdown={touchstartFun}
  430. on:pointermove={touchmoveFun}
  431. on:pointerup={touchendFun}
  432. class="touch-none cursor-move"
  433. >
  434. <!-- 轮播容器 -->
  435. <!-- Carousel container -->
  436. <div class="overflow-hidden relative" style="width:{width}px;height:{(width * aspectRatio[1]) / aspectRatio[0]}px;perspective:{width}px;">
  437. <!-- 通过循环dataNew渲染多个item -->
  438. <!-- Render multiple item through loop dataNew -->
  439. {#each dataNew as item, i}
  440. <div
  441. class={`absolute ${pxObj[px] || ''} ${pyObj[py] || ''} ${translateXTransition ? 'transition-all' : 'transition-none'} ${
  442. i === active ? activeInjClass : notActiveInjClass
  443. }`}
  444. style="width:{width}px;height:{(width * aspectRatio[1]) / aspectRatio[0]}px;left:{width * (i - active) +
  445. moveX}px;transition-duration: {duration}ms;z-index:{zIndexFun(
  446. i,
  447. active,
  448. dataNew,
  449. movePercent,
  450. )};transform:translateX({translateXFun(i, active, translateX, movePercent)}) translateZ({translateZFun(
  451. i,
  452. active,
  453. translateZ,
  454. movePercent,
  455. )}) rotateX({rotateXFun(i, active, rotateX, movePercent)}) rotateY({rotateYFun(
  456. i,
  457. active,
  458. rotateY,
  459. movePercent,
  460. )}) rotateZ({rotateZFun(i, active, rotateZ, movePercent)});"
  461. >
  462. {#if item.type === 'img'}
  463. <!-- svelte-ignore a11y-click-events-have-key-events -->
  464. <!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
  465. <img
  466. on:click={clickImgFun}
  467. class={`object-cover w-full h-full ${radiusObj[radius] || ''} ${innerInjClass}`}
  468. src={item.url}
  469. alt=""
  470. />
  471. {/if}
  472. {#if item.type === 'component'}
  473. <div class={` w-full h-full ${radiusObj[radius] || ''} ${innerInjClass}`}>
  474. <svelte:component this={item.component} />
  475. </div>
  476. {/if}
  477. </div>
  478. {/each}
  479. <!-- 轮播指示器(内部) -->
  480. <!-- Carousel indicator (inner) -->
  481. <div
  482. class:hidden={data.length < 2 || indicatePosition === 'out' || indicatePosition === 'none'}
  483. class={`absolute bottom-0 flex pt-4 pb-2 px-4 space-x-2 w-full bg-gradient-to-b from-black/0 to-black/40 z-50 ${indicateInjClass} ${
  484. indicateAlignObj[indicateAlign] || indicateAlignObj.center
  485. }`}
  486. >
  487. <!-- eslint-disable-next-line no-unused-vars -->
  488. {#each data as item, i}
  489. <div
  490. class={`${indicateStyleInnerFun(indicateStyle, currentIndicate === i, indicateColor, indicateActiveColor)} ${
  491. indicateRadius && 'rounded-full'
  492. } transition-all`}
  493. style="transition-duration: {duration}ms;"
  494. >
  495. {#if indicateStyle === 'longLine'}
  496. <div
  497. class={`absolute h-1 transition-all ${long ? 'ease-linear' : ''} ${indicateRadius && 'rounded-full'} ${
  498. long && currentIndicate === i ? 'w-16' : 'w-1'
  499. } ${indicateActiveColor === '' ? 'bg-white' : indicateActiveColor}`}
  500. style={`${
  501. longTransition
  502. ? `transition-duration: ${currentIndicate === 0 && once ? interval * 1000 : interval * 1000 - duration}ms`
  503. : `transition-duration:${duration}ms`
  504. }`}
  505. />
  506. {/if}
  507. </div>
  508. {/each}
  509. </div>
  510. </div>
  511. <!-- 轮播指示器(外部) -->
  512. <!-- Carousel indicator (outer) -->
  513. <div
  514. class:hidden={data.length < 2 || indicatePosition === 'inner' || indicatePosition === 'none'}
  515. class={`flex py-3 px-4 space-x-2 w-full ${indicateAlignObj[indicateAlign] || indicateAlignObj.center} ${indicateInjClass}`}
  516. >
  517. <!-- eslint-disable-next-line no-unused-vars -->
  518. {#each data as item, i}
  519. <div
  520. class={`${indicateStyleOutFun(indicateStyle, currentIndicate === i, indicateColor, indicateActiveColor)} ${
  521. indicateRadius && 'rounded-full'
  522. } transition-all`}
  523. style="transition-duration: {duration}ms;"
  524. >
  525. {#if indicateStyle === 'longLine'}
  526. <div
  527. class={`absolute h-1 transition-all ${long ? 'ease-linear' : ''} ${indicateRadius && 'rounded-full'} ${
  528. long && currentIndicate === i ? 'w-16' : 'w-1'
  529. } ${indicateActiveColor === '' ? 'bg-primary dark:bg-dark' : indicateActiveColor}`}
  530. style={longTransition
  531. ? `transition-duration: ${currentIndicate === 0 && once ? interval * 1000 : interval * 1000 - duration}ms;`
  532. : `transition-duration:${duration}ms`}
  533. />
  534. {/if}
  535. </div>
  536. {/each}
  537. </div>
  538. </div>