目录
2.1.3 将 接口返回的字段名 转换为 可直接使用的污染物
1. 校验类方法
1.1 判断是否为数字
export const isNumeric = (val: string | number): val is string => typeof val === 'number' || /^\d+(\.\d+)?$/.test(val);
1.2 判断变量是否定义
export const isDef = <T>(val: T): val is NonNullable<T> => val !== undefined && val !== null;
2. 常见业务常量
2.1 污染物格式
2.1.1 html 标签封装的污染物
export const POLLUTION_HTML = [
{
name: 'O3',
html: 'O<small><sub>3</sub></small>',
},
{
name: 'PM10',
html: 'PM<small><sub>10</sub></small>',
},
{
name: 'PM25',
html: 'PM<small><sub>2.5</sub></small>',
},
{
name: 'SO2',
html: 'SO<small><sub>2</sub></small>',
},
{
name: 'SO3',
html: 'SO<small><sub>3</sub></small>',
},
{
name: 'CO',
html: 'CO',
},
{
name: 'CODMN',
html: 'COD<small><sub>mn</sub></small>',
},
{
name: 'VOCS',
html: 'VOC<small><sub>s</sub></small>',
},
{
name: 'NO',
html: 'NO',
},
{
name: 'NO2',
html: 'NO<small><sub>2</sub></small>',
},
{
name: 'NH3',
html: 'NH<small><sub>3</sub></small>',
},
{
name: 'NOX',
html: 'NO<small><sub>x</sub></small>',
},
{
name: 'NH4',
html: 'NH<small><sub>4</sub><sup>+</sup></small>',
},
{
name: 'MNO4',
html: 'MnO<small><sub>4</sub><sup>-</sup></small>',
},
{
name: 'PH',
html: 'pH',
},
];
2.1.2 echarts 图表中可以直接复制的污染物
export const POLLUTION_CHARTS = [
{
name: 'O3',
html: 'O₃',
},
{
name: 'PM10',
html: 'PM₁₀',
},
{
name: 'PM25',
html: 'PM₂.₅',
},
{
name: 'SO2',
html: 'SO₂',
},
{
name: 'SO3',
html: 'SO₃',
},
{
name: 'CO',
html: 'CO',
},
{
name: 'CODMN',
html: 'CODmn',
},
{
name: 'VOCS',
html: 'VOCs',
},
{
name: 'NO',
html: 'NO',
},
{
name: 'NO2',
html: 'NO₂',
},
{
name: 'NH3',
html: 'NH₃',
},
{
name: 'NOX',
html: 'NOx',
},
{
name: 'NH4',
html: 'NH₄⁺',
},
{
name: 'MNO4',
html: 'MnO₄¯',
},
{
name: 'PH',
html: 'pH',
},
];
2.1.3 将 接口返回的字段名 转换为 可直接使用的污染物
export const POLLUTION_CHARTS_ALL = [
{
name: ['O3', 'o3'],
html: 'O₃',
},
{
name: ['PM10', 'pm10'],
html: 'PM₁₀',
},
{
name: ['PM25', 'PM2_5', 'PM2.5', 'pm25', 'pm2_5', 'pm25'],
html: 'PM₂.₅',
},
{
name: ['SO2', 'so2'],
html: 'SO₂',
},
{
name: ['SO3', 'so3'],
html: 'SO₃',
},
{
name: ['CO2', 'co2'],
html: 'CO₂',
},
{
name: ['CODMN', 'codmn'],
html: 'CODmn',
},
{
name: ['VOCS', 'vocs'],
html: 'VOCs',
},
{
name: ['no'],
html: 'NO',
},
{
name: ['NO2', 'no2'],
html: 'NO₂',
},
{
name: ['NH3', 'nh3'],
html: 'NH₃',
},
{
name: ['NOX', 'nox'],
html: 'NOx',
},
{
name: ['NH4', 'nh4'],
html: 'NH₄⁺',
},
{
name: ['MNO4', 'mno4'],
html: 'MnO₄¯',
},
{
name: ['PH', 'ph'],
html: 'pH',
},
];
2.2 AQI 文字等级及对应颜色
// AQI 等级 1-6 级,7 为无数据时
export const AQI_TYPE = {
1: '优',
2: '良',
3: '轻度污染',
4: '中度污染',
5: '重度污染',
6: '严重污染',
7: '-',
};
// AQI 等级颜色 1-6 级,7 为无数据颜色
export const AQI_COLOR = {
1: '#05CE04',
2: '#FCFE03',
3: '#FF6600',
4: '#FE0000',
5: '#9820F4',
6: '#800000',
7: '#777',
};
2.3 Echarts 图默认选项
2.3.1 关于 Object.freeze
用 Object.freeze() 定义一个不可被修改的对象(冻结对象),被冻结的对象有以下特性:
- 不能添加新属性
- 不能删除已有属性
- 不能修改已有属性的值
- 不能修改原型
- 不能修改已有属性的可枚举性、可配置性、可写性
参考文章:
2.3.2 默认选项
export const DEFAULT_OPTIONS = Object.freeze({
color: [
'#2ec7c9',
'#b6a2de',
'#5ab1ef',
'#ffb980',
'#d87a80',
'#8d98b3',
'#e5cf0d',
'#97b552',
'#95706d',
'#dc69aa',
'#07a2a4',
'#9a7fd1',
'#588dd5',
'#f5994e',
'#c05050',
'#59678c',
'#c9ab00',
'#7eb00a',
'#6f5553',
'#c14089',
],
backgroundColor: 'rgba(0,0,0,0)',
textStyle: {},
title: {
show: false,
text: '标题',
padding: [5, 5, 5, 5],
left: 'left',
top: 'top',
textStyle: {
color: '#008acd',
},
subtextStyle: {
color: '#aaaaaa',
},
},
toolbox: {
iconStyle: {
borderColor: '#2ec7c9',
},
emphasis: {
iconStyle: {
borderColor: '#18a4a6',
},
},
},
legend: {
show: true,
padding: [10, 5, 5, 5],
textStyle: {
color: '#333333',
},
},
tooltip: {
trigger: 'axis',
axisPointer: {
lineStyle: {
color: '#008acd',
width: '1',
},
crossStyle: {
color: '#008acd',
width: '1',
},
},
},
markPoint: {
label: {
color: '#eeeeee',
},
emphasis: {
label: {
color: '#eeeeee',
},
},
},
valueAxis: {
axisLine: {
show: false,
},
axisTick: {
show: false,
},
axisLabel: {
show: true,
},
splitLine: {
show: false,
},
splitArea: {
show: false,
},
},
dataZoom: [
{
// 禁用缩放
disabled: true,
type: 'inside',
start: 0,
end: 100,
preventDefaultMouseMove: true,
},
{
// 隐藏滑块
show: false,
type: 'slider',
start: 0,
end: 100,
height: 12,
borderColor: 'transparent',
backgroundColor: '#f8f8f8',
dataBackground: {
lineStyle: {
width: 0,
},
areaStyle: {
color: 'transparent',
},
},
fillerColor: '#e1e1e1',
handleIcon: 'path://path://M100, 100m -75, 0a75,75 0 1,0 150,0a75,75 0 1,0 -150,0',
handleStyle: {
color: '#fff',
shadowColor: 'rgba(0, 0, 0, 0.2)',
shadowBlur: 4,
},
handleSize: '100%',
textStyle: {
color: '#888',
},
bottom: '10px',
},
],
});
2.3.3 X/Y坐标轴选项
export const DEFAULT_OPTIONS_AXIS = Object.freeze({
// X轴配置
xAxis: {
show: true,
name: '',
type: 'category',
nameTextStyle: {
align: 'left',
color: '#666',
fontSize: '12',
fontFamily: 'PF',
},
nameGap: 5,
boundaryGap: false,
axisLine: {
show: true,
lineStyle: {
color: '#cacaca',
width: 1,
type: 'solid',
},
},
axisTick: {
show: false,
lineStyle: {
color: '#333',
},
},
splitLine: {
show: false,
lineStyle: {
color: 'rgba(202,202,202,0.3)',
width: 1,
type: 'solid',
},
},
axisLabel: {
show: true,
rotate: 0,
color: '#666',
fontSize: '12',
fontFamily: 'PF',
margin: 10,
},
},
// y轴配置
yAxis: {
show: true,
name: '',
nameLocation: 'end',
type: 'value',
nameTextStyle: {
color: '#666',
fontSize: '12',
fontFamily: 'PF',
align: 'left',
padding: [0, 0, 7, -24],
},
nameGap: 10,
inverse: false,
boundaryGap: false,
splitNumber: 5,
axisLine: {
show: true,
lineStyle: {
color: '#cacaca',
width: 1,
type: 'solid',
},
},
axisTick: {
show: false,
},
splitLine: {
show: true,
lineStyle: {
color: 'rgba(202,202,202,0.3)',
width: 1,
type: 'solid',
},
},
axisLabel: {
show: true,
interval: 0,
rotate: 0,
color: '#666',
fontSize: '12',
fontFamily: 'PF',
formatter: '{value}',
align: 'right',
},
},
});
3. 工具方法
3.1 定义数据类型接口
export type MouseState = 'default' | 'hover' | 'focus' | 'active' | 'finish';
// 组件自定义样式
export interface ComponentCustomStyle {
// 组件最外层 必填
wrapper: SetInternalElementStyleOptions;
// 组件内部需要设置样式的元素 例如 icon button text 等
[n: string]: SetInternalElementStyleOptions;
}
// 设置组件内置元素样式
export interface SetInternalElementStyleOptions {
// 默认
default: CssProperty;
// 选中
active?: CssProperty;
// 滑过
hover?: CssProperty;
// 聚焦
focus?: CssProperty;
// 完成状态
finish?: CssProperty;
// 出错状态
error?: CssProperty;
// 禁用状态
disabled?: CssProperty;
// 禁用选中状态
disabledActive?: CssProperty;
}
// css 属性
export interface CssProperty {
[n: string]: string | number;
}
3.2 生成指定长度的随机字符串
/**
* @description: 随机字符串
* @param {*} pasLen 字符串长度
* @return {*}
*/
export const getRandomStr = (pasLen) => {
const pasArr = [
'a',
'b',
'c',
'd',
'e',
'f',
'g',
'h',
'i',
'j',
'k',
'l',
'm',
'n',
'o',
'p',
'q',
'r',
's',
't',
'u',
'v',
'w',
'x',
'y',
'z',
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z',
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
];
let pwdResult = '';
const pasArrLen = pasArr.length;
for (let i = 0; i < pasLen; i++) {
const x = Math.floor(Math.random() * pasArrLen);
pwdResult += pasArr[x];
}
return pwdResult;
};
3.3 将 css 样式对象转换为字符串
/**
* @description: 将css样式对象转换为字符串
* @param {CssProperty} CssProperty css样式对象
* @return {string} str
*/
export const getCssPropertyString = (cssProperty: CssProperty = {}) => {
let str = '';
Object.keys(cssProperty).forEach((key) => {
if (key && cssProperty) {
const cssPropertyName = key.replace(/([A-Z])/g, (match, p1) => `-${p1.toLowerCase()}`);
str += `${cssPropertyName}: ${cssProperty[key]};`;
}
});
return str;
};
3.4 生成元素的随机 class 名
/**
* @description: 获取元素随机class名称
* @param {string} classNamePrefix DOM节点class名前缀
* @return {*} 随机class
*/
export const getDomRandomClass = (classNamePrefix: string) => `${classNamePrefix}-${getRandomStr(16)}`;
3.5 根据 cStyle 设置元素样式
/**
* @description: 根据cStyle设置元素样式
* @param {SetInternalElementStyleOptions} cStyleItem 传入的样式cStyle
* @param {string} selectorString 样式选择器
* @returns {string} 整合好的样式
*/
export const setStyle = (
cStyleItem: SetInternalElementStyleOptions,
selectorString: string,
) => {
let innerHtml = '';
Object.keys(cStyleItem).forEach((key) => {
const state = key as MouseState;
// 过滤掉:active的伪类样式
if (state === 'active') {
return;
}
// 兼容selectorString为并集选择器时的css样式代码
const newSelectorString = selectorString
.split(',')
.map((singleSelector) => `${singleSelector}:${state}`)
.join(',');
innerHtml
+= state === 'default'
? `
${selectorString} {
${getCssPropertyString(cStyleItem[state])}
}
`
: `
${newSelectorString} {
${getCssPropertyString(cStyleItem[state])}
}
`;
});
return innerHtml;
};
3.6 添加单位
传入数字,则拼接为 px,传入字符串,则保留字符串
/**
* @description: 添加单位
* @param {string} value
* @return {*} 带单位数据
*/
export function addUnit(value?: string | number): string {
if (!isDef(value)) {
return '';
}
return isNumeric(value) ? `${value}px` : String(value);
}
3.7 过滤 attr 属性
/**
* @description: 过滤attr属性
* @param obj 需要过滤的对象
* @param customAttr 自定义需要过滤的属性名称
* @return 过滤后的对象
*/
export function filterAttrs(obj: any, customAttr: string[] = []) {
const resObj: any = {};
Object.keys(obj).forEach((key: string) => {
const keys = [
'data-id',
'id',
'cStyle',
'class',
'style',
'onClick',
'onDblclick',
'onMousedown',
'onMouseup',
'onMousemove',
'onMouseover',
'onMouseout',
'onMouseenter',
'onMouseleave',
'onAnimationstart',
'onAnimationend',
'onAnimationiteration',
'onTransitionend',
].concat(customAttr);
const include = keys.reduce((x: boolean, y: string) => x || key === y, false);
if (!include) {
resObj[key] = obj[key];
}
});
return resObj;
}
3.8 过滤元素样式
// 过滤样式定义
interface Style {
[propName: string]: any
}
/**
* 过滤元素样式
* @param styles 样式
*/
export const getStyle = (styles: Style) => {
const keys = [
'width',
'height',
'top',
'left',
'rotate',
'fontSize',
'marginTop',
'marginLeft',
'marginBottom',
'marginRight',
'paddingTop',
'paddingLeft',
'paddingBottom',
'paddingRight',
'lineHeight',
'textIndent',
'borderWidth',
'borderRadius',
'borderTopWidth',
'borderBottomWidth',
'borderLeftWidth',
'borderRightWidth',
'borderTopLeftRadius',
'borderTopRightRadius',
'borderBottomLeftRadius',
'borderBottomRightRadius',
];
const obj: Style = {};
if (styles) {
Object.keys(styles).forEach((key: string) => {
if (keys.includes(key) && typeof styles[key] !== 'string') {
let defaultValue = 0;
if (key === 'fontSize') {
defaultValue = 12;
}
if (key === 'width' || key === 'height') {
obj[key] = styles[key] ? `${styles[key]}px` : '';
} else {
obj[key] = `${styles[key] ? styles[key] : defaultValue}px`;
}
} else {
obj[key] = styles[key];
}
});
}
return obj;
};
3.9 颜色格式转换
/**
* 十六进制颜色转换rgb
* @param color 十六进制颜色
*/
export function colorRgb(color: string) {
let sColor = color.toLowerCase();
// 十六进制颜色值的正则表达式
const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
// 如果是16进制颜色
if (sColor && reg.test(sColor)) {
if (sColor.length === 4) {
let sColorNew = '#';
for (let i = 1; i < 4; i += 1) {
sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1));
}
sColor = sColorNew;
}
// 处理六位的颜色值
const sColorChange: number[] = [];
for (let i = 1; i < 7; i += 2) {
// eslint-disable-next-line radix
sColorChange.push(parseInt(`0x${sColor.slice(i, i + 2)}`));
}
return sColorChange.join(',');
}
return sColor;
}
/**
* @description 颜色转成rgba
* @param color #FFFFFF
* @param alp 透明度
* @returns rgba(0,0,0,alp)
*/
export const rgb2rgba = (color: string, alp = 1): string => {
if (color.indexOf('rgb') !== -1) {
return color;
}
let rgb = '255,255,255';
// 颜色码对照表
const colorMap = {
aliceblue: '#F0F8FF',
antiquewhite: '#FAEBD7',
aqua: '#00FFFF',
aquamarine: '#7FFFD4',
azure: '#F0FFFF',
beige: '#F5F5DC',
bisque: '#FFE4C4',
black: '#000000',
blanchedalmond: '#FFEBCD',
blue: '#0000FF',
blueviolet: '#8A2BE2',
brown: '#A52A2A',
burlywood: '#DEB887',
cadetblue: '#5F9EA0',
chartreuse: '#7FFF00',
chocolate: '#D2691E',
coral: '#FF7F50',
cornflowerblue: '#6495ED',
cornsilk: '#FFF8DC',
crimson: '#DC143C',
cyan: '#00FFFF',
darkblue: '#00008B',
darkcyan: '#008B8B',
darkgoldenrod: '#B8860B',
darkgray: '#A9A9A9',
darkgreen: '#006400',
darkkhaki: '#BDB76B',
darkmagenta: '#8B008B',
darkolivegreen: '#556B2F',
darkorange: '#FF8C00',
darkorchid: '#9932CC',
darkred: '#8B0000',
darksalmon: '#E9967A',
darkseagreen: '#8FBC8F',
darkslateblue: '#483D8B',
darkslategray: '#2F4F4F',
darkturquoise: '#00CED1',
darkviolet: '#9400D3',
deeppink: '#FF1493',
deepskyblue: '#00BFFF',
dimgray: '#696969',
dodgerblue: '#1E90FF',
firebrick: '#B22222',
floralwhite: '#FFFAF0',
forestgreen: '#228B22',
fuchsia: '#FF00FF',
gainsboro: '#DCDCDC',
ghostwhite: '#F8F8FF',
gold: '#FFD700',
goldenrod: '#DAA520',
gray: '#808080',
green: '#008000',
greenyellow: '#ADFF2F',
honeydew: '#F0FFF0',
hotpink: '#FF69B4',
indianred: '#CD5C5C',
indigo: '#4B0082',
ivory: '#FFFFF0',
khaki: '#F0E68C',
lavender: '#E6E6FA',
lavenderblush: '#FFF0F5',
lawngreen: '#7CFC00',
lemonchiffon: '#FFFACD',
lightblue: '#ADD8E6',
lightcoral: '#F08080',
lightcyan: '#E0FFFF',
lightgoldenrodyellow: '#FAFAD2',
lightgreen: '#90EE90',
lightgray: '#D3D3D3',
lightpink: '#FFB6C1',
lightsalmon: '#FFA07A',
lightseagreen: '#20B2AA',
lightskyblue: '#87CEFA',
lightslategray: '#778899',
lightsteelblue: '#B0C4DE',
lightyellow: '#FFFFE0',
lime: '#00FF00',
limegreen: '#32CD32',
linen: '#FAF0E6',
magenta: '#FF00FF',
maroon: '#800000',
mediumaquamarine: '#66CDAA',
mediumblue: '#0000CD',
mediumorchid: '#BA55D3',
mediumpurple: '#9370DB',
mediumseagreen: '#3CB371',
mediumslateblue: '#7B68EE',
mediumspringgreen: '#00FA9A',
mediumturquoise: '#48D1CC',
mediumvioletred: '#C71585',
midnightblue: '#191970',
mintcream: '#F5FFFA',
mistyrose: '#FFE4E1',
moccasin: '#FFE4B5',
navajowhite: '#FFDEAD',
navy: '#000080',
oldlace: '#FDF5E6',
olive: '#808000',
olivedrab: '#6B8E23',
orange: '#FFA500',
orangered: '#FF4500',
orchid: '#DA70D6',
palegoldenrod: '#EEE8AA',
palegreen: '#98FB98',
paleturquoise: '#AFEEEE',
palevioletred: '#DB7093',
papayawhip: '#FFEFD5',
peachpuff: '#FFDAB9',
peru: '#CD853F',
pink: '#FFC0CB',
plum: '#DDA0DD',
powderblue: '#B0E0E6',
purple: '#800080',
red: '#FF0000',
rosybrown: '#BC8F8F',
royalblue: '#4169E1',
saddlebrown: '#8B4513',
salmon: '#FA8072',
sandybrown: '#FAA460',
seagreen: '#2E8B57',
seashell: '#FFF5EE',
sienna: '#A0522D',
silver: '#C0C0C0',
skyblue: '#87CEEB',
slateblue: '#6A5ACD',
slategray: '#708090',
snow: '#FFFAFA',
springgreen: '#00FF7F',
steelblue: '#4682B4',
tan: '#D2B48C',
teal: '#008080',
thistle: '#D8BFD8',
tomato: '#FF6347',
turquoise: '#40E0D0',
violet: '#EE82EE',
wheat: '#F5DEB3',
white: '#FFFFFF',
whitesmoke: '#F5F5F5',
yellow: '#FFFF00',
yellowgreen: '#9ACD32',
};
const colorEncode = Object.keys(colorMap).find((item) => item === color.toLowerCase()); // 颜色码英文名
rgb = colorEncode ? colorRgb(colorMap[colorEncode]) : colorRgb(color); // rgb
return `rgba(${rgb},${alp})`;
};
3.10 将数组拆分成指定个数的分组数组
/**
* @description 将数组拆分
* @param arr 数组
* @param n 拆分组数
* @returns 分组的数组
*/
export const splitArray = (arr: unknown[], n = 1): unknown[] => {
if (!n) {
throw new Error(`error in params n: ${n}`);
}
const arrTemp: unknown[] = [...arr];
const every: number = Math.ceil(arrTemp.length / n) || 1;
const ret: unknown[] = [];
// eslint-disable-next-line no-constant-condition
while (true) {
const temp: unknown[] = arrTemp.splice(0, every);
if (!temp || temp.length === 0) {
break;
}
ret.push(temp);
}
return ret;
};
3.11 生成随机 uuid
export function getUuid(): string {
const s = [];
const hexDigits = '0123456789ABCDEF';
for (let i = 0; i < 32; i += 1) {
// @ts-ignore
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
const uuid = s.join('');
return uuid;
}
3.12 业务方法
3.12.1 获取 AQI 等级
/**
* 获取AQI值等级
* @param value aqi数值
* @returns number AQI等级1-6,7为无数据时
*/
export const getAQILevel = (value: any) => {
// 数据为null、undefined、NAN、空 无数据,等级7
if (value === null || value === undefined || Number.isNaN(Number(value)) || value === '') {
return 7;
}
const AQI = Number(value);
// 0-50 优 等级1
if (AQI <= 50 && AQI >= 0) {
return 1;
}
// 51-100 良 等级2
if (AQI > 50 && AQI <= 100) {
return 2;
}
// 101-150 轻度污染 等级3
if (AQI <= 150 && AQI > 100) {
return 3;
}
// 151-200 中度污染 等级4
if (AQI <= 200 && AQI > 150) {
return 4;
}
// 201-300 重度污染 等级5
if (AQI <= 300 && AQI > 200) {
return 5;
}
// 301- 严重污染 等级6
return 6;
};
3.12.2 获取污染物 html,不存在则原样返回
/**
* 获取污染物html,不存在则原样返回
* @param htmlArray 污染物名称对应上下标数组值
* @param name 污染物名称
* @return 污染物html
*/
export const getPollutionHtml = (
htmlArray: { [key: string]: string }[],
name: string = '',
): string => {
// 转大写字母,去除._等字符
const pollutionName: string = name.toUpperCase().replace(/[-.+_]/g, '');
const maped = htmlArray.filter((item) => item.name === pollutionName);
if (maped.length > 0) {
return maped[0].html;
}
return name;
};
3.12.3 替换一段字符串中所有污染物为正确格式
/**
* @description: 替换一段字符串中所有污染物为正确格式
* @param optionString 要替换的字符串
* @return 替换完的字符串
*/
export const replacePollutionHtml = (optionString: string): string => {
let curString = optionString;
POLLUTION_CHARTS_ALL.forEach((item) => {
item.name.forEach((name) => {
curString = curString.replace(name, item.html);
});
});
return curString;
};
4. 创建动态类名
4.1 BEM HELPER
此章节的方法 会根据 元素名、元素状态,来动态生成一个 BEM 风格的类名
假设根类名为 button,button 后会追加块元素、块元素状态,参考下方例子:
b() // 'button'
b('text') // 'button__text'
b({ disabled }) // 'button button--disabled'
b('text', { disabled }) // 'button__text button__text--disabled'
b(['disabled', 'primary']) // 'button button--disabled button--primary'
方法接收两个参数:
- 元素名:name - 字符串
- 元素状态:mods - 字符串、对象、数组
方法逻辑:
- 如果没接收元素状态,则不处理元素名
- 如果元素状态为字符串,则使用 -- 连接元素名及元素状态
- 如果元素状态为数组,则递归调用此方法,生成多个类名
- 如果元素状态为对象,则递归调用此方法,生成多个类名
export type Mod = string | { [key: string]: any };
export type Mods = Mod | Mod[];
/**
* @description: 动态创建class名称
* @param name 描述
* @param mods 状态
* @return 命名名称
*/
function genBem(name: string, mods?: Mods): string {
if (!mods) {
return '';
}
if (typeof mods === 'string') {
return ` ${name}--${mods}`;
}
if (Array.isArray(mods)) {
return mods.reduce<string>((ret, item) => ret + genBem(name, item), '');
}
return Object.keys(mods).reduce(
(ret, key) => ret + (mods[key] ? genBem(name, key) : ''),
'',
);
}
export function createBEM(name: string) {
return (el?: Mods, mods?: Mods): Mods => {
if (el && typeof el !== 'string') {
mods = el;
el = '';
}
el = el ? `${name}__${el}` : name;
return `${el}${genBem(el, mods)}`;
};
}
export type BEM = ReturnType<typeof createBEM>;
4.2 创建命名空间
/**
* @description: 创建命名空间
* @param name 名称
* @return 新名词
*/
export function createNamespace(name: string) {
const prefixedName = `t-${name}`;
return [createBEM(prefixedName)] as const;
}
5. 获取并设置 cookies 中的语言类型
import Cookies from 'js-cookie';
const CookieKeys = {
// 语言类型
LANGUAGE_KEY: 'language',
};
/**
* 获取语言类型
*/
export const getLanguage = () => Cookies.get(CookieKeys.LANGUAGE_KEY);
/**
* 设置语言类型
* @param language
*/
export const setLanguage = (language: string) => Cookies.set(CookieKeys.LANGUAGE_KEY, language);
6. 主题换肤处理
6.1 修改主题色及背景色
使用 setProperty 调整属性值
/**
* 修改主题色及背景色
* @param className
* @param themeColor
* @param backgroundColor
*/
export function changeThemeStyle(className: string, themeColor: string, backgroundColor: string) {
const themeElement: Array<HTMLElement> = Array.from(document.querySelectorAll(className));
if (themeElement && themeElement.length) {
themeElement.forEach((item: HTMLElement) => {
// 修改深浅主题元素的主题色
item.style.setProperty('--theme-color', themeColor);
// 修改深浅主题元素的背景色
item.style.setProperty('--background-color', backgroundColor);
});
}
}
6.2 设置颜色变量值
使用 setProperty 调整属性值
/**
* 设置颜色变量值
* @param className 元素类名
* @param variableName 变量名称
* @param value 变量值
*/
export function setColorVariable(className: string, variableName: string, value: string) {
const themeElement: Array<HTMLElement> = Array.from(document.querySelectorAll(className));
if (themeElement && themeElement.length) {
themeElement.forEach((item: HTMLElement) => {
// 修改变量值
item.style.setProperty(variableName, value);
});
}
}
6.3 修改主题风格下的颜色变量
提前内置 light、dark 两套主题
/**
* 修改主题风格下的颜色变量
*/
export function changeColorVariable() {
interface IThemeVariables {
[propName: string]: {
[propName: string]: string;
};
}
const variables: IThemeVariables = {
'.light': {
/* 主题色 默认为primary */
'--theme-color': 'var(--t-brand8)',
'--theme-color-opacity-10': 'rgba(0, 82, 217, 0.1)',
'--theme-color-opacity-15': 'rgba(0, 82, 217, 0.15)',
'--theme-color-opacity-30': 'rgba(0, 82, 217, 0.3)',
'--theme-color-opacity-60': 'rgba(0, 82, 217, 0.6)',
'--theme-color-opacity-80': 'rgba(0, 82, 217, 0.8)',
'--theme-color-opacity-90': 'rgba(0, 82, 217, 0.9)',
/* 颜色变量 */
'--t-font-color1': '#333',
'--t-font-color2': '#333',
'--t-font-color3': '#666',
'--t-font-color4': '#999',
'--t-border-color3': '#DEDEDE',
'--t-border-color2': '#D8D8D8',
'--t-border-color1': '#999',
'--t-background-color1': '#FFF',
'--t-background-color2': '#333',
'--t-background-color3': '#999',
'--t-background-color4': '#F3F3F3',
'--t-background-color': '#FFF',
'--t-background-color-dark': '#000050',
/** 菜单下划线颜色 * */
'--t-border-bottom-color': 'var(--theme-color)',
/** 菜单下划线颜色 * */
'--t-surface-background-color': 'var(--theme-color)',
/* 背景色 */
'--background-color': '#FFF',
'--background-color-dark': '#000050',
/* 基础字号 用于整体动态改变字号使用 */
'--base-font-size': '16px',
/* border-radius 用于整体动态改变border-radius使用 */
'--border-radius-base': '4px',
'--border-radius-small': '2px',
/* padding */
'--t-padding-md': '20px',
'--t-padding-xs': '10px',
},
'.dark': {
/* 主题色 默认为primary */
'--theme-color': '#0DE0E8',
'--theme-color-opacity-10': 'rgba(13, 224, 232, 0.1)',
'--theme-color-opacity-15': 'rgba(13, 224, 232, 0.15)',
'--theme-color-opacity-30': 'rgba(13, 224, 232, 0.3)',
'--theme-color-opacity-60': 'rgba(13, 224, 232, 0.6)',
'--theme-color-opacity-80': 'rgba(13, 224, 232, 0.8)',
'--theme-color-opacity-90': 'rgba(13, 224, 232, 0.9)',
/* 颜色变量 */
'--t-font-color1': '#333',
'--t-font-color2': '#333',
'--t-font-color3': '#666',
'--t-font-color4': '#999',
'--t-border-color3': '#DEDEDE',
'--t-border-color2': '#D8D8D8',
'--t-border-color1': '#999',
'--t-background-color1': '#FFF',
'--t-background-color2': '#333',
'--t-background-color3': '#999',
'--t-background-color4': '#F3F3F3',
'--t-background-color': '#FFF',
'--t-background-color-dark': '#000050',
/** 菜单下划线颜色 * */
'--t-border-bottom-color': 'var(--theme-color)',
/** 菜单下划线颜色 * */
'--t-surface-background-color': 'var(--theme-color)',
/* 背景色 */
'--background-color': '#FFF',
'--background-color-dark': '#000050',
/* 基础字号 用于整体动态改变字号使用 */
'--base-font-size': '16px',
/* border-radius 用于整体动态改变border-radius使用 */
'--border-radius-base': '4px',
'--border-radius-small': '2px',
/* padding */
'--t-padding-md': '20px',
'--t-padding-xs': '10px',
},
};
Object.keys(variables).forEach((key: string) => {
Object.keys(variables[key]).forEach((variableName: string) => {
setColorVariable(key, variableName, variables[key][variableName]);
});
});
}
6.4 设置主题及背景色、设置主题风格下的颜色变量
/**
* 设置主题色及背景色
*/
export function useSetThemeStyle() {
/**
* 设置主题色
*/
function setThemeStyle() {
changeThemeStyle('.dark', '#0de0e8', '#000050');
changeThemeStyle('.light', '#33B897', '#fff');
}
/**
* 设置主题风格下的颜色变量
*/
function setColorVariables() {
changeColorVariable();
}
return {
setThemeStyle,
setColorVariables,
};
}
6.5 将设置主题色及颜色变量的方法封装为 hooks
import { useSetThemeStyle } from './theme';
export default {
/**
* 初始化主题色及背景色
*/
mounted() {
const { setColorVariables } = useSetThemeStyle();
setColorVariables();
},
};