前言
公司的商城小程序一直是开发几个周然后就停几个周。并且经由了多人开发,每个页面的样式也不统一。并且由于UI同学在figma上的UI图也不统一(比如有的间距是12px,有的间距是16px,但都是同样的卡片)。因此团队决定重构样式。
如何重构
主要是定义一系列的css变量。因为本项目没有使用任何css工具
css
:root,
page {
color: #333333;
--nutui-color-primary: #ffcf14;
/** 主要内容用色,常用语常规标题内容、细文浏览、常规按钮文字以及图表引导。*/
--nutui-gray-7: #333333;
/** 次要文字色,用于次级标题、属性标示、非主要信息引导等。*/
--nutui-black-10: #666666;
/** 不可操作内容色,用于预置内容、无效内容、特殊不可点击按钮、组件边框线等。*/
--nutui-gray-6: #cccccc;
/** 页面基底色,用于卡片式页面的兜底,永远置于页面最底层。*/
--nutui-gray-5: #f7f8fa;
/** 卡片内嵌背景色,用于卡片内部的信息包裹,感知较弱。*/
--nutui-gray-4: #f7f8fc;
/** 卡片背景色*/
--nutui-black-3: #ffffff;
/** 页面全局蒙层,用于弹出层、弹窗、新功能引导出现的整页遮罩*/
--nutui-gray-3: rgba(0, 0, 0, 0.7);
/** 局部蒙层,用于非整页遮罩*/
--nutui-gray-2: rgba(0, 0, 0, 0.4);
/** 间隔线/容错线,用于结构或信息分割*/
--nutui-black-2: rgba(0, 0, 0, 0.08);
/** 图片容错蒙层 */
--nutui-gray-1: rgba(0, 0, 0, 0.02);
/** 主题色 */
--tx-bg: #ffcf14;
/** 次主色 */
--tx-bg-secondary: #ae7466;
/** 浅主色 */
--tx-bg-light: #fff8e5;
/* 主文本浅颜色 */
--tx-text-primary-light: #E79600;
/** 主文本颜色 */
--tx-text: #333333;
/** 常规文本颜色 */
--tx-text-normal: #666666;
/** 次要文本颜色 */
--tx-text-secondary: #999999;
/** 不可操作内容颜色 */
--tx-text-disabled: #cccccc;
/** 页面背景色 */
--tx-bg-page: #f7f8fa;
/** 卡片背景色 */
--tx-bg-card: #ffffff;
/** 线条颜色 */
--tx-border: #eeeeee;
/** 价格红色 */
--tx-text-price: #ff4d4f;
/** 主/次按钮高度 */
--tx-button-height: 88rpx;
/** 主/次按钮字号 */
--tx-button-font-size: 32rpx;
/** 主/次按钮x内边距 */
--tx-button-padding-x: 64rpx;
/** 主/次按钮高度-小 */
--tx-button-height-small: 66rpx;
/** 主/次按钮字号-小 */
--tx-button-font-size-small: 28rpx;
/** 主/次按钮x内边距-小 */
--tx-button-padding-x-small: 40rpx;
/** 主/次按钮高度-极小 */
--tx-button-height-tiny: 48rpx;
/** 主/次按钮字号-极小 */
--tx-button-font-size-tiny: 24rpx;
/** 主/次按钮x内边距-极小 */
--tx-button-padding-x-tiny: 24rpx;
/** 按钮圆角 */
--tx-button-border-radius: 100rpx;
/** 幽灵按钮高度 */
--tx-ghost-button-height: 64rpx;
/** 幽灵按钮字号 */
--tx-ghost-button-font-size: 28rpx;
/** 极小间距 */
--tx-tiny-spacing: 8rpx;
/** 小间距 */
--tx-small-spacing: 16rpx;
/** 中间距 */
--tx-medium-spacing: 24rpx;
/** 标准间距 */
--tx-standard-spacing: 32rpx;
/** 大间距 */
--tx-large-spacing: 48rpx;
/** 卡片圆角 */
--tx-card-border-radius: 16rpx;
/** 标签圆角 */
--tx-label-border-radius: 4rpx;
/** 大标签圆角 */
--tx-large-label-border-radius: 16rpx;
/** 弹窗圆角 */
--tx-popup-border-radius: 24rpx;
/** 极大标题字号 */
--tx-xlarge-title-font-size: 48rpx;
/** 大标题字号 */
--tx-large-title-font-size: 40rpx;
/** 标准行高 */
--tx-standard-line-height: 1.4;
/** 小字行高 */
--tx-small-line-height: 1.2;
/** 模块标题字号 */
--tx-module-title-font-size: 32rpx;
/** 商品主标题字号 */
--tx-product-title-font-size: 28rpx;
/** 商品副文本字号 */
--tx-product-subtitle-font-size: 24rpx;
/** 极小标签字号 */
--tx-tiny-label-font-size: 20rpx;
/** 价格整数部分字号 */
--tx-price-integer-font-size: 36rpx;
/** 价格小数部分字号 */
--tx-price-decimal-font-size: 24rpx;
/** 积分数字小字号 */
--tx-code-font-size: 60rpx;
/** 积分数字小字号行高 */
--tx-code-line-height: 60rpx;
/** 积分数字大字号 */
--tx-code-font-size-large: 72rpx;
/** 积分数字大字号行高 */
--tx-code-line-height-large: 72rpx;
color: var(--tx-text-normal);
font-size: var(--tx-product-title-font-size);
line-height: var(--tx-standard-line-height);
}
/** @description 主题颜色 */
.bg-theme {
background-color: var(--tx-bg);
}
.bg-sub {
background-color: var(--tx-bg-light);
}
.bg-page {
background-color: var(--tx-bg-page);
}
.bg-card {
background-color: var(--tx-bg-card);
}
/** @description 线条颜色 */
.border-color {
border-color: var(--tx-border);
}
/** @description 文本颜色 */
.text-main {
color: var(--tx-text);
}
.text-normal {
color: var(--tx-text-normal);
}
.text-secondary {
color: var(--tx-text-secondary);
}
.text-disabled {
color: var(--tx-text-disabled);
}
.text-money {
color: var(--tx-text-price);
}
/** @description 间距 */
.mt {
margin-top: var(--tx-tiny-spacing);
}
.mb {
margin-bottom: var(--tx-tiny-spacing);
}
.ml {
margin-left: var(--tx-tiny-spacing);
}
.mr {
margin-right: var(--tx-tiny-spacing);
}
.mx {
margin-left: var(--tx-tiny-spacing);
margin-right: var(--tx-tiny-spacing);
}
.my {
margin-top: var(--tx-tiny-spacing);
margin-bottom: var(--tx-tiny-spacing);
}
.m {
margin: var(--tx-tiny-spacing);
}
.mt-2 {
margin-top: var(--tx-small-spacing);
}
.mb-2 {
margin-bottom: var(--tx-small-spacing);
}
.ml-2 {
margin-left: var(--tx-small-spacing);
}
.mr-2 {
margin-right: var(--tx-small-spacing);
}
.mx-2 {
margin-left: var(--tx-small-spacing);
margin-right: var(--tx-small-spacing);
}
.my-2 {
margin-top: var(--tx-small-spacing);
margin-bottom: var(--tx-small-spacing);
}
.m-2 {
margin: var(--tx-small-spacing);
}
.m-3 {
margin: var(--tx-medium-spacing);
}
/* 中间距 */
.mt-3 {
margin-top: var(--tx-medium-spacing);
}
.mb-3 {
margin-bottom: var(--tx-medium-spacing);
}
.ml-3 {
margin-left: var(--tx-medium-spacing);
}
.mr-3 {
margin-right: var(--tx-medium-spacing);
}
.mx-3 {
margin-left: var(--tx-medium-spacing);
margin-right: var(--tx-medium-spacing);
}
.my-3 {
margin-top: var(--tx-medium-spacing);
margin-bottom: var(--tx-medium-spacing);
}
/* 标准间距 */
.mt-4 {
margin-top: var(--tx-standard-spacing);
}
.mb-4 {
margin-bottom: var(--tx-standard-spacing);
}
.ml-4 {
margin-left: var(--tx-standard-spacing);
}
.mr-4 {
margin-right: var(--tx-standard-spacing);
}
.mx-4 {
margin-left: var(--tx-standard-spacing);
margin-right: var(--tx-standard-spacing);
}
.my-4 {
margin-top: var(--tx-standard-spacing);
margin-bottom: var(--tx-standard-spacing);
}
.m-4 {
margin: var(--tx-standard-spacing);
}
/* 大间距 */
.mt-big {
margin-top: var(--tx-large-spacing);
}
.mb-big {
margin-bottom: var(--tx-large-spacing);
}
.ml-big {
margin-left: var(--tx-large-spacing);
}
.mr-big {
margin-right: var(--tx-large-spacing);
}
.mx-big {
margin-left: var(--tx-large-spacing);
margin-right: var(--tx-large-spacing);
}
.my-big {
margin-top: var(--tx-large-spacing);
margin-bottom: var(--tx-large-spacing);
}
.m-big {
margin: var(--tx-large-spacing);
}
.pt-tiny {
padding-top: var(--tx-tiny-spacing);
}
.pb-tiny {
padding-bottom: var(--tx-tiny-spacing);
}
.pl-tiny {
padding-left: var(--tx-tiny-spacing);
}
.pr-tiny {
padding-right: var(--tx-tiny-spacing);
}
.px-tiny {
padding-left: var(--tx-tiny-spacing);
padding-right: var(--tx-tiny-spacing);
}
.py-tiny {
padding-top: var(--tx-tiny-spacing);
padding-bottom: var(--tx-tiny-spacing);
}
.p-tiny {
padding: var(--tx-tiny-spacing);
}
.pt-small {
padding-top: var(--tx-small-spacing);
}
.pb-small {
padding-bottom: var(--tx-small-spacing);
}
.pl-small {
padding-left: var(--tx-small-spacing);
}
.pr-small {
padding-right: var(--tx-small-spacing);
}
.px-small {
padding-left: var(--tx-small-spacing);
padding-right: var(--tx-small-spacing);
}
.py-small {
padding-top: var(--tx-small-spacing);
padding-bottom: var(--tx-small-spacing);
}
.p-small {
padding: var(--tx-small-spacing);
}
.pt-medium {
padding-top: var(--tx-medium-spacing);
}
.pb-medium {
padding-bottom: var(--tx-medium-spacing);
}
.pl-medium {
padding-left: var(--tx-medium-spacing);
}
.pr-medium {
padding-right: var(--tx-medium-spacing);
}
.px-medium {
padding-left: var(--tx-medium-spacing);
padding-right: var(--tx-medium-spacing);
}
.py-medium {
padding-top: var(--tx-medium-spacing);
padding-bottom: var(--tx-medium-spacing);
}
.p-medium {
padding: var(--tx-medium-spacing);
}
.pt-standard {
padding-top: var(--tx-standard-spacing);
}
.pb-standard {
padding-bottom: var(--tx-standard-spacing);
}
.pl-standard {
padding-left: var(--tx-standard-spacing);
}
.pr-standard {
padding-right: var(--tx-standard-spacing);
}
.px-standard {
padding-left: var(--tx-standard-spacing);
padding-right: var(--tx-standard-spacing);
}
.py-standard {
padding-top: var(--tx-standard-spacing);
padding-bottom: var(--tx-standard-spacing);
}
.p-standard {
padding: var(--tx-standard-spacing);
}
.pt-large {
padding-top: var(--tx-large-spacing);
}
.pb-large {
padding-bottom: var(--tx-large-spacing);
}
.pl-large {
padding-left: var(--tx-large-spacing);
}
.pr-large {
padding-right: var(--tx-large-spacing);
}
.px-large {
padding-left: var(--tx-large-spacing);
padding-right: var(--tx-large-spacing);
}
.py-large {
padding-top: var(--tx-large-spacing);
padding-bottom: var(--tx-large-spacing);
}
.p-large {
padding: var(--tx-large-spacing);
}
.p-card {
padding: var(--tx-medium-spacing);
}
.p-page {
margin: var(--tx-standard-spacing);
}
.ml-big {
margin-left: var(--tx-large-spacing);
}
.mr-big {
margin-right: var(--tx-large-spacing);
}
.mt-big {
margin-top: var(--tx-large-spacing);
}
.mb-big {
margin-bottom: var(--tx-large-spacing);
}
.mx-big {
margin-left: var(--tx-large-spacing);
margin-right: var(--tx-large-spacing);
}
.my-big {
margin-top: var(--tx-large-spacing);
margin-bottom: var(--tx-large-spacing);
}
/** @description 圆角 */
.radius-card {
border-radius: var(--tx-card-border-radius);
}
.radius-label {
border-radius: var(--tx-label-border-radius);
}
.radius-label-big {
border-radius: var(--tx-large-label-border-radius);
}
.radius-modal {
border-radius: var(--tx-popup-border-radius);
}
/** @description 字体大小 */
.text-h1 {
font-size: var(--tx-large-title-font-size);
line-height: var(--tx-standard-line-height);
font-weight: 500;
}
.text-h2 {
font-size: var(--tx-module-title-font-size);
line-height: var(--tx-standard-line-height);
font-weight: 500;
}
.text-title {
font-size: var(--tx-product-title-font-size);
line-height: var(--tx-standard-line-height);
font-weight: 400;
}
.text-tips {
font-size: var(--tx-product-subtitle-font-size);
line-height: var(--tx-standard-line-height);
font-weight: 400;
}
.text-mini {
font-size: var(--tx-tiny-label-font-size);
line-height: var(--tx-small-line-height);
font-weight: 400;
}
.text-price {
font-size: var(--tx-price-integer-font-size);
line-height: var(--tx-small-line-height);
font-weight: 600;
}
.text-price-sub {
font-size: var(--tx-price-decimal-font-size);
line-height: var(--tx-small-line-height);
font-weight: 600;
}
.text-code-number {
font-size: var(--tx-code-font-size);
line-height: var(--tx-code-line-height-large);
font-weight: 500;
}
.text-code-number-large {
font-size: var(--tx-code-font-size-large);
line-height: var(--tx-code-line-height);
font-weight: bold;
}
.gap {
gap: var(--tx-standard-spacing);
}
.gap-block {
gap: var(--tx-large-spacing);
}
.gap-card {
gap: var(--tx-small-spacing);
}
.gap-medium {
gap: var(--tx-medium-spacing);
}
.gap-tiny {
gap: var(--tx-tiny-spacing);
}
比如规定好,大按钮、小按钮、主要文本色、次要文本色、页面间距、卡片间距等等。
如何在把原来的替换掉统一起来。
像按钮这种,就封一个组件,根据props去生成样式
tsx
import { classNames } from '@/utils/Tool';
import { View } from '@tarojs/components';
import Taro from '@tarojs/taro';
import './index.scss';
export interface ITXButtonProps {
children?: React.ReactNode;
/** @param 是否占据整行 */
block?: boolean;
className?: string;
/** @param 是否禁用 */
disabled?: boolean;
/** @param 禁用时的提示文本 */
disabledText?: string;
/** @param 点击事件 */
onClick?: () => void;
/** @param 是否为大按钮 */
large?: boolean;
/** @param 是否为小按钮 */
small?: boolean;
/** @param 是否为极小按钮 */
tiny?: boolean;
/** @param 是否为主要按钮 */
theme?: boolean;
/** @param 是否为主要按钮-浅色 */
themeLight?: boolean;
}
export const TXButton = function TXButton_(props: ITXButtonProps) {
return (
<View
className={classNames({
'tx-button': true,
'tx-button-block': props.block,
small: props.small,
tiny: props.tiny,
large: props.large,
disabled: props.disabled,
theme: props.theme,
themeLight: props.themeLight,
[props.className || '']: true,
})}
onClick={() => {
if (props.disabled) {
if (props.disabledText) {
Taro.showToast({
title: props.disabledText,
icon: 'none',
duration: 700,
});
}
return;
}
props.onClick?.();
}}
>
{props.children}
</View>
);
};
css
.tx-button {
--bg: var(--tx-bg-page);
--color: var(--tx-text);
--border-radius: var(--tx-button-border-radius);
--height: var(--tx-button-height-small);
--font-size: var(--tx-button-font-size-small);
--padding-x: var(--tx-button-padding-x-small);
--font-weight: 400;
background-color: var(--bg);
color: var(--color);
border-radius: var(--border-radius);
height: var(--height);
font-size: var(--font-size);
font-weight: var(--font-weight);
padding: 0 var(--padding-x);
display: inline-flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
&.tx-button-block {
display: flex;
}
&.theme {
--bg: var(--tx-bg);
--color: var(--tx-text);
}
&.themeLight {
--color: var(--tx-text-primary-light);
--bg: var(--tx-bg-light);
}
&.large {
--height: var(--tx-button-height);
--font-size: var(--tx-button-font-size);
--padding-x: var(--tx-button-padding-x);
--font-weight: 700;
}
&.small {
--height: var(--tx-button-height-small);
--font-size: var(--tx-button-font-size-small);
--padding-x: var(--tx-button-padding-x-small);
}
&.tiny {
--height: var(--tx-button-height-tiny);
--font-size: var(--tx-button-font-size-tiny);
--padding-x: var(--tx-button-padding-x-tiny);
}
&.disabled {
--bg: var(--tx-border);
--color: var(--tx-text-secondary);
}
}
.nut-popup-bottom.nut-popup-round {
border-radius: var(--tx-popup-border-radius) var(--tx-popup-border-radius) 0 0 !important;
}
在使用时
tsx
<TXButton
large
theme
block
onClick={() => {
if (computed.loading) return;
logic.onSave();
}}
>
保存地址
</TXButton>