特效页面:排名多场景组件的设计

1,592 阅读4分钟

前言


本文主要是分享在一个涉及到本人排名在多种情况下所处位置不同的具体实践。

图示


image.png

分析


针对设计稿提供效果,共有8种情况,分别是4个节点的4种,5个节点的4种。

从dom出发,简单的处理方案时,按照4+4的方式,将每个节点都放在视图中,然后控制其样式以及显示隐藏。

样式的部分主要是考量1 是4个节点还是5个节点 2 当前的这个节点是否是用户的排名
是否显示主要考量的是1 是4个节点还是5个节点 2 当前用户的排名所能得到的节点排序

因此,只需要知道用户的排名以及我们的4个节点的节点数组去判断就可以了,也是需要两个工具函数。

工具函数

只与业务逻辑有关,组件无关,抽离到constant.js中,更建议放在领域模型的文件中

/**
 * 
 * @param {*} rank 判断拿几等奖 
 */
export const judgePrizeIndex = (rank) => {
   const judgeArray = [1, 10, 20, 50];
   let prizeIndex = 1
   let hasFind = false
   if (!rank) { 
       prizeIndex = 5
       return prizeIndex
   } 
   judgeArray.forEach((item, index) => {
       if (rank <= item && !hasFind) {
           prizeIndex = index + 1;
           hasFind = true
       } else if (rank > item && index === 3) {
           prizeIndex =5;
       }
   });
   return prizeIndex
};

export const judgeIsCertain = rank => { 
   const judgeArray = [1, 10, 20, 50];
   return judgeArray.includes(rank)
}

而样式的部分是要考量节点的属性以及上面两个工具函数的结果,也需要定义一个工具函数

   const certainClass = (currentIndex, flag) => {
            let className = "item";
            if (isCertain) {
                className += " four";
                if (currentIndex === prizeIndex) {
                    className += " current";
                }
            } else {
                className += " five";
                if (currentIndex === prizeIndex && !flag) {
                    className += " current";
                }
            }
            return className;
        };

label的组件设计

import React from "react";
import { judgePrizeIndex, judgeIsCertain } from '../constant'
import './rankLabel.scss'
/**
 * 
 * @param {*} props
 * @description 分标签展示奖项 
 */
const RankLabelList = (props) => {
    const { rank, auth,score } = props;
    console.log('auth',auth)
    const isCertain = judgeIsCertain(rank)
    const prizeIndex = judgePrizeIndex(rank)
    const certainClass = (currentIndex,flag) => { 
        let className = 'item'
        if (isCertain) {
            className += ' four'
            if (currentIndex === prizeIndex) {
                className += ' current'
            }
        } else { 
            className += ' five'
            if (currentIndex === prizeIndex && !flag) {
                className += ' current'
            }
        }
        return className

    }

    return (
        <div className="left" id='ranklabellist'>
            <div className={certainClass(1,true)}>
                <div className="rank">第1名</div>
                <div className="prize">5G手机</div>
            </div>
            {/* 中间的位置 */}
            {prizeIndex === 2 &&!isCertain && <div className={certainClass(2,false)}>
                <div className="rank">{`第${rank}名`}</div>
                <div className="prize">66元现金红包</div>
            </div>}
            <div className={certainClass(2,true)}>
                <div className="rank">第10名</div>
                <div className="prize">66元现金红包</div>
            </div>
            {/* 中间的位置 */}
            {prizeIndex === 3 &&!isCertain && <div className={certainClass(3,false)}>
                <div className="rank">{`第${rank}名`}</div>
                <div className="prize">16元现金红包</div>
            </div>}
            <div className={certainClass(3,true)}>
                <div className="rank">第20名</div>
                <div className="prize">16元现金红包</div>
            </div>
            {/* 中间的位置 */}
            {prizeIndex === 4 && !isCertain &&<div className={certainClass(4,false)}>
                <div className="rank">{`第${rank}名`}</div>
                <div className="prize">6元现金红包</div>
            </div>}
            <div className={certainClass(4,true)}>
                <div className="rank">第50名</div>
                <div className="prize">6元现金红包</div>
            </div>
            {/* 最后的位置 */}
            {prizeIndex === 5 && !isCertain &&<div className={certainClass(5)}>
                {/* 单个元素添加一个空div来上下居中 */}
                {
                    !score && <div className="blank-ele" />
                }
                <div className="rank">{!score ? '未参加':(score.valid? `第${rank}名`:'未认证') }</div>
                { score&&!score.valid   && <div className="rank" style={{marginTop:5}}>不计排名</div>}
            </div>}
        </div>
    );
};
export default RankLabelList;

火箭的设计

针对火箭位置因为是直接对应8种情况,所以其判断逻辑略有不同,是进行的一个类似策略模式的拼接得到其正确的样式名称即可。其中r1代表4个节点开始的四个图,r2代表5个节点时的四个图,然后根据其得到的排名进行相应的1和2的图即可。

import React from "react";
import { judgePrizeIndex, judgeIsCertain } from '../constant'
import './rocketProgress.scss'
const RocketProgress = props => {
   const { rank } = props

   const isCertain = judgeIsCertain(rank)
   const prizeIndex = judgePrizeIndex(rank)
   let rocketIndex  = ''
   if (isCertain) {
      rocketIndex = 'r1-'+prizeIndex
   } else { 
      rocketIndex = 'r2-'+prizeIndex
   }
   

   return <div className={'rocketProgress middle '+rocketIndex} id='rocketProgress'></div>



}
export default RocketProgress

得分以及奖品组件的设计

import React, { Component } from "react";
import { judgePrizeIndex, judgeIsCertain } from "../constant";
// import phoneImg from "../../../assets/images/phone.png";
import "./scorelist.scss";
/**
 * @description 分数列表
 */
class ScoreList extends Component{


    render() {
        const { scoreList, score, rank } = this.props;
        
        const isCertain = judgeIsCertain(rank);
        const prizeIndex = judgePrizeIndex(rank);
        const strUtil = (time) => {
            if (time > 9) {
                return time
            } else {
                return '0' + time
            }
        }
        const toStandTimeStr = (millseconds) => {
            if (!millseconds) {
                return
            }
            const diff = millseconds / 1000
            const hours = parseInt(diff / 3600)
            const mins = parseInt((diff - hours * 3600) / 60)
            const secs = diff - hours * 3600 - mins * 60
            return strUtil(hours) + ":" + strUtil(mins) + ":" + strUtil(secs)
        }
        const certainClass = (currentIndex, flag) => {
            let className = "item";
            if (isCertain) {
                className += " four";
                if (currentIndex === prizeIndex) {
                    className += " current";
                }
            } else {
                className += " five";
                if (currentIndex === prizeIndex && !flag) {
                    className += " current";
                }
            }
            return className;
        };
        return (
            <div className="right" id="scorelist">
                <div className={certainClass(1, true)}>
                    <img src={!certainClass(1, true).includes('current') ? '//static.aistarfish.com/front-release/file/F2020080710383285700006456.prize-phone-1.png' : '//static.aistarfish.com/front-release/file/F2020080710383286000000120.prize-phoe2.png'} alt="" className="prize-img" />
                    <span className="value phone">{scoreList[0] ? scoreList[0].score : '--'}</span>
                    <span className="score"></span>
                    <span className="time">{scoreList[0] ? scoreList[0].time : '--:--:--'}</span>
                    <span className='flag'>我的成绩</span>
                </div>
                {/* 中间的位置 66的红底缺图 */}
                {prizeIndex === 2 && !isCertain &&
                    <div className={certainClass(2, false)}>
                        <img src={!certainClass(2, false).includes('current') ? '//static.aistarfish.com/front-release/file/F2020080710533527700002186.66.png' : '//static.aistarfish.com/front-release/file/F2020080710533527700002186.66.png'} alt="" className="prize-img money" />
                        <span className="value">{score?.score}</span>
                        <span className="score"></span>
                        <span className="time">{toStandTimeStr(score?.duration)}</span>
                        <span className='flag'>我的成绩</span>
                    </div>}
                <div className={certainClass(2, true)}>
                    <img src={!certainClass(2, true).includes('current') ? '//static.aistarfish.com/front-release/file/F2020080711265619300004779.66-dark.png' : '//static.aistarfish.com/front-release/file/F2020080710533527700002186.66.png'} alt="" className="prize-img money" />
                    <span className="value">{scoreList[1] ? scoreList[1].score : '--'}</span>
                    <span className="score"></span>
                    <span className="time">{scoreList[1] ? scoreList[1].time : '--:--:--'}</span>
                    <span className='flag'>我的成绩</span>
                </div>
                {/* 中间的位置 */}
                {prizeIndex === 3 && !isCertain && (
                    <div className={certainClass(3, false)}>
                        <img src={!certainClass(1, true).includes('current') ? '//static.aistarfish.com/front-release/file/F2020080710533528000002839.16.png' : '//static.aistarfish.com/front-release/file/F2020080710533526900008129.16-2.png'} alt="" className="prize-img money" />
                        <span className="value">{score?.score}</span>
                        <span className="score"></span>
                        <span className="time">{toStandTimeStr(score?.duration)}</span>
                        <span className='flag'>我的成绩</span>
                    </div>
                )}
                <div className={certainClass(3, true)}>
                    <img src={certainClass(3, true).includes('current') ? '//static.aistarfish.com/front-release/file/F2020080710533528000002839.16.png' : '//static.aistarfish.com/front-release/file/F2020080710533526900008129.16-2.png'} alt="" className="prize-img money" />
                    <span className="value">{scoreList[2] ? scoreList[2].score : '--'}</span>
                    <span className="score"></span>
                    <span className="time">{scoreList[2] ? scoreList[2].time : '--:--:--'}</span>
                    <span className='flag'>我的成绩</span>
                </div>
                {/* 中间的位置 */}
                {prizeIndex === 4 && !isCertain && (
                    <div className={certainClass(4, false)}>
                        <img src={certainClass(4, false).includes('current') ? '//static.aistarfish.com/front-release/file/F2020080710533527100005234.6.png' : '//static.aistarfish.com/front-release/file/F2020080710533530600000032.6-2.png'} alt="" className="prize-img money" />
                        <span className="value">{score?.score}</span>
                        <span className="score"></span>
                        <span className="time">{toStandTimeStr(score?.duration)}</span>
                        <span className='flag'>我的成绩</span>
                    </div>
                )}
                <div className={certainClass(4, true)}>
                    <img src={certainClass(4, true).includes('current') ? '//static.aistarfish.com/front-release/file/F2020080710533527100005234.6.png' : '//static.aistarfish.com/front-release/file/F2020080710533530600000032.6-2.png'} alt="" className="prize-img  money" />
                    <span className="value">{scoreList[3] ? scoreList[3].score : '--'}</span>
                    <span className="score"></span>
                    <span className="time">{scoreList[3] ? scoreList[3].time : '--:--:--'}</span>
                    <span className='flag'>我的成绩</span>
                </div>
                {/* 最后的位置 肯定没有奖品 */}
                {prizeIndex === 5 && !isCertain && (
                    <div className={certainClass(5)}>
                        {/* 是否有成绩,有成绩展示成绩 ;没有成绩 展示无 ;  */}
                  
                        <img src={'//static.aistarfish.com/front-release/file/F2020081016411701700006037.theme-zqyn.png'} alt="" className="prize-img money" />
                        <span className="value">{score ? score.score : '0'}</span>
                        <span className="score"></span>
                        <span className="time">{score ? toStandTimeStr(score?.duration) : '00:00:00'}</span>
                        <span className='flag'>我的成绩</span>
                    </div>
                )}
            </div>
        );
    }
};

export default ScoreList;

小结

本文中最终采用的方案是提炼工具函数,然后在dom中直接提供其所有case,然后根据工具函数的返回结果来判断是否展示以及展示所需要的类以及数据。
在组件内部设计时,由于时间不足,每个item的部分代码存在冗余,可以在抽离为组件简化。

如果你有兴趣,也可以尝试直接工具函数计算出正确的list,在每个item中直接包含正确的所有条件。

欢迎关注我的语雀知识库,1000+技术文档小结,覆盖前端的各个知识面以及优质资源,并分享自己的工作日常所得。

原文链接:www.yuque.com/robinson/de…