react + better-scroll 横向滚动案例

在这里插入图片描述

JS

import React, { useState, useEffect, useRef } from 'react'
import styles from './style.less'
import { RestOutlined, RedditOutlined } from '@ant-design/icons'
import { DS } from './utils/index'
const data = [
    { event: '向女神表白被拒', location: '钱柜KTV', src: 'https://www.dataojocloud.com/dataeye/v1/data/image/get?imageid=61bc5c91fd73384a0bde157f', id: 1 },
    { event: '打架斗殴', location: '孙浩家里', src: 'https://www.dataojocloud.com/dataeye/v1/data/image/get?imageid=61bc5c9422a0c63075b01ec5', id: 2 },
    { event: '发酒疯导致被打', location: '郭帅家里', src: 'https://www.dataojocloud.com/dataeye/v1/data/image/get?imageid=617a55a011001e6b8ea0cce3', id: 3 },
    { event: '连续通宵', location: '鸣鹿网吧', src: 'https://www.dataojocloud.com/dataeye/v1/data/image/get?imageid=61bc5c982ee1bd7d90486745', id: 4 },
    { event: '挑衅路人', location: '鹿邑县城', src: 'https://www.dataojocloud.com/dataeye/v1/data/image/get?imageid=617a55a422a0c62f56684521', id: 5 },
    { event: '唱歌音质过差', location: '麦地', src: 'https://www.dataojocloud.com/dataeye/v1/data/image/get?imageid=617a5596fd73380b818dc300', id: 6 },
    { event: '爬树掉下去', location: '后陈西头', src: 'https://www.dataojocloud.com/dataeye/v1/data/image/get?imageid=617a559d2ee1bd5a04779569', id: 7 },
]
const Index = () =>
{
    const scrollRef = useRef()
    const scrollBar = useRef()
    const [dsContainer, setDsContainer] = useState(null)
    useEffect(() =>
    {  // 发送数据请求 设置订阅/启动定时器 手动更改 DOM 等 ~
        DS({ wrapper: scrollRef.current, scrollBar: scrollBar.current }, setDsContainer)
        return () =>
        {  // 组件卸载之前 做一些收尾工作 比如清楚定时器/取消订阅 等 ~
        }
    }, [])  // 检测数组内变量 如果为空 则监控全局
    const scrollDom = () =>
    {
        return (
            <div id='wrapper' ref={scrollRef} className={styles.wrapper}>
                <div className={styles.content}>

                    {data.map((data, index) => (
                        <div key={data.id} className={styles.coreItem}>
                            <div className={styles.detail}>
                                <div className={styles.detailItem}>
                                    <div className={styles.round}></div>
                                    <span className={styles.event}>事件</span>
                                    <span className={styles.colon}>:</span>
                                    <span className={styles.eventDetails}>{data.event}</span>
                                </div>
                                <div className={styles.detailItem}>
                                    <div className={styles.round}></div>
                                    <span className={styles.event}>地点</span>
                                    <span className={styles.colon}>:</span>
                                    <span className={styles.eventDetails}>{data.location}</span>
                                </div>
                            </div>
                            <div className={styles.coreItemImg}>
                                <img src={data.src} alt="" />
                            </div>
                        </div>
                    ))}
                </div>
                <div ref={scrollBar} className={styles.horizontal_scrollbar}>
                    <div className={styles.horizontal_indicator}></div>
                </div>
            </div>
        )
    }
    return (
        <div className={styles.container}>
            <div className={styles.overall}>
                <div className={styles.head}>
                    <RedditOutlined className={styles.RedditOutlined} />
                    <span className={styles.headTitle}>羽神天下第一</span>
                </div>
                <div className={styles.core}>
                    <div className={styles.coreLeft}>
                        <div className={styles.leftBox}>
                            <RestOutlined className={styles.RestOutlined} />
                            <div className={styles.article}>
                                <span className={styles.articleQuantity}>223</span>
                                <span className={styles.unit}></span>
                            </div>
                            <span className={styles.abnormalOccurrence}>羽神异常事件</span>
                        </div>
                    </div>
                    <div className={styles.line}></div>
                    {scrollDom()}
                </div>
            </div>
        </div >
    )
}

export default Index

utils

import BScroll from '@better-scroll/core'  // BScroll 核心
import MouseWheel from '@better-scroll/mouse-wheel'  // 引入滚轮
import Scrollbar from '@better-scroll/scroll-bar'

BScroll.use(MouseWheel)
BScroll.use(Scrollbar)

export const DS = (container, setDsContainer = false, action = false) =>
{

    const { wrapper, scrollBar } = container  // wrapper 可以是 id scrollBar 必须是 Ref
    const { payload } = action
    if (wrapper)
    {
        if (typeof wrapper === 'string')
        {
            let wrapperRef = document.querySelector('#' + wrapper)
            deployX(wrapper ? [wrapperRef, scrollBar] : null, setDsContainer ? setDsContainer : null, payload ? payload.callback : null)
        } else
        {
            deployX(wrapper ? [wrapper, scrollBar] : null, setDsContainer ? setDsContainer : null, payload ? payload.callback : null)
        }
    }
}
// X轴配置
const deployX = (container, setDsContainer) =>  // horizontal 拿到自定义滚动条 ref 
{
    let [wrapper, horizontal] = container  // 结构赋值
    if (wrapper)
    {
        let ds = new BScroll(wrapper, {
            probeType: 0,  // 默认0 不侦测 0和1 都不侦测  2:在手指滚动的过程中侦测 手指离开后的惯性滚动过程中不侦测 3:只要是滚动 都进行侦测
            click: true,  // 可以点击  用法:要覆盖本机滚动,BetterScroll必须禁止某些默认浏览器行为,例如鼠标单击。如果您希望您的应用程序响应click事件,则必须将该选项显式设置为true。然后BetterScroll将向其_constructed调度事件添加一个私有属性,该属性的值为true。
            mouseWheel: true,  // 鼠标滚轮
            scrollX: true,
            scrollY: false,
            scrollbar: {
                customElements: [horizontal],  // 自定义滚动条  [horizontal,vertical]  横竖 我只用了 horizontal 滚动条 DOM 传过来的 REF
                fade: true,  // 淡入淡出
                interactive: true,
                scrollbarTrackClickable: true
            }  // 滚动条
        })
        setDsContainer(ds)  // 保存 ds
    }
}

CSS

.container {
  position: absolute;
  width: 100%;
  height: 100%;
  background-color: rgb(207, 108, 108);

  .overall {
    margin: 200px auto;
    position: relative;
    width: 1000px;
    height: 285px;
    border-radius: 4px;
    box-sizing: border-box;
    background: linear-gradient(0deg, rgba(10, 15, 22, .7) 0%, rgba(21, 31, 45, .7) 100%);
    line-height: 1.45;
  }

  img {
    width: 100%;
    height: 100%;
  }
}

.head {
  display: flex;
  align-items: center;
  width: 100%;
  height: 60px;
  background: linear-gradient(0deg, rgba(27, 71, 143, .9) 0%, rgba(21, 31, 45, .9) 100%);
  border-radius: 4px;

  .RedditOutlined {
    margin-left: 22px;
    font-size: 38px;
    color: rgb(45, 198, 224);
  }

  .headTitle {
    margin-left: 8px;
    font-size: 30px;
    font-weight: 600;
    color: #FFFFFF;
    background: linear-gradient(0deg, rgba(90, 203, 255, .9) 0%, rgba(26, 134, 255, .9) 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
  }
}

.core {
  display: flex;

  .coreLeft {
    width: 249px;
    height: calc(~'100% - 60px');
    overflow: hidden;

    .leftBox {
      padding: 20px 0 0 20px;
      margin: 21px 30px 25px 20px;
      width: 196px;
      height: 179px;
      background: linear-gradient(0deg, #16508D 0%, #041528 100%);
      border: 1px solid rgba(24, 63, 113, 0.4);
      border-radius: 4px;

      .RestOutlined {
        font-size: 42px;
        color: cornflowerblue;
      }

      .article {
        display: flex;
        color: #FFFFFF;

        .articleQuantity {
          font-size: 38px;
          font-weight: 500;

        }

        .unit {
          margin-left: 10px;
          padding-top: 20px;
          font-size: 20px;
          font-weight: 400;
        }
      }

      .abnormalOccurrence {
        display: flex;
        font-size: 22px;
        font-weight: 400;
        color: #AFC6E4;
      }
    }

  }

  .line {
    margin-top: 18px;
    width: 1px;
    height: 185px;
    background: rgba(50, 93, 154, .6);
    border-radius: 4px;
  }

  .wrapper {
    position: relative;
    white-space: nowrap;
    width: 753px;
    overflow: hidden;

    .content {
      display: inline-block;

      .coreItem {
        display: inline-block;
        margin-left: 31px;
        width: 216px;
        height: 100%;

        .detail {
          padding-top: 18px;
          height: 81px;
          line-height: 1.45;

          .detailItem {
            display: flex;
            align-items: center;

            .round {
              width: 8px;
              height: 8px;
              background: rgba(249, 81, 3, 1);
              border-radius: 50%;
            }

            .event {
              margin-left: 6px;
              color: rgba(180, 217, 244, 1);
              font-size: 20px;
            }

            .colon {
              margin-left: 2px;
              color: rgba(180, 217, 244, 1);
              font-size: 20px;
            }

            .eventDetails {
              margin-left: 10px;
              font-size: 20px;
              color: rgba(255, 255, 255, 1);
            }
          }
        }
      }

      .coreItemImg {
        width: 100%;
        height: 119px;
        border-radius: 4px;
      }
    }
  }

  // 自定义滚动条
  .horizontal_scrollbar {
    position: absolute;
    left: 50%;
    bottom: 10px;
    width: 100px;
    height: 7px;
    border-radius: 5px;
    transform: translateX(-50%) translateZ(0);
    background: linear-gradient(to right, rgba(182, 54, 128) 0%, rgba(16, 202, 100, ) 100%);

    .horizontal_indicator {
      height: 100%;
      width: 20px;
      border-radius: 5px;
      background-color: #db8090;
    }
  }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

臧小川

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值