JavaScript 方法封装:前端动态添加滚动条动画-可复用-支持横向纵向样式自定义

118 阅读2分钟

介绍

绘制公司大屏业务的时候,很多地方需要添加滚动动画,所以封装了一个方法用于动态添加,不需要每个页面写一次 css,方法支持自定义方向、动画播放模式等。

代码

/**
 * 给元素设置 marquee 内容滚动效果,支持来回滚动,正常跑马灯,无限无缝滚动。
 * 一般来说设置两层,滚动的区间就是父元素的大小。
 * 若 #demo 高度小于 container,除非 loopType 设置 infinite,否则不会有动画。
 * <div class="demo-container"><div id="#demo">...span.items...</div></div>
 * @example
 * marquee('#demo'); /// 默认横向正常滚动(loopType=normal)
 * marquee('.demo-y', {direction: 'Y', loopType: 'infinite', speed: 3}); /// Y 轴无限无缝滚动,speed > 0 越小速度越快。
 * marquee('.demo-x', {direction: 'X', loopType: 'origin', speed: 3, style: 'animation-delay:2s;', parentStyle: 'color:red;'}); /// X 轴无限来回滚动
 * @param selector 选择器字符串
 * @param options 动画配置
 * @returns
 */
export function marquee(
  selector: string,
  options?: {
    direction?: 'X' | 'Y';
    loopType?: 'infinite' | 'normal' | 'origin';
    speed?: number;
    style?: string;
    parentStyle?: string;
  },
): void {
  try {
    const cssAnimation =
      '@keyframes marquee-ANIMATION_NAME{0%{transform:translate3d(0,0,0);-webkit-transform:translate3d(0,0,0);-moz-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0);-o-transform:translate3d(0,0,0)}50%{transform:translate3d(X_TEMP_VAL,Y_TEMP_VAL,0);-webkit-transform:translate3d(X_TEMP_VAL,Y_TEMP_VAL,0);-moz-transform:translate3d(X_TEMP_VAL,Y_TEMP_VAL,0);-ms-transform:translate3d(X_TEMP_VAL,Y_TEMP_VAL,0);-o-transform:translate3d(X_TEMP_VAL,Y_TEMP_VAL,0)}100%{transform:translate3d(X_END_VAL,Y_END_VAL,0);-webkit-transform:translate3d(X_END_VAL,Y_END_VAL,0);-moz-transform:translate3d(X_END_VAL,Y_END_VAL,0);-ms-transform:translate3d(X_END_VAL,Y_END_VAL,0);-o-transform:translate3d(X_END_VAL,Y_END_VAL,0)}}';
    const tempId = selector.replace(/[.#]/g, '');
    const styleElId = `style-${tempId}`;
    const $animationStyle = document.getElementById(styleElId) ?? document.createElement('style');
    $animationStyle.id = styleElId;
    const $marqueeDom: any = document.querySelector(selector);
    const noAnimation =
      options?.loopType != 'infinite' && $marqueeDom?.clientHeight < $marqueeDom?.parentElement?.offsetHeight;
    $marqueeDom?.setAttribute(
      'style',
      `overflow:visible;animation-name:marquee-${tempId};animation-timing-function:linear;animation-iteration-count:infinite;animation-duration:${
        ((options?.direction === 'Y' ? $marqueeDom.clientHeight : $marqueeDom.clientWidth) / 200) *
          (options?.speed ?? 3) ?? 5
      }s;${noAnimation ? 'animation-duration:0s;' : ''}${
        options?.style ??
        `${
          options?.loopType === 'origin'
            ? options?.direction === 'Y'
              ? 'padding-bottom:12px;'
              : 'padding-right:12px;'
            : ''
        }`
      }`,
    );
    if (options?.direction === 'Y') {
      $animationStyle.innerHTML = cssAnimation
        .replace('ANIMATION_NAME', tempId)
        .replace(/X_TEMP_VAL/g, '0')
        .replace(
          /Y_TEMP_VAL/g,
          options.loopType === 'origin' ? `calc(-100% + ${$marqueeDom?.parentElement?.offsetHeight ?? 0}px)` : '-50%',
        )
        .replace(/X_END_VAL/g, '0')
        .replace(/Y_END_VAL/g, options.loopType === 'origin' ? '0' : '-100%');
    } else {
      $animationStyle.innerHTML = cssAnimation
        .replace('ANIMATION_NAME', tempId)
        .replace(/Y_TEMP_VAL/g, '0')
        .replace(
          /X_TEMP_VAL/g,
          options?.loopType === 'origin' ? `calc(-100% + ${$marqueeDom?.parentElement?.offsetWidth ?? 0}px)` : '-50%',
        )
        .replace(/Y_END_VAL/g, '0')
        .replace(/X_END_VAL/g, options?.loopType === 'origin' ? '0' : '-100%');
    }
    $marqueeDom?.parentElement?.setAttribute('style', `overflow:hidden;${options?.parentStyle ?? ''}`);
    if (options?.loopType === 'infinite') {
      $marqueeDom.parentElement.innerHTML = $marqueeDom.outerHTML + $marqueeDom.outerHTML;
    } else {
      // $marqueeDom.parentElement.innerHTML = $marqueeDom.outerHTML;
    }
    !document.getElementById(styleElId) && document.getElementsByTagName('head')[0].appendChild($animationStyle);
  } catch (e) {
    console.log('js-xxx:marqueeError--->', e);
  }
}

也可直接安装 js-xxx 工具库直接使用

// npm i js-xxx
import { marquee } from 'js-xxx';

marquee('#demo'); /// 默认横向正常滚动(loopType=normal)
marquee('.demo-y', {direction: 'Y', loopType: 'infinite', speed: 3}); /// Y 轴无限无缝滚动,speed > 0 越小速度越快。
marquee('.demo-x', {direction: 'X', loopType: 'origin', speed: 3, style: 'animation-delay:2s;', parentStyle: 'color:red;'}); /// X 轴无限来回滚动