常规尺寸[满屏]

缩小尺寸[满屏]

放大尺寸[满屏]

缩小尺寸[非全屏]

放大尺寸[非全屏]

主要亮点:适配任意尺寸
围绕适配使用Autofit展开,项目介绍:
1. 项目基础结构
package.json - 项目依赖配8置
vite.config.js - Vite 构建配置
index.html - 入口 HTML 文件
src/main.js - Vue 应用入口
2. 自适应工具
src/utils/autofit.js - 屏幕自适应缩放工具类
3. 主大屏组件 (src/App.vue)
顶部标题栏(实时时间显示)
左侧面板:AI 类型分布饼图、实时使用趋势折线图
中间面板:总览数据卡片(总使用人数、今日新增、活跃用户、增长率)、地区分布热力图
右侧面板:AI 类型使用排行柱状图、使用时段分析面积图
底部滚动数据条
4. 图表组件
PieChart.vue - 饼图组件(环形图)
LineChart.vue - 折线图组件(多系列)
BarChart.vue - 柱状图组件(横向)
AreaChart.vue - 面积图组件
MapChart.vue - 地图散点图组件
5. 设计特点
深色主题,渐变背景
玻璃态效果(backdrop-filter)
响应式布局,自适应不同屏幕
实时数据更新(模拟)
动画效果和交互
6.其它
a. 页面包含header、footer以及main-content的左中右布局
b. 非全屏尺寸下,宽度100%,高度支持overflow滚动查阅内容
c. 在足够大的屏幕上自动铺满,在小屏幕上保持原始尺寸,支持滚动查看全部内容,窗口大小变化时自动适配
d. 可滚动条,隐藏滚动条占位,所有内容可见
代码- autofit.js 【自己手动搓的-下面还有应用官方autofit.js的示例】
/**
* autofit.js - 自适应屏幕缩放
*/
export default class Autofit {
constructor(options = {}) {
this.el = options.el || '#app'
this.dw = options.dw || 1920
this.dh = options.dh || 1080
this.resize = options.resize || true
this.delay = options.delay || 100
this.transition = options.transition || 0.3
this.init()
}
init() {
this.setScale()
if (this.resize) {
this.bindResize()
}
}
setScale() {
const target = document.querySelector(this.el)
if (!target) return
const w = window.innerWidth
const h = window.innerHeight
const scaleX = w / this.dw
const scaleY = h / this.dh
// 水平方向始终铺满(使用 scaleX),垂直方向根据缩放后的高度决定
// 计算水平缩放后的实际高度
const scaledHeight = this.dh * scaleX
const isHeightEnough = h >= scaledHeight
if (isHeightEnough) {
// 屏幕高度足够显示缩放后的内容,水平和垂直都铺满
const scale = Math.max(scaleX, scaleY)
target.style.transform = `scale(${scale})`
target.style.transformOrigin = 'top left'
target.style.width = `${this.dw}px`
target.style.height = `${this.dh}px`
target.style.position = 'fixed'
target.style.left = '0'
target.style.top = '0'
target.style.overflow = 'hidden'
target.style.transition = `transform ${this.transition}s`
} else {
// 屏幕高度不够时,水平铺满(scaleX),垂直保持原始高度并允许滚动
target.style.transform = `scaleX(${scaleX})`
target.style.transformOrigin = 'top left'
target.style.width = `${this.dw}px`
target.style.height = `${this.dh}px`
target.style.position = 'relative'
target.style.left = 'auto'
target.style.top = 'auto'
target.style.overflowX = 'hidden'
target.style.overflowY = 'auto'
// 移除过渡效果,避免滚动时出现动画
target.style.transition = 'none'
}
}
bindResize() {
let timer = null
window.addEventListener('resize', () => {
clearTimeout(timer)
timer = setTimeout(() => {
this.setScale()
}, this.delay)
})
}
destroy() {
window.removeEventListener('resize', this.setScale)
}
}
代码- index.html
全局样式部分需要关注,配合autofit的使用
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI类型使用人数统计大屏</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
width: 100%;
height: 100%;
overflow-x: hidden;
overflow-y: auto;
font-family: 'Microsoft YaHei', Arial, sans-serif;
/* 隐藏滚动条但保留滚动功能 */
scrollbar-width: none;
/* Firefox */
-ms-overflow-style: none;
/* IE 和 Edge */
}
/* 隐藏 Chrome、Safari 和 Opera 的滚动条 */
html::-webkit-scrollbar,
body::-webkit-scrollbar {
display: none;
}
#app {
width: 100%;
min-height: 100%;
overflow-x: hidden;
overflow-y: auto;
position: relative;
/* 隐藏滚动条但保留滚动功能 */
scrollbar-width: none;
/* Firefox */
-ms-overflow-style: none;
/* IE 和 Edge */
}
/* 隐藏 Chrome、Safari 和 Opera 的滚动条 */
#app::-webkit-scrollbar {
display: none;
}
</style>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
代码- 大屏界面index.vue
首页引用autofit.js
<template>
<div class="dashboard-container" ref="dashboardRef">
<!-- 顶部标题栏 -->
<div class="header">
<div class="title">
<h1>AI类型使用人数统计大屏</h1>
<div class="time">{{ currentTime }}</div>
</div>
</div>
<!-- 主要内容区域 -->
<div class="main-content">
<!-- 左侧区域 -->
<div class="left-panel">
<!-- AI类型分布饼图 -->
<div class="chart-box">
<div class="chart-title">
<span class="icon">📊</span>
<span>AI类型分布</span>
</div>
<PieChart :data="pieData" />
</div>
<!-- 实时使用趋势 -->
<div class="chart-box">
<div class="chart-title">
<span class="icon">📈</span>
<span>实时使用趋势</span>
</div>
<LineChart :data="lineData" />
</div>
</div>
<!-- 中间区域 -->
<div class="center-panel">
<!-- 总览数据 -->
<div class="overview-box">
<div class="stat-item">
<div class="stat-value">{{ totalUsers.toLocaleString() }}</div>
<div class="stat-label">总使用人数</div>
</div>
<div class="stat-item">
<div class="stat-value">{{ todayUsers.toLocaleString() }}</div>
<div class="stat-label">今日新增</div>
</div>
<div class="stat-item">
<div class="stat-value">{{ activeUsers.toLocaleString() }}</div>
<div class="stat-label">活跃用户</div>
</div>
<div class="stat-item">
<div class="stat-value">{{ growthRate }}%</div>
<div class="stat-label">增长率</div>
</div>
</div>
<!-- 地图热力图 -->
<div class="chart-box map-box">
<div class="chart-title">
<span class="icon">🌍</span>
<span>地区分布热力图</span>
</div>
<MapChart :data="mapData" />
</div>
</div>
<!-- 右侧区域 -->
<div class="right-panel">
<!-- 各类型使用人数排行 -->
<div class="chart-box">
<div class="chart-title">
<span class="icon">🏆</span>
<span>AI类型使用排行</span>
</div>
<BarChart :data="barData" />
</div>
<!-- 使用时段分析 -->
<div class="chart-box">
<div class="chart-title">
<span class="icon">⏰</span>
<span>使用时段分析</span>
</div>
<AreaChart :data="areaData" />
</div>
</div>
</div>
<!-- 底部滚动数据 -->
<div class="footer">
<div class="scroll-data">
<div
class="scroll-item"
v-for="(item, index) in scrollData"
:key="index"
>
<span class="ai-type">{{ item.type }}</span>
<span class="user-count">{{ item.count }}人</span>
<span class="region">{{ item.region }}</span>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, nextTick } from "vue";
import Autofit from "./utils/autofit.js";
import PieChart from "./components/PieChart.vue";
import LineChart from "./components/LineChart.vue";
import BarChart from "./components/BarChart.vue";
import AreaChart from "./components/AreaChart.vue";
import MapChart from "./components/MapChart.vue";
const dashboardRef = ref(null);
const currentTime = ref("");
const totalUsers = ref(125680);
const todayUsers = ref(3420);
const activeUsers = ref(8920);
const growthRate = ref(28.5);
// 饼图数据
const pieData = ref([
{ name: "ChatGPT", value: 45230 },
{ name: "Claude", value: 32150 },
{ name: "Midjourney", value: 28420 },
{ name: "Stable Diffusion", value: 19880 },
]);
// 折线图数据
const lineData = ref({
categories: ["00:00", "04:00", "08:00", "12:00", "16:00", "20:00"],
series: [
{
name: "ChatGPT",
data: [1200, 800, 3500, 6800, 5200, 4100],
},
{
name: "Claude",
data: [900, 600, 2800, 5500, 4200, 3300],
},
{
name: "Midjourney",
data: [700, 500, 2200, 4800, 3800, 2900],
},
],
});
// 柱状图数据
const barData = ref([
{ name: "ChatGPT", value: 45230, color: "#5470c6" },
{ name: "Claude", value: 32150, color: "#91cc75" },
{ name: "Midjourney", value: 28420, color: "#fac858" },
{ name: "Stable Diffusion", value: 19880, color: "#ee6666" },
{ name: "DALL-E", value: 15620, color: "#73c0de" },
{ name: "GPT-4", value: 12450, color: "#3ba272" },
]);
// 面积图数据
const areaData = ref({
categories: [
"0-2",
"2-4",
"4-6",
"6-8",
"8-10",
"10-12",
"12-14",
"14-16",
"16-18",
"18-20",
"20-22",
"22-24",
],
data: [1200, 800, 1500, 3200, 6800, 8500, 7200, 5800, 5200, 4800, 4100, 2800],
});
// 地图数据
const mapData = ref([
{ name: "北京", value: 15230 },
{ name: "上海", value: 14250 },
{ name: "广东", value: 18200 },
{ name: "浙江", value: 11200 },
{ name: "江苏", value: 9800 },
{ name: "四川", value: 7200 },
{ name: "湖北", value: 6500 },
{ name: "山东", value: 5800 },
]);
// 滚动数据
const scrollData = ref([
{ type: "ChatGPT", count: 45230, region: "北京" },
{ type: "Claude", count: 32150, region: "上海" },
{ type: "Midjourney", count: 28420, region: "广东" },
{ type: "Stable Diffusion", count: 19880, region: "浙江" },
{ type: "DALL-E", count: 15620, region: "江苏" },
{ type: "GPT-4", count: 12450, region: "四川" },
]);
let autofit = null;
let timeInterval = null;
let dataUpdateInterval = null;
// 更新时间
const updateTime = () => {
const now = new Date();
currentTime.value = now.toLocaleString("zh-CN", {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
});
};
// 模拟数据更新
const updateData = () => {
// 更新总用户数
totalUsers.value += Math.floor(Math.random() * 100);
todayUsers.value += Math.floor(Math.random() * 50);
activeUsers.value = Math.floor(totalUsers.value * 0.07);
// 更新折线图数据
lineData.value.series.forEach((series) => {
series.data = series.data.map(() => Math.floor(Math.random() * 8000));
});
};
onMounted(() => {
// 等待 DOM 渲染完成后再初始化 autofit
nextTick(() => {
// 初始化 autofit
autofit = new Autofit({
el: ".dashboard-container",
dw: 1920,
dh: 1080,
});
});
// 更新时间
updateTime();
timeInterval = setInterval(updateTime, 1000);
// 更新数据
dataUpdateInterval = setInterval(updateData, 5000);
});
onUnmounted(() => {
if (autofit) {
autofit.destroy();
}
if (timeInterval) {
clearInterval(timeInterval);
}
if (dataUpdateInterval) {
clearInterval(dataUpdateInterval);
}
});
</script>
<style scoped>
.dashboard-container {
width: 1920px;
height: 1080px;
background: linear-gradient(135deg, #0c1622 0%, #1a2332 50%, #0f1b2e 100%);
position: relative;
min-height: 1080px;
/* 宽度和 overflow 由 autofit.js 动态控制 */
/* 隐藏滚动条但保留滚动功能 */
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE 和 Edge */
}
/* 隐藏 Chrome、Safari 和 Opera 的滚动条 */
.dashboard-container::-webkit-scrollbar {
display: none;
}
.header {
height: 80px;
background: linear-gradient(
90deg,
rgba(21, 101, 192, 0.3) 0%,
rgba(13, 71, 161, 0.2) 100%
);
border-bottom: 2px solid rgba(33, 150, 243, 0.3);
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.title h1 {
font-size: 42px;
font-weight: bold;
background: linear-gradient(90deg, #2196f3, #00bcd4, #4dd0e1);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-align: center;
letter-spacing: 4px;
text-shadow: 0 0 20px rgba(33, 150, 243, 0.5);
}
.time {
position: absolute;
right: 40px;
top: 50%;
transform: translateY(-50%);
color: #00bcd4;
font-size: 20px;
font-weight: 500;
}
.main-content {
display: flex;
padding: 20px;
gap: 20px;
height: calc(100% - 160px);
}
.left-panel,
.right-panel {
flex: 1;
display: flex;
flex-direction: column;
gap: 20px;
}
.center-panel {
flex: 1.5;
display: flex;
flex-direction: column;
gap: 20px;
}
.chart-box {
background: rgba(15, 27, 46, 0.6);
border: 1px solid rgba(33, 150, 243, 0.3);
border-radius: 8px;
padding: 20px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
backdrop-filter: blur(10px);
flex: 1;
display: flex;
flex-direction: column;
}
.chart-title {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 15px;
font-size: 20px;
font-weight: 600;
color: #e3f2fd;
border-left: 4px solid #2196f3;
padding-left: 10px;
}
.chart-title .icon {
font-size: 24px;
}
.overview-box {
display: flex;
gap: 20px;
background: rgba(15, 27, 46, 0.6);
border: 1px solid rgba(33, 150, 243, 0.3);
border-radius: 8px;
padding: 30px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
backdrop-filter: blur(10px);
}
.stat-item {
flex: 1;
text-align: center;
padding: 20px;
background: rgba(33, 150, 243, 0.1);
border-radius: 8px;
border: 1px solid rgba(33, 150, 243, 0.2);
transition: all 0.3s;
}
.stat-item:hover {
background: rgba(33, 150, 243, 0.2);
transform: translateY(-5px);
box-shadow: 0 8px 25px rgba(33, 150, 243, 0.3);
}
.stat-value {
font-size: 36px;
font-weight: bold;
color: #00bcd4;
margin-bottom: 10px;
text-shadow: 0 0 10px rgba(0, 188, 212, 0.5);
}
.stat-label {
font-size: 16px;
color: #b0bec5;
}
.map-box {
flex: 1;
}
.footer {
height: 80px;
background: rgba(15, 27, 46, 0.8);
border-top: 2px solid rgba(33, 150, 243, 0.3);
overflow: hidden;
}
.scroll-data {
display: flex;
height: 100%;
align-items: center;
animation: scroll 30s linear infinite;
white-space: nowrap;
}
.scroll-item {
display: inline-flex;
align-items: center;
gap: 30px;
padding: 0 40px;
color: #e3f2fd;
font-size: 16px;
border-right: 1px solid rgba(33, 150, 243, 0.3);
}
.ai-type {
color: #00bcd4;
font-weight: 600;
}
.user-count {
color: #4caf50;
font-weight: 500;
}
.region {
color: #ff9800;
}
@keyframes scroll {
0% {
transform: translateX(0);
}
100% {
transform: translateX(-50%);
}
}
</style>
其它模块的代码在此就不提供了,需要源码,可私聊~
接下来,我们来看使用官方提供的autofit.js的示例
相关文档点击链接访问
安装autofit
npm i autofit.js@2.0.5
在需要的页面进行引入应用
import autofit from "autofit.js";
初始化
onMounted(() => {
// 等待 DOM 渲染完成后再初始化 autofit
nextTick(() => {
autofit.init({
el: ".dashboard-container",
dw: 1920,
dh: 1080,
resize: true,
ignore: [],
transition: 0.3,
delay: 100,
});
});
销毁
onUnmounted(() => {
// 销毁 autofit
autofit.off(".dashboard-container");
});
此处提供完整的index.vue文件,可对比示例一中的的手戳处理
<template>
<div class="dashboard-container" ref="dashboardRef">
<!-- 顶部标题栏 -->
<div class="header">
<div class="title">
<h1>AI类型使用人数统计大屏</h1>
<div class="time">{{ currentTime }}</div>
</div>
</div>
<!-- 主要内容区域 -->
<div class="main-content">
<!-- 左侧区域 -->
<div class="left-panel">
<!-- AI类型分布饼图 -->
<div class="chart-box">
<div class="chart-title">
<span class="icon">📊</span>
<span>AI类型分布</span>
</div>
<PieChart :data="pieData" />
</div>
<!-- 实时使用趋势 -->
<div class="chart-box">
<div class="chart-title">
<span class="icon">📈</span>
<span>实时使用趋势</span>
</div>
<LineChart :data="lineData" />
</div>
</div>
<!-- 中间区域 -->
<div class="center-panel">
<!-- 总览数据 -->
<div class="overview-box">
<div class="stat-item">
<div class="stat-value">{{ totalUsers.toLocaleString() }}</div>
<div class="stat-label">总使用人数</div>
</div>
<div class="stat-item">
<div class="stat-value">{{ todayUsers.toLocaleString() }}</div>
<div class="stat-label">今日新增</div>
</div>
<div class="stat-item">
<div class="stat-value">{{ activeUsers.toLocaleString() }}</div>
<div class="stat-label">活跃用户</div>
</div>
<div class="stat-item">
<div class="stat-value">{{ growthRate }}%</div>
<div class="stat-label">增长率</div>
</div>
</div>
<!-- 地图热力图 -->
<div class="chart-box map-box">
<div class="chart-title">
<span class="icon">🌍</span>
<span>地区分布热力图</span>
</div>
<MapChart :data="mapData" />
</div>
</div>
<!-- 右侧区域 -->
<div class="right-panel">
<!-- 各类型使用人数排行 -->
<div class="chart-box">
<div class="chart-title">
<span class="icon">🏆</span>
<span>AI类型使用排行</span>
</div>
<BarChart :data="barData" />
</div>
<!-- 使用时段分析 -->
<div class="chart-box">
<div class="chart-title">
<span class="icon">⏰</span>
<span>使用时段分析</span>
</div>
<AreaChart :data="areaData" />
</div>
</div>
</div>
<!-- 底部滚动数据 -->
<div class="footer">
<div class="scroll-data">
<div
class="scroll-item"
v-for="(item, index) in scrollData"
:key="index"
>
<span class="ai-type">{{ item.type }}</span>
<span class="user-count">{{ item.count }}人</span>
<span class="region">{{ item.region }}</span>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, nextTick } from "vue";
import PieChart from "../components/PieChart.vue";
import LineChart from "../components/LineChart.vue";
import BarChart from "../components/BarChart.vue";
import AreaChart from "../components/AreaChart.vue";
import MapChart from "../components/MapChart.vue";
import {
initialStats,
initialPieData,
initialLineData,
initialBarData,
initialAreaData,
initialMapData,
initialScrollData,
} from "../data/dashboard";
import type {
PieDataItem,
LineChartData,
BarDataItem,
AreaChartData,
MapDataItem,
ScrollDataItem,
} from "../types/chart";
import autofit from "autofit.js";
const dashboardRef = ref<HTMLDivElement | null>(null);
const currentTime = ref<string>("");
const totalUsers = ref<number>(initialStats.totalUsers);
const todayUsers = ref<number>(initialStats.todayUsers);
const activeUsers = ref<number>(initialStats.activeUsers);
const growthRate = ref<number>(initialStats.growthRate);
// 图表数据
const pieData = ref<PieDataItem[]>(initialPieData);
const lineData = ref<LineChartData>(initialLineData);
const barData = ref<BarDataItem[]>(initialBarData);
const areaData = ref<AreaChartData>(initialAreaData);
const mapData = ref<MapDataItem[]>(initialMapData);
const scrollData = ref<ScrollDataItem[]>(initialScrollData);
let timeInterval: ReturnType<typeof setInterval> | null = null;
let dataUpdateInterval: ReturnType<typeof setInterval> | null = null;
// 更新时间
const updateTime = (): void => {
const now = new Date();
currentTime.value = now.toLocaleString("zh-CN", {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
});
};
// 模拟数据更新
const updateData = (): void => {
// 更新总用户数
totalUsers.value += Math.floor(Math.random() * 100);
todayUsers.value += Math.floor(Math.random() * 50);
activeUsers.value = Math.floor(totalUsers.value * 0.07);
// 更新折线图数据
lineData.value.series.forEach((series) => {
series.data = series.data.map(() => Math.floor(Math.random() * 8000));
});
};
onMounted(() => {
// 等待 DOM 渲染完成后再初始化 autofit
nextTick(() => {
// // 初始化 autofit
// autofit = new Autofit({
// el: ".dashboard-container",
// dw: 1920,
// dh: 1080,
// });
autofit.init({
el: ".dashboard-container",
dw: 1920,
dh: 1080,
resize: true,
ignore: [],
transition: 0.3,
delay: 100,
});
});
// 更新时间
updateTime();
timeInterval = setInterval(updateTime, 1000);
// 更新数据
dataUpdateInterval = setInterval(updateData, 5000);
});
onUnmounted(() => {
// 销毁 autofit
autofit.off(".dashboard-container");
if (timeInterval) {
clearInterval(timeInterval);
}
if (dataUpdateInterval) {
clearInterval(dataUpdateInterval);
}
});
</script>
<style scoped>
.dashboard-container {
width: 1920px;
height: 1080px;
background: linear-gradient(135deg, #0c1622 0%, #1a2332 50%, #0f1b2e 100%);
position: relative;
min-height: 1080px;
/* 宽度和 overflow 由 autofit.js 动态控制 */
/* 隐藏滚动条但保留滚动功能 */
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE 和 Edge */
}
/* 隐藏 Chrome、Safari 和 Opera 的滚动条 */
.dashboard-container::-webkit-scrollbar {
display: none;
}
.header {
height: 80px;
background: linear-gradient(
90deg,
rgba(21, 101, 192, 0.3) 0%,
rgba(13, 71, 161, 0.2) 100%
);
border-bottom: 2px solid rgba(33, 150, 243, 0.3);
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.title h1 {
font-size: 42px;
font-weight: bold;
background: linear-gradient(90deg, #2196f3, #00bcd4, #4dd0e1);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-align: center;
letter-spacing: 4px;
text-shadow: 0 0 20px rgba(33, 150, 243, 0.5);
}
.time {
position: absolute;
right: 40px;
top: 50%;
transform: translateY(-50%);
color: #00bcd4;
font-size: 20px;
font-weight: 500;
}
.main-content {
display: flex;
padding: 20px;
gap: 20px;
height: calc(100% - 160px);
}
.left-panel,
.right-panel {
flex: 1;
display: flex;
flex-direction: column;
gap: 20px;
}
.center-panel {
flex: 1.5;
display: flex;
flex-direction: column;
gap: 20px;
}
.chart-box {
background: rgba(15, 27, 46, 0.6);
border: 1px solid rgba(33, 150, 243, 0.3);
border-radius: 8px;
padding: 20px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
backdrop-filter: blur(10px);
flex: 1;
display: flex;
flex-direction: column;
}
.chart-title {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 15px;
font-size: 20px;
font-weight: 600;
color: #e3f2fd;
border-left: 4px solid #2196f3;
padding-left: 10px;
}
.chart-title .icon {
font-size: 24px;
}
.overview-box {
display: flex;
gap: 20px;
background: rgba(15, 27, 46, 0.6);
border: 1px solid rgba(33, 150, 243, 0.3);
border-radius: 8px;
padding: 30px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
backdrop-filter: blur(10px);
}
.stat-item {
flex: 1;
text-align: center;
padding: 20px;
background: rgba(33, 150, 243, 0.1);
border-radius: 8px;
border: 1px solid rgba(33, 150, 243, 0.2);
transition: all 0.3s;
}
.stat-item:hover {
background: rgba(33, 150, 243, 0.2);
transform: translateY(-5px);
box-shadow: 0 8px 25px rgba(33, 150, 243, 0.3);
}
.stat-value {
font-size: 36px;
font-weight: bold;
color: #00bcd4;
margin-bottom: 10px;
text-shadow: 0 0 10px rgba(0, 188, 212, 0.5);
}
.stat-label {
font-size: 16px;
color: #b0bec5;
}
.map-box {
flex: 1;
}
.footer {
height: 80px;
background: rgba(15, 27, 46, 0.8);
border-top: 2px solid rgba(33, 150, 243, 0.3);
overflow: hidden;
}
.scroll-data {
display: flex;
height: 100%;
align-items: center;
animation: scroll 30s linear infinite;
white-space: nowrap;
}
.scroll-item {
display: inline-flex;
align-items: center;
gap: 30px;
padding: 0 40px;
color: #e3f2fd;
font-size: 16px;
border-right: 1px solid rgba(33, 150, 243, 0.3);
}
.ai-type {
color: #00bcd4;
font-weight: 600;
}
.user-count {
color: #4caf50;
font-weight: 500;
}
.region {
color: #ff9800;
}
@keyframes scroll {
0% {
transform: translateX(0);
}
100% {
transform: translateX(-50%);
}
}
</style>
非全屏尺寸

全屏尺寸

相对于示例一的手戳
有一下优势:
达到了真正的任意尺寸的自适应,无需设定滚动处理等问题。整体代码更加简洁、快捷!!!
继续手戳调整处理也可以实现,但有现成的直接用更香。如果需要定制化特殊处理的话,那还是示例一的手戳更容易去调整和适配。