js纯函数实现页面自定义区域滚动效果

·  阅读 103
js纯函数实现页面自定义区域滚动效果

需求:
1、实现页面种某个区域的内容自动滚动;
2、鼠标划入时停在当前滚动的位置,鼠标离开后继续当前位置滚动;
2、自动滚动区域可自由选择;鼠标划入是否停止滚动可配置。
思路整理:
1、获取到指定滚动区域的元素节点,和滚动的内容,
2、获取滚动区域、滚动内容的高度,如果滚动内容高度大于滚动区域才能滚动,
3、为实现滚动时无缝效果,我们需要将滚动区域复制一份插入到原始滚动内容的末尾, 让元素滚出容器后有数据填充,实现无间断效果。
4、编写css滚动样式animation动画上场,
   ①为了一个函数搞定,我们不需要再自己去copy这样的样式放在样式表中,所以我们使用给head中动态插入style标签的方式,
   ②但是这里需要注意一点就是如果一个页面中有多个需要滚动的区域时,因为每个滚动的高度、速度、鼠标划入是否暂停等都是独立不关联的,所以我们再创建style时也应该为独立的,切再次创建时应该删除原有的样式标签,所以我们给style表添加一个id属性作为唯一的判定条件。
编码:

/**
 * 为指定元素设置滚动
 * @param { classname } key - 每个滚动元素的全局唯一标识,这个类名需要设置再滚动容器得父节点,
 *                            key必须传入,否则极易造成样式污染
 * @param { classname } content - 滚动内容得选择器,用于确定那个内容要滚动
 * @param { classname } container - 滚动容器选择器,滚动得内容要再那个容器中滚动,如果不传入则
                                    content的父节点
 * @param { number } speed - 滚动的速度,1为基准,如果想快则设置小于1的数,想慢则设置大于1的数
 * @param { boolean } paused - 鼠标划入滚动容器时,滚动是否要暂停
 */
export function setRollEffect({
  key = '',
  content = '',
  container = '',
  speed = 1,
  paused = true,
}) {
  // 获取滚动内容的高度,并拿到滚懂的元素节点
  const contentNode = document.querySelector(`${key} ${content}`);
  const { offsetHeight, childNodes } = contentNode;
  
  // 获取滚动容器的高度
  let containerH = 0;
  if (container) containerH = document.querySelector(`${key} ${container}`).offsetHeight;
  else containerH = contentNode.parentNode.offsetHeight;
  
  // 当容器高度大于滚动内容的高度时,无需滚动
  if (containerH >= offsetHeight) return;
  // 将滚动的内容复制一份插入到末尾
  childNodes.forEach((item, index) => {
    contentNode.append(item.cloneNode(true));
  });
  
  const nodeKey = key ? key : content
  /**
   * 获取所有滚动标识的样式表
   */
  const styleList = document.querySelectorAll('head style[roll-id]');
  styleList.forEach(item => {
    if (item['roll-id'] === nodeKey) item.remove();
  });

  // 创建一个style标签
  const style = document.createElement('style');
  // 创建这个style标签的内容,也就是滚动所需要的动画
  const keyframeName = nodeKey.match(/\w+/g).join('');
  const keyFrames = `\
    @keyframes ${keyframeName} {\
      0% {\
        transform: translate3d(0, 0, 0);\
      }\
      100% {\
        transform: translate3d(0, -${offsetHeight}px, 0);\
      }\
    }`;

  // 移动20像素需要1s作为滚动速度的基准,以此计算出这个原始列表滚动完所需要的时间
  const animation = `
    ${key} ${content} {\
      animation: ${(offsetHeight / 20) * speed}s ${keyframeName} linear infinite normal;\
    }\
    ${key} ${content}:hover {\
      animation-play-state: ${paused ? 'paused' : 'unset'};
    }\
  `;

  /**
   * 将构造好的动画样式内容赋给style,并将style样式表插入到head中
   * 并给style设置一个roll-id,当key不存在时取content作为roll-id
   * 这里为什么一定要添加一个roll-id,是为了当再次调用该方法时,避免给head中重复添加相同类名的css样式
   */
  style.innerHTML = keyFrames + animation;
  style.setAttribute('roll-id', nodeKey);
  style['roll-id'] = nodeKey;
  document.getElementsByTagName('head')[0].appendChild(style);
}
复制代码
分类:
前端
标签: