njzscloud-dispose-web/z-doc/颜色计算.html

465 lines
12 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>Element 风格颜色阶数计算器</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Microsoft Yahei", sans-serif;
}
body {
padding: 2rem;
background-color: #F5F7FA;
max-width: 1200px;
margin: 0 auto;
}
.container {
background: white;
padding: 2rem;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
}
.input-group {
margin-bottom: 2rem;
}
.input-row {
display: flex;
gap: 1rem;
margin-bottom: 1rem;
flex-wrap: wrap;
}
.input-item {
flex: 1;
min-width: 250px;
}
label {
display: block;
margin-bottom: 0.5rem;
font-weight: 600;
color: #333333;
}
#baseColor, #varPrefix {
width: 100%;
padding: 0.8rem;
border: 1px solid #DCDFE6;
border-radius: 4px;
font-size: 1rem;
outline: none;
}
#baseColor:focus, #varPrefix:focus {
border-color: #5D87FF;
}
.options {
display: flex;
align-items: center;
gap: 1rem;
margin: 1rem 0;
}
.checkbox-item {
display: flex;
align-items: center;
gap: 0.5rem;
}
button {
background-color: #5D87FF;
color: white;
border: none;
padding: 0.8rem 2rem;
border-radius: 4px;
font-size: 1rem;
cursor: pointer;
margin-right: 1rem;
}
button:hover {
background-color: #85A5FF;
}
.result-section {
margin-top: 2rem;
overflow-x: auto;
}
.color-row {
display: flex;
gap: 1rem;
flex-wrap: wrap;
}
.color-card {
display: flex;
flex-direction: column;
align-items: center;
padding: 1rem;
border-radius: 4px;
border: 1px solid #EEEEEE;
min-width: 120px;
cursor: pointer;
transition: all 0.2s;
}
.color-card:hover {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.color-swatch {
width: 80px;
height: 80px;
border-radius: 4px;
margin-bottom: 0.8rem;
border: 1px solid #DDDDDD;
}
.color-info {
text-align: center;
}
.color-name {
font-weight: 600;
margin-bottom: 0.3rem;
color: #333333;
font-size: 0.9rem;
}
.color-code {
color: #666666;
font-family: monospace;
font-size: 0.9rem;
}
.css-code {
margin-top: 2rem;
padding: 1rem;
background-color: #F8F9FA;
border-radius: 4px;
font-family: monospace;
white-space: pre-wrap;
word-wrap: break-word;
color: #333333;
border: 1px solid #EEEEEE;
position: relative;
}
.copy-btn {
position: absolute;
top: 1rem;
right: 1rem;
padding: 0.4rem 0.8rem;
font-size: 0.8rem;
background-color: #4CAF50;
border: none;
color: white;
border-radius: 4px;
cursor: pointer;
}
.copy-btn:hover {
background-color: #45A049;
}
.tooltip {
position: fixed;
padding: 0.5rem 1rem;
background-color: rgba(0, 0, 0, 0.8);
color: white;
border-radius: 4px;
font-size: 0.9rem;
z-index: 9999;
opacity: 0;
transition: opacity 0.2s;
pointer-events: none;
}
</style>
</head>
<body>
<div class="container">
<h1>Element 风格颜色阶数计算器</h1>
<div class="input-group">
<div class="input-row">
<div class="input-item">
<label for="baseColor">输入主色 HEX 值(如 #c93649、#FFCC55</label>
<input id="baseColor" placeholder="请输入带 # 的 HEX 色值,例如 #5D87FF" type="text" value="#D4A017">
</div>
<div class="input-item">
<label for="varPrefix">变量前缀(替代 primary</label>
<input id="varPrefix" placeholder="例如warning、danger、custom" type="text" value="warning">
</div>
</div>
<div class="options">
<div class="checkbox-item">
<input id="withHash" checked type="checkbox">
<label for="withHash">复制色值时包含 # 号</label>
</div>
</div>
<button onclick="calculateColorLevels()">计算色阶</button>
<button onclick="copyAllCss()">一键复制所有变量</button>
</div>
<div id="resultSection" class="result-section">
<!-- 色阶结果会动态生成 -->
</div>
<div id="cssCode" class="css-code">
<!-- CSS 代码会动态生成 -->
<button class="copy-btn" onclick="copyAllCss()">复制代码</button>
</div>
</div>
<!-- 复制提示弹窗 -->
<div id="tooltip" class="tooltip">复制成功!</div>
<script>
// 全局变量存储当前计算结果
let currentColorResults = {}
/**
* HEX 转 RGB
* @param {string} hex 带 # 的 HEX 色值
* @returns {object} r/g/b 数值0-255
*/
function hexToRgb(hex) {
hex = hex.replace(/^#/, '')
if (hex.length === 3) {
hex = hex.split('').map(c => c + c).join('')
}
const r = parseInt(hex.substring(0, 2), 16)
const g = parseInt(hex.substring(2, 4), 16)
const b = parseInt(hex.substring(4, 6), 16)
return { r, g, b }
}
/**
* RGB 转 HEX
* @param {number} r 红0-255
* @param {number} g 绿0-255
* @param {number} b 蓝0-255
* @returns {string} 带 # 的 HEX 色值
*/
function rgbToHex(r, g, b) {
r = Math.max(0, Math.min(255, Math.round(r)))
g = Math.max(0, Math.min(255, Math.round(g)))
b = Math.max(0, Math.min(255, Math.round(b)))
return '#' +
r.toString(16).padStart(2, '0') +
g.toString(16).padStart(2, '0') +
b.toString(16).padStart(2, '0')
}
/**
* 计算颜色亮度(相对亮度)
* @param {number} r 红0-255
* @param {number} g 绿0-255
* @param {number} b 蓝0-255
* @returns {number} 亮度值0-100
*/
function getLuminance(r, g, b) {
const a = [ r, g, b ].map(v => {
v /= 255
return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4)
})
return (a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722) * 100
}
/**
* 显示复制提示
* @param {string} text 提示文本
*/
function showTooltip(text) {
const tooltip = document.getElementById('tooltip')
tooltip.textContent = text
tooltip.style.opacity = 1
tooltip.style.left = (window.innerWidth / 2 - tooltip.offsetWidth / 2) + 'px'
tooltip.style.top = (window.innerHeight / 2) + 'px'
setTimeout(() => {
tooltip.style.opacity = 0
}, 1500)
}
/**
* 复制文本到剪贴板
* @param {string} text 要复制的文本
*/
function copyToClipboard(text) {
navigator.clipboard.writeText(text).then(() => {
showTooltip('复制成功!')
}).catch(err => {
showTooltip('复制失败:' + err)
})
}
/**
* 核心:计算 Element 风格的颜色阶数
*/
function calculateColorLevels() {
const baseHex = document.getElementById('baseColor').value.trim()
const varPrefix = document.getElementById('varPrefix').value.trim() || 'primary'
// 验证 HEX 格式
if (!/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/.test(baseHex)) {
alert('请输入有效的 HEX 色值,例如 #5D87FF 或 #fff')
return
}
const rgb = hexToRgb(baseHex)
const { r: r0, g: g0, b: b0 } = rgb
// 色阶调整参数
const levelConfig = {
'dark-2': { brightness: -0.18, saturation: 0.05 },
'light-3': { brightness: 0.10, saturation: -0.10 },
'light-5': { brightness: 0.20, saturation: -0.20 },
'light-7': { brightness: 0.30, saturation: -0.30 },
'light-8': { brightness: 0.35, saturation: -0.35 },
'light-9': { brightness: 0.40, saturation: -0.40 },
}
// 计算各阶颜色
currentColorResults = {
'主色': baseHex,
}
// 遍历计算每个阶数
Object.entries(levelConfig).forEach(([ level, config ]) => {
const newR = r0 + (255 - r0) * config.brightness
const newG = g0 + (255 - g0) * config.brightness
const newB = b0 + (255 - b0) * config.brightness
// 饱和度调整
const gray = (r0 + g0 + b0) / 3
const finalR = config.saturation > 0
? newR + (newR - gray) * config.saturation
: newR - (newR - gray) * Math.abs(config.saturation)
const finalG = config.saturation > 0
? newG + (newG - gray) * config.saturation
: newG - (newG - gray) * Math.abs(config.saturation)
const finalB = config.saturation > 0
? newB + (newB - gray) * config.saturation
: newB - (newB - gray) * Math.abs(config.saturation)
// 转 HEX 并保存
currentColorResults[level] = rgbToHex(finalR, finalG, finalB).toUpperCase()
})
// 渲染结果
renderResults(currentColorResults, varPrefix)
// 生成 CSS 代码
generateCssCode(currentColorResults, varPrefix)
}
/**
* 渲染颜色结果卡片(横向排列)
*/
function renderResults(results, varPrefix) {
const resultSection = document.getElementById('resultSection')
resultSection.innerHTML = ''
// 创建横向容器
const colorRow = document.createElement('div')
colorRow.className = 'color-row'
// 按固定顺序展示
const displayOrder = [ '主色', 'dark-2', 'light-3', 'light-5', 'light-7', 'light-8', 'light-9' ]
displayOrder.forEach(level => {
const hex = results[level]
const card = document.createElement('div')
card.className = 'color-card'
card.title = '点击复制色值'
// 颜色块
const swatch = document.createElement('div')
swatch.className = 'color-swatch'
swatch.style.backgroundColor = hex
// 颜色信息
const info = document.createElement('div')
info.className = 'color-info'
// 变量名
const varName = level === '主色'
? `--el-color-${varPrefix}`
: `--el-color-${varPrefix}-${level}`
info.innerHTML = `
<div class="color-name">${level}</div>
<div class="color-code" data-hex="${hex}">${hex}</div>
`
// 点击卡片复制色值
card.addEventListener('click', () => {
const withHash = document.getElementById('withHash').checked
const copyText = withHash ? hex : hex.replace(/^#/, '')
copyToClipboard(copyText)
})
card.appendChild(swatch)
card.appendChild(info)
colorRow.appendChild(card)
})
resultSection.appendChild(colorRow)
}
/**
* 生成 CSS 变量代码
*/
function generateCssCode(results, varPrefix) {
const cssCode = document.getElementById('cssCode')
const baseVar = `--el-color-${varPrefix}`
let css = `/* 基于 ${results['主色']} 的 Element 色阶配置 */\n`
css += `${baseVar}: ${results['主色']} !important;\n`
css += `${baseVar}-dark-2: ${results['dark-2']} !important;\n`
css += `${baseVar}-light-3: ${results['light-3']} !important;\n`
css += `${baseVar}-light-5: ${results['light-5']} !important;\n`
css += `${baseVar}-light-7: ${results['light-7']} !important;\n`
css += `${baseVar}-light-8: ${results['light-8']} !important;\n`
css += `${baseVar}-light-9: ${results['light-9']} !important;`
// 移除原有按钮,重新添加(避免重复)
cssCode.innerHTML = ''
const copyBtn = document.createElement('button')
copyBtn.className = 'copy-btn'
copyBtn.textContent = '复制代码'
copyBtn.onclick = copyAllCss
cssCode.appendChild(copyBtn)
cssCode.appendChild(document.createTextNode(css))
}
/**
* 一键复制所有 CSS 变量
*/
function copyAllCss() {
const cssCode = document.getElementById('cssCode')
// 排除按钮,只复制文本内容
const text = cssCode.textContent.replace('复制代码', '').trim()
copyToClipboard(text)
}
// 页面加载时默认计算一次
window.onload = calculateColorLevels
</script>
</body>
</html>