撸一个掘金APP会员等级轮播

使用的是我之前开发的开源库 bear-react-carousel

主要试试看能做到什么程度,之前公司也有类似的需求

废话不多说,直接开始

需求

首先我们先看掘金在APP端的预览结果

  • 可滑动的部分只有 卡片的部分
  • 并且在滑动时等级卡片会往上移动
  • 等级卡片显示为置中为 选中项目
  • 等级卡片下方需要被遮住(圆弧),不显示完全
  • 等级名称项目需同步移动
  • 等级名称项目移动时圆弧移动
  • 等级名称线需同步移动
  • API 捞回时,预设需要移动到选中的等级(无动画移动)

开发轮播项目

轮播项目可以切分为:

  • 等级卡片,显示1.2个并且置
tsx 复制代码
<BearCarousel
    slidesPerView={1.2}
    spaceBetween={20}
    isCenteredSlides={true}
    // ...ignore
/>
  • 等级名称
  • 等级线 这两个都是显示3个并且置中
tsx 复制代码
<BearCarousel
    slidesPerView={3}
    isCenteredSlides={true}
    // ...ignore
/>

所以开发目标是 移动等级卡片时,同步移动 等级名称与等级线

tsx 复制代码
import React, {useCallback, useEffect, useRef, useState} from 'react';
import BearCarousel, {TMoveEffectFn, TBearSlideItemDataList, BearSlideCard, elClassName, Controller, TOnSlideChange} from 'bear-react-carousel';

const MemberLevelWrapper = () => {
   const carouselMainRef = useRef<BearCarousel>(null);
   const carouselMetaRef = useRef<BearCarousel>(null);
   const carouselLineRef = useRef<BearCarousel>(null);

   return <>
        {/* 等级卡片 */}
        <BearCarousel
            ref={carouselMainRef}
            syncCarouselRefs={[carouselMetaRef, carouselLineRef]}
            slidesPerView={1.2}
            spaceBetween={20}
            isCenteredSlides={true}
            // ...ignore
        />

        {/* 等级名称 */}
        <BearCarousel
            ref={carouselMetaRef}
            // ...ignore
        />

        {/* 等级名称线 */}
        <BearCarousel
            ref={carouselLineRef}
            // ...ignore
        />
    </>;
};    

然后再来是 滑动时等级卡片会往上移动, 新增一个 动画 effect function

tsx 复制代码
import BearCarousel, {TMoveEffectFn} from 'bear-react-carousel';

const mainMoveEffectFn: TMoveEffectFn = useCallback((percentageInfo) => {
    const transformY = 40;
    return {
        transform: `translate(0px, ${-transformY * (percentageInfo.calcPercentage - 1)}px)`,
    };
}, []);

<BearCarousel
    ref={carouselMainRef}
    syncCarouselRefs={[carouselMetaRef, carouselLineRef]}
    moveEffect={{
        moveFn: mainMoveEffectFn,
    }}
    // ...ignore
/>

等级名称的圆弧移动

tsx 复制代码
const levelNameMoveEffectFn: TMoveEffectFn = useCallback((percentageInfo) => {
    const transformY = -19;
    return {
        transform: `translate(0px, ${-transformY * (percentageInfo.calcPercentage - 1)}px)`,
    };
}, []);

<BearCarousel
    ref={carouselMainRef}
    moveEffect={{
        moveFn: levelNameMoveEffectFn,
    }}
    // ...ignore
/>

至于圆弧的部分,我们最后使用遮罩的方式来显示,并且关闭 NavButton、Pagination、MouseMove,画SVG不熟的话,可以使用这个工具 yqnn.github.io/svg-path-ed...

tsx 复制代码
<LevelLine>
    <LineBearCarousel
        ref={carouselLineRef}
        data={lineData}       
        slidesPerView={3}
        isCenteredSlides={true}
        isEnableNavButton={false}
        isEnablePagination={false}
        isEnableMouseMove={false}
    />

    <svg height="100%" width="100%">
        <clipPath id="wave12">
            {/*跟隨線*/}
            <path d="M 0 4 C 175 30 175 30 356 4 L 356 2 C 175 28 175 28 0 2" stroke="black" fill="transparent"/>
        </clipPath>
    </svg>
</LevelLine>

而 Level Card 遮罩的部分一样,但我用了3块

tsx 复制代码
<svg height="100%" width="100%">
    <clipPath id="wave10">
        <path d="M 0,0 356,0 356,130 0,130" stroke="black" fill="transparent"/>
        {/* 圓弧 */}
        <path d="M 0 130 C 175 155 175 155 356 130" stroke="black" fill="transparent"/>
         {/* 下箭頭 */}
        <path d="M 152 143 L 176 153 L 178 153 L 202 143" stroke="black" fill="transparent"/>
    </clipPath>
</svg>

最后就是 预设选中等级的部分(无动画方式移动)

tsx 复制代码
const [carouselMainController, setMainController] = useState<Controller>();
const [currLevel, setCurrLevel] = useState<{lv: number,count: number}|undefined>();


useEffect(() => {
    carouselMainController?.slideToPage(5, false);
}, [carouselMainController]);


<BearCarousel
    ref={carouselMainRef}
    syncCarouselRefs={[carouselMetaRef]}
    onSlideChange={handleSlideChange}
    setController={setMainController}
    slidesPerView={1.2}
    spaceBetween={20}
    isCenteredSlides={true}
    // ...ignore
/>

完成

目前成果作为文件的展示使用,想试试看的客观可以实际操作看看

bear-react-carousel.pages.dev/

以上就完成了,基本上如果两边都需要移动的话,互相同步在bear-react-carousel 因为是进行独立的同步控制,所以不会循环互控,但也因为这样所以目前是无法A控制B , B自动再控制C,所以在这边可以发现是A控制B和C。

相关推荐
miss16 分钟前
AI 改完不敢上线?OpenSpec 规约驱动开发实战
前端·代码规范·前端工程化
AiMan1 小时前
腾讯ima还是不可以导出左侧所有对话,只能单条导出,方法不对吗
前端
去伪存真1 小时前
并发量一高就装死?Agent 全链路“防猝死”手册
前端·agent
Moment1 小时前
AI 编程时代,聊聊我的 Mac mini 双屏桌面
前端·后端
AiMan1 小时前
先确认能不能一次把Microsofat Copilot所有内容打包一个文件导出
前端
总要学点什么1 小时前
第97篇:三维数据加载-城市建筑白模自定义着色器——让一条光带沿高度扫上去,快慢却由帧率说了算
前端·gis·webgl·cesium·着色器·空间分析·白模
上海懒图科技2 小时前
工厂厂区电子地图定位导航:厂区人车精准定位,安全合规双保障
前端·arcgis·vue
西安小哥2 小时前
端侧跑大模型,真正的门槛不在参数量:一次 596 秒到 10 秒的压缩路径复盘
前端·人工智能
陈随易2 小时前
Cloudflare 出钱,Vite 团队挑人,44 个维护者分 30 万美元
前端·后端·程序员
恋猫de小郭3 小时前
Flutter THLC 的 WebView 滚动终于从 70 FPS 提升到 120 FPS
android·前端·flutter