代码优雅化进阶学习(二)

代码优雅化进阶学习(二)

实现一行个性化自定义样式文本

需求详情


实现以下的内容:

实现高亮效果
在这里插入图片描述

分析设计

难点

若只是实现以上内容,则很简单
但若从具体抽象到一般,则不容易

若要实现一般化,就需要抽象,寻找变与不变,封装变化,使变化的部分灵活,不变的部分稳定。所以需要考虑到以下几个方面:

  1. 如何抽象特殊文本的位置:特殊文本的位置是变化的,如何确定位置
  2. 如何抽象特殊文本的样式:特殊文本样式不仅仅是加粗,若未来需求变化,改为了其他特殊样式,该如何拓展
  3. 如何从业务需求中抽离出来,实现真正的一般化、抽象化

旧设计


设计详情:
将每一行文字分为 高亮文字前,高亮文字,高亮文字后 三种部分,若没有高亮文字,则就是 desc

在这里插入图片描述

优点

  • 抽象了特殊文字的位置
  • 可以实现样式的拓展,不只是可以实现高亮的效果

缺点

  1. 分得太细,这种数据设计导致后面实现连带变得复杂
  2. 命名不够抽象,不具有一般性和扩展性,若之后不是展示价格和折扣,则命名失去意义
  3. 将价格和折扣分开来抽象了,需要提取两者共性,将两者结合来具体抽象
  4. 抽象的还不够具体,还需再进一步抽象
  5. 没有从业务需求中抽离出来,单独来看,我们所需要实现的就是 一行文字中有些特殊文本

新设计

设计详情:

  • 抽离业务,就变成了一行文字中带有一部分特殊样式的文本
  • 文本样式可自定义
  • 文本位置可自定义

思路

思路1:占位符,通过占位符来替换文本(但是占位符的位置如何确定)


思路2:

  • 传入整行文本
  • 传入特殊样式的文本数组
  • 抽取共性,形成一个组件
  • 实现了更深一层的抽象
  • 注意抽象命名

实现

import React, { FC, ReactNode } from 'react';
export interface IAttributeTextProps extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement> {
    /**
     * 要展示的整个文本
     */
    content?: string;
    /**
     * 需要特殊样式的文本
     */
    attributes?: IAttributeInfo[];
}
export interface IAttributeInfo extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> {
    /**
     * 文本
     */
    text: string;
}

export const AttributeText: FC<IAttributeTextProps> = (props) => {
    const { content = '', attributes = [], ...resetProps } = props;

    return <div {...resetProps}>{getAttributeText(content, attributes)}</div>;
};

function getAttributeText(content: string, attributes: IAttributeInfo[]) {
    const cAttributes = [...attributes];
    if (!cAttributes.length) {
        return content;
    }
    let splitText = content;
    const attributeText: (ReactNode | string)[] = [];
    cAttributes.forEach((item, index) => {
        const { text, ...resetProps } = item;
        const textIndex = splitText.indexOf(text);
        const beforeText = splitText.substring(0, textIndex);
        if (beforeText) {
            attributeText.push(beforeText);
        }
        attributeText.push(
            <span key={index} {...resetProps}>
                {text}
            </span>
        );
        splitText = splitText.substring(textIndex + text.length);
        if (index === cAttributes.length - 1 && splitText) {
            attributeText.push(splitText);
        }
    });
    return attributeText;
}

使用方法

const medalDesc: IAttributeTextProps[] = [
    {
        content: '300元红包',
        attributes: [
            {
                text: '300',
                style: { fontWeight: '700' }
            }
        ]
    },

    {
        content: '优惠卷50元',
        attributes: [
            {
                text: '50',
                style:  { color: '#000' }
            }
        ]
    }
];


<div>
  {medalDesc.map((desc, idx) => (
      <AttributeText key={idx} {...desc} />
  ))}
</div>

前端小菜鸟进阶学习中,欢迎指正!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值