撸一个掘金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。

相关推荐
子非鱼a2 小时前
【WEB】multiSQL
前端
lemon_sjdk3 小时前
DOM 节点
java·前端·javascript
nvd113 小时前
深入现代 Web 鉴权架构:网关统一代理 (Forward-Auth) vs 前端持有 JWT 的终极选型与边缘同域实践
前端·架构·状态模式
leoZ2313 小时前
2026-09-09-springboot-cloud-deploy-pitfalls
java·前端·javascript·vue.js·人工智能·spring boot·后端
YWL3 小时前
OpenLayers弹窗Overlay深度实战
前端·vue·openlayers
YWL4 小时前
OpenLayers+ECharts联动:地图点击联动图表,数据可视化大屏方案
前端·信息可视化·vue·echarts·openlayers
芭拉拉小魔仙4 小时前
Vue 2 门诊收费系统中的医保结算流程设计与实践
前端·javascript·vue.js
moonrailgun4 小时前
用 Node.js 复刻 Codex Astra 的终端星光
前端·javascript·算法
海上彼尚4 小时前
Cursor 模型的强度实测排行
前端·人工智能·后端
默_笙4 小时前
💫 给金鱼建图书馆(下):Milvus 向量数据库,让 AI 拥有长期记忆
前端·javascript