【可视化】封装滚动菜单列表组件

在这里插入图片描述
在这里插入图片描述

源码及源码分析


<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,当数据发生变化时,重置索引并重新渲染显示项。

滚动菜单列表组件使用文档


目录
  1. 概述
  2. 安装
  3. 快速开始
  4. API 参考
  5. 示例
  6. 常见问题

概述

滚动菜单列表组件是一个适用于大屏可视化项目的自定义组件。它支持自定义表格头部、多种数据格式、自动滚动显示数据,并具有高度的灵活性和可配置性。无论是单列数据还是多列数据,都可以通过简单配置快速展示,并且支持自定义样式以匹配不同的视觉风格。


安装

  1. 通过 npm 安装:

    npm install vue-scroll-menu-list --save
    
  2. 通过 yarn 安装:

    扫描二维码关注公众号,回复: 17439588 查看本文章
    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>

常见问题

  1. 组件不滚动: 检查 scrollSpeed 是否设置过长或者数据量是否不足以触发滚动。
  2. 自定义样式未生效: 请确保传入的 props 符合组件要求,并且样式值合法。

猜你喜欢

转载自blog.csdn.net/wanghaoyingand/article/details/141328084