源码及源码分析
<template>
<!-- 滚动菜单的主要容器 -->
<div class="scrolling-menu">
<!-- 如果headers数组有内容,就渲染表头 -->
<div
class="table-header"
v-if="headers.length"
:style="{ backgroundColor: headerBackground }"
>
<!-- 遍历表头的每一个项,并渲染 -->
<div
class="header-item"
v-for="(header, index) in headers"
:key="index"
:style="getHeaderStyle()"
>
{{ header }}
</div>
</div>
<!-- 表体部分,包含所有的表项 -->
<div class="table-body" ref="menuContainer">
<!-- 遍历当前展示的items,并渲染 -->
<div
class="menu-item"
v-for="(item, index) in displayedItems"
:key="index"
:style="getItemStyle(index)"
>
<!-- 根据配置的列,渲染每一列的数据 -->
<div
v-for="(field, colIndex) in columns"
:key="colIndex"
class="column-item"
style="color: aliceblue;"
:style="getColumnStyle()"
>
{{ formatItem(item, field) }}
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, watch, defineProps } from 'vue';
const props = defineProps({
data: {
type: Array, // 传入的数据数组
required: true, // 必须传入该数据
},
headers: {
type: Array, // 表头内容
default: () => [], // 如果没有传入,则为空数组
},
columns: {
type: Array, // 显示数据的列名
required: true, // 必须传入
},
rows: {
type: Number, // 显示的行数
default: 5, // 默认显示5行
},
scrollSpeed: {
type: Number, // 滚动速度,单位为毫秒
default: 3000, // 默认每隔3000ms滚动一次
},
itemFormatter: {
type: Function, // 自定义数据格式化函数
default: (item, field) => item[field]?.toString() || '', // 默认返回对应字段的值,如果不存在则为空字符串
},
rowHeight: {
type: String,
default: '20%', // 每行高度占父容器的20%,即5行平均分配
},
fontSize: {
type: String,
default: '16px', // 默认字体大小
},
textAlign: {
type: String,
default: 'center', // 默认文字居中对齐
},
headerBackground: {
type: String,
default: 'rgba(0, 0, 50, 0.5)', // 表头背景色
},
rowBackground: {
type: String,
default: 'rgba(0, 0, 50, 0.2)', // 行背景色
},
alternateRowBackground: {
type: String,
default: 'rgba(62, 62, 173, 0.2)', // 每隔一行的背景色
},
});
const menuContainer = ref(null); // 获取表体的引用
const displayedItems = ref([]); // 当前显示的行项
let interval = null; // 存储setInterval的引用,用于清除
let currentIndex = 0; // 当前滚动的起始索引
const startScrolling = () => {
// 开始自动滚动
interval = setInterval(() => {
currentIndex += props.rows; // 每次滚动显示rows数量的数据
if (currentIndex >= props.data.length) {
// 如果到达数据末尾,回到起始位置
currentIndex = 0;
}
updateDisplayedItems(); // 更新当前显示的项
}, props.scrollSpeed);
};
const updateDisplayedItems = () => {
// 更新显示的数据项,切片当前的rows个数据
displayedItems.value = props.data.slice(currentIndex, currentIndex + props.rows);
};
const formatItem = (item, field) => {
// 使用自定义的格式化函数,格式化每个数据项
return props.itemFormatter(item, field);
};
const getHeaderStyle = () => {
// 获取表头样式
return {
width: `${100 / props.columns.length}%`, // 宽度根据列的数量平分
fontSize: props.fontSize,
textAlign: props.textAlign,
};
};
const getItemStyle = (index) => {
// 获取每行的样式
return {
display: 'flex',
width: '100%',
height: props.rowHeight,
backgroundColor: index % 2 === 0 ? props.rowBackground : props.alternateRowBackground, // 根据行的索引决定背景颜色
};
};
const getColumnStyle = () => {
// 获取每列的样式
return {
width: `${100 / props.columns.length}%`, // 宽度根据列的数量平分
fontSize: props.fontSize,
textAlign: props.textAlign,
};
};
onMounted(() => {
// 组件挂载后,初始化显示的数据并开始滚动
updateDisplayedItems();
startScrolling();
});
onUnmounted(() => {
// 组件卸载前,清除滚动的定时器
clearInterval(interval);
});
watch(
() => props.data, // 监听数据变化
() => {
// 当数据变化时,重置索引并更新显示项
currentIndex = 0;
updateDisplayedItems();
}
);
</script>
<style scoped>
.scrolling-menu {
display: flex;
flex-direction: column; /* 使子元素垂直排列 */
overflow: hidden; /* 隐藏溢出的内容 */
width: 100%;
height: 100%;
}
.table-header {
display: flex;
padding: 10px;
font-weight: bold; /* 表头字体加粗 */
color: white;
}
.header-item {
text-align: center; /* 表头项居中对齐 */
}
.table-body {
display: flex;
flex-direction: column;
flex-grow: 1; /* 表体部分填充剩余空间 */
overflow: hidden; /* 隐藏溢出的内容 */
}
.menu-item {
display: flex;
align-items: center;
justify-content: space-between; /* 在行内的列之间均匀分布 */
box-sizing: border-box; /* 包括边框和内边距在内的大小计算方式 */
}
</style>
代码逻辑解析
Props定义: 组件接收多种参数用于自定义显示效果,比如 data (数据数组), headers (表头数组), columns (要显示的列), rows (显示的行数), scrollSpeed (滚动速度), 等等。这些参数让组件在不同的使用场景中保持灵活性。
Data定义: displayedItems 是一个 ref,用来存放当前显示的表项。menuContainer 是一个 ref,指向表体部分的 DOM 元素。
startScrolling函数: 通过 setInterval 实现自动滚动的效果,每隔 scrollSpeed 毫秒更新显示的项。当 currentIndex 达到数据长度的末尾时,会重置为 0,实现循环滚动。
updateDisplayedItems函数: 这个函数根据 currentIndex 来更新 displayedItems,只显示 rows 数量的数据。
getHeaderStyle函数和getItemStyle函数: 用来动态生成样式,确保组件的每一列和每一行都能根据传入的参数灵活调整。
生命周期钩子:
在 onMounted 中,组件加载后初始化显示的数据并开始滚动。
在 onUnmounted 中,组件卸载前清除定时器,防止内存泄漏。
数据监听: 使用 watch 监听 props.data,当数据发生变化时,重置索引并重新渲染显示项。
滚动菜单列表组件使用文档
目录
- 概述
- 安装
- 快速开始
- API 参考
- Props
- Slots
- Events
- 示例
- 常见问题
概述
滚动菜单列表组件是一个适用于大屏可视化项目的自定义组件。它支持自定义表格头部、多种数据格式、自动滚动显示数据,并具有高度的灵活性和可配置性。无论是单列数据还是多列数据,都可以通过简单配置快速展示,并且支持自定义样式以匹配不同的视觉风格。
安装
-
通过 npm 安装:
npm install vue-scroll-menu-list --save
-
通过 yarn 安装:
yarn add vue-scroll-menu-list
快速开始
在 Vue 项目中使用滚动菜单列表组件:
<template>
<ScrollMenuList
:data="menuData"
:headers="['项目名称', '漏洞数量', '严重等级']"
:columns="['name', 'count', 'severity']"
:rows="5"
:scrollSpeed="3000"
:itemFormatter="formatMenuItem"
rowHeight="19%"
fontSize="18px"
textAlign="center"
headerBackground="rgba(10, 10, 50, 0.7)"
rowBackground="rgba(0, 0, 50, 0.3)"
alternateRowBackground="rgba(62, 62, 173, 0.3)"
/>
</template>
<script>
import ScrollMenuList from 'vue-scroll-menu-list';
export default {
components: { ScrollMenuList },
data() {
return {
menuData: [
{ name: '项目A', count: 100, severity: '高' },
{ name: '项目B', count: 200, severity: '中' },
// 更多数据...
],
};
},
methods: {
formatMenuItem(item, field) {
return item[field] || '-';
}
}
};
</script>
API 参考
Props
Prop 名称 | 类型 | 默认值 | 说明 |
---|---|---|---|
data | Array | [] | 必需。要显示的数据列表。每个对象表示一行数据。 |
headers | Array | [] | 可选。表头名称列表。与 columns 对应,若为空则不显示表头。 |
columns | Array | [] | 必需。要显示的列名列表,定义每列对应的数据字段。 |
rows | Number | 5 | 显示的行数。默认为5。 |
scrollSpeed | Number | 3000 | 可选。自动滚动的速度,单位为毫秒。 |
itemFormatter | Function | `(item, field) => item[field]?.toString() | |
rowHeight | String | '20%' | 可选。每行的高度,支持百分比或像素值,默认为父容器高度的20%。 |
fontSize | String | '16px' | 可选。表格文字的大小。 |
textAlign | String | 'center' | 可选。文字对齐方式。可以是 'left' , 'center' , 'right' 。 |
headerBackground | String | 'rgba(0, 0, 50, 0.5)' | 可选。表头背景颜色。 |
rowBackground | String | 'rgba(0, 0, 50, 0.2)' | 可选。表格行的背景颜色。 |
alternateRowBackground | String | 'rgba(62, 62, 173, 0.2)' | 可选。表格隔行背景颜色。 |
示例
<template>
<ScrollMenuList
:data="menuData"
:headers="['项目名称', '漏洞数量', '严重等级']"
:columns="['name', 'count', 'severity']"
:rows="5"
:scrollSpeed="3000"
:itemFormatter="formatMenuItem"
rowHeight="19%"
fontSize="18px"
textAlign="center"
headerBackground="rgba(10, 10, 50, 0.7)"
rowBackground="rgba(0, 0, 50, 0.3)"
alternateRowBackground="rgba(62, 62, 173, 0.3)"
/>
</template>
<script>
export default {
data() {
return {
menuData: [
{ name: '项目A', count: 100, severity: '高' },
{ name: '项目B', count: 200, severity: '中' },
{ name: '项目C', count: 150, severity: '低' },
// 更多数据...
],
};
},
methods: {
formatMenuItem(item, field) {
return item[field] || '-';
}
}
};
</script>
常见问题
- 组件不滚动: 检查
scrollSpeed
是否设置过长或者数据量是否不足以触发滚动。 - 自定义样式未生效: 请确保传入的
props
符合组件要求,并且样式值合法。