|
|
@@ -1,385 +0,0 @@
|
|
|
-<!DOCTYPE html>
|
|
|
-<html>
|
|
|
-<head>
|
|
|
- <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
|
|
|
- <style>
|
|
|
- body {
|
|
|
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
|
- padding: 20px;
|
|
|
- background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
|
|
- min-height: 100vh;
|
|
|
- }
|
|
|
-
|
|
|
- #app {
|
|
|
- max-width: 1200px;
|
|
|
- margin: 0 auto;
|
|
|
- background-color: white;
|
|
|
- border-radius: 12px;
|
|
|
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
|
|
|
- padding: 25px;
|
|
|
- overflow: hidden;
|
|
|
- }
|
|
|
-
|
|
|
- h1 {
|
|
|
- text-align: center;
|
|
|
- color: #2c3e50;
|
|
|
- margin-bottom: 5px;
|
|
|
- }
|
|
|
-
|
|
|
- .description {
|
|
|
- text-align: center;
|
|
|
- color: #7f8c8d;
|
|
|
- margin-bottom: 25px;
|
|
|
- font-size: 0.95em;
|
|
|
- }
|
|
|
-
|
|
|
- .controls {
|
|
|
- display: flex;
|
|
|
- justify-content: center;
|
|
|
- gap: 15px;
|
|
|
- margin-bottom: 20px;
|
|
|
- flex-wrap: wrap;
|
|
|
- }
|
|
|
-
|
|
|
- button {
|
|
|
- padding: 10px 20px;
|
|
|
- background-color: #4CAF50;
|
|
|
- color: white;
|
|
|
- border: none;
|
|
|
- border-radius: 6px;
|
|
|
- cursor: pointer;
|
|
|
- font-weight: 600;
|
|
|
- transition: all 0.3s ease;
|
|
|
- }
|
|
|
-
|
|
|
- button:hover {
|
|
|
- background-color: #3d8b40;
|
|
|
- transform: translateY(-2px);
|
|
|
- }
|
|
|
-
|
|
|
- button:active {
|
|
|
- transform: translateY(0);
|
|
|
- }
|
|
|
-
|
|
|
- button.pause {
|
|
|
- background-color: #f39c12;
|
|
|
- }
|
|
|
-
|
|
|
- button.pause:hover {
|
|
|
- background-color: #d68910;
|
|
|
- }
|
|
|
-
|
|
|
- button.reset {
|
|
|
- background-color: #e74c3c;
|
|
|
- }
|
|
|
-
|
|
|
- button.reset:hover {
|
|
|
- background-color: #c0392b;
|
|
|
- }
|
|
|
-
|
|
|
- .table-container {
|
|
|
- max-height: 600px;
|
|
|
- overflow: hidden;
|
|
|
- position: relative;
|
|
|
- border-radius: 8px;
|
|
|
- border: 1px solid #ddd;
|
|
|
- }
|
|
|
-
|
|
|
- .scroll-message {
|
|
|
- position: absolute;
|
|
|
- top: 10px;
|
|
|
- right: 10px;
|
|
|
- background-color: #4CAF50;
|
|
|
- color: white;
|
|
|
- padding: 5px 10px;
|
|
|
- border-radius: 20px;
|
|
|
- font-size: 0.8em;
|
|
|
- z-index: 10;
|
|
|
- animation: pulse 2s infinite;
|
|
|
- }
|
|
|
-
|
|
|
- @keyframes pulse {
|
|
|
- 0% { opacity: 1; }
|
|
|
- 50% { opacity: 0.7; }
|
|
|
- 100% { opacity: 1; }
|
|
|
- }
|
|
|
-
|
|
|
- .table-wrapper {
|
|
|
- overflow: hidden;
|
|
|
- }
|
|
|
-
|
|
|
- .scrolling-table {
|
|
|
- animation: scrollUp 50s linear infinite;
|
|
|
- animation-play-state: running;
|
|
|
- }
|
|
|
-
|
|
|
- .scrolling-table.paused {
|
|
|
- animation-play-state: paused;
|
|
|
- }
|
|
|
-
|
|
|
- @keyframes scrollUp {
|
|
|
- 0% {
|
|
|
- transform: translateY(0);
|
|
|
- }
|
|
|
- 100% {
|
|
|
- transform: translateY(calc(-100% + 600px));
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- table {
|
|
|
- border-collapse: collapse;
|
|
|
- width: 100%;
|
|
|
- font-size: 0.95em;
|
|
|
- }
|
|
|
-
|
|
|
- th, td {
|
|
|
- border: 1px solid #e0e0e0;
|
|
|
- padding: 12px 15px;
|
|
|
- text-align: left;
|
|
|
- }
|
|
|
-
|
|
|
- th {
|
|
|
- background: #4CAF50;
|
|
|
- color: white;
|
|
|
- font-weight: 600;
|
|
|
- position: sticky;
|
|
|
- top: 0;
|
|
|
- z-index: 5;
|
|
|
- }
|
|
|
-
|
|
|
- .dept {
|
|
|
- background: #f0f8ff;
|
|
|
- font-weight: bold;
|
|
|
- color: #2c3e50;
|
|
|
- }
|
|
|
-
|
|
|
- tr:nth-child(even) {
|
|
|
- background-color: #f9f9f9;
|
|
|
- }
|
|
|
-
|
|
|
- tr:hover {
|
|
|
- background-color: #f1f8ff;
|
|
|
- }
|
|
|
-
|
|
|
- .footer {
|
|
|
- text-align: center;
|
|
|
- margin-top: 20px;
|
|
|
- color: #7f8c8d;
|
|
|
- font-size: 0.9em;
|
|
|
- }
|
|
|
-
|
|
|
- .counter {
|
|
|
- display: inline-block;
|
|
|
- background-color: #ecf0f1;
|
|
|
- padding: 5px 10px;
|
|
|
- border-radius: 4px;
|
|
|
- font-weight: bold;
|
|
|
- color: #2c3e50;
|
|
|
- }
|
|
|
- </style>
|
|
|
-</head>
|
|
|
-<body>
|
|
|
-<div id="app">
|
|
|
- <h1>部门员工信息表</h1>
|
|
|
- <p class="description">当数据超过15条时,表格会自动向上滚动。使用下方按钮控制滚动行为。</p>
|
|
|
-
|
|
|
- <div class="controls">
|
|
|
- <button @click="toggleScroll" :class="{pause: isPaused}">
|
|
|
- {{ isPaused ? '继续滚动' : '暂停滚动' }}
|
|
|
- </button>
|
|
|
- <button @click="resetScroll" class="reset">重置到顶部</button>
|
|
|
- <button @click="toggleSpeed">{{ speedLabel }}</button>
|
|
|
- <div class="counter">当前数据: {{ data.length }} 条</div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="table-container">
|
|
|
- <div v-if="shouldScroll" class="scroll-message">自动滚动中</div>
|
|
|
- <div class="table-wrapper">
|
|
|
- <table :class="['scrolling-table', {paused: isPaused}]" ref="table">
|
|
|
- <thead>
|
|
|
- <tr>
|
|
|
- <th>部门编号</th>
|
|
|
- <th>部门</th>
|
|
|
- <th>姓名</th>
|
|
|
- <th>职位</th>
|
|
|
- <th>薪资</th>
|
|
|
- </tr>
|
|
|
- </thead>
|
|
|
- <tbody>
|
|
|
- <template v-for="dept in data" :key="dept.id">
|
|
|
- <tr>
|
|
|
- <td class="dept" rowspan="2">{{dept.id}}</td>
|
|
|
- <td class="dept" rowspan="2">{{dept.name}}</td>
|
|
|
- <td>{{dept.emp1.name}}</td>
|
|
|
- <td>{{dept.emp1.position}}</td>
|
|
|
- <td>¥{{dept.emp1.salary.toLocaleString()}}</td>
|
|
|
- </tr>
|
|
|
- <tr>
|
|
|
- <td>{{dept.emp2.name}}</td>
|
|
|
- <td>{{dept.emp2.position}}</td>
|
|
|
- <td>¥{{dept.emp2.salary.toLocaleString()}}</td>
|
|
|
- </tr>
|
|
|
- </template>
|
|
|
- <!-- 添加重复数据以实现无缝滚动效果 -->
|
|
|
- <template v-if="shouldScroll" v-for="dept in data" :key="`repeat-${dept.id}`">
|
|
|
- <tr>
|
|
|
- <td class="dept" rowspan="2">{{dept.id}}</td>
|
|
|
- <td class="dept" rowspan="2">{{dept.name}}</td>
|
|
|
- <td>{{dept.emp1.name}}</td>
|
|
|
- <td>{{dept.emp1.position}}</td>
|
|
|
- <td>¥{{dept.emp1.salary.toLocaleString()}}</td>
|
|
|
- </tr>
|
|
|
- <tr>
|
|
|
- <td>{{dept.emp2.name}}</td>
|
|
|
- <td>{{dept.emp2.position}}</td>
|
|
|
- <td>¥{{dept.emp2.salary.toLocaleString()}}</td>
|
|
|
- </tr>
|
|
|
- </template>
|
|
|
- </tbody>
|
|
|
- </table>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="footer">
|
|
|
- <p>每行显示一个部门的两名员工信息 | 数据条数超过15条时自动滚动</p>
|
|
|
- </div>
|
|
|
-</div>
|
|
|
-
|
|
|
-<script>
|
|
|
- Vue.createApp({
|
|
|
- setup() {
|
|
|
- // 生成更多数据(超过15条)
|
|
|
- const generateData = () => {
|
|
|
- const departments = [
|
|
|
- {id:'D001', name:'技术部'},
|
|
|
- {id:'D002', name:'市场部'},
|
|
|
- {id:'D003', name:'人力资源部'},
|
|
|
- {id:'D004', name:'财务部'},
|
|
|
- {id:'D005', name:'销售部'},
|
|
|
- {id:'D006', name:'产品部'},
|
|
|
- {id:'D007', name:'设计部'},
|
|
|
- {id:'D008', name:'客服部'},
|
|
|
- {id:'D009', name:'研发部'},
|
|
|
- {id:'D010', name:'运营部'},
|
|
|
- {id:'D011', name:'质量部'},
|
|
|
- {id:'D012', name:'采购部'},
|
|
|
- {id:'D013', name:'行政部'},
|
|
|
- {id:'D014', name:'法务部'},
|
|
|
- {id:'D015', name:'公关部'},
|
|
|
- {id:'D016', name:'物流部'},
|
|
|
- {id:'D017', name:'工程部'},
|
|
|
- {id:'D018', name:'信息部'},
|
|
|
- {id:'D019', name:'培训部'},
|
|
|
- {id:'D020', name:'战略部'}
|
|
|
- ];
|
|
|
-
|
|
|
- const positions = [
|
|
|
- {title:'工程师', salaryRange:[8000, 15000]},
|
|
|
- {title:'高级工程师', salaryRange:[12000, 25000]},
|
|
|
- {title:'经理', salaryRange:[15000, 30000]},
|
|
|
- {title:'专员', salaryRange:[6000, 10000]},
|
|
|
- {title:'主管', salaryRange:[10000, 18000]},
|
|
|
- {title:'总监', salaryRange:[20000, 40000]},
|
|
|
- {title:'助理', salaryRange:[5000, 8000]},
|
|
|
- {title:'分析师', salaryRange:[9000, 16000]}
|
|
|
- ];
|
|
|
-
|
|
|
- const firstNames = ['张', '李', '王', '赵', '刘', '陈', '杨', '黄', '周', '吴', '郑', '孙', '马', '朱', '胡', '林', '郭', '何', '高', '罗'];
|
|
|
- const lastNames = ['伟', '芳', '娜', '敏', '静', '磊', '洋', '艳', '勇', '军', '霞', '强', '秀英', '文', '明', '华', '建国', '桂英', '亮', '玲'];
|
|
|
-
|
|
|
- const getRandomName = () => {
|
|
|
- const firstName = firstNames[Math.floor(Math.random() * firstNames.length)];
|
|
|
- const lastName = lastNames[Math.floor(Math.random() * lastNames.length)];
|
|
|
- return firstName + lastName;
|
|
|
- };
|
|
|
-
|
|
|
- const getRandomPosition = () => {
|
|
|
- return positions[Math.floor(Math.random() * positions.length)];
|
|
|
- };
|
|
|
-
|
|
|
- return departments.map(dept => {
|
|
|
- const pos1 = getRandomPosition();
|
|
|
- const pos2 = getRandomPosition();
|
|
|
-
|
|
|
- return {
|
|
|
- id: dept.id,
|
|
|
- name: dept.name,
|
|
|
- emp1: {
|
|
|
- name: getRandomName(),
|
|
|
- position: pos1.title,
|
|
|
- salary: Math.floor(Math.random() * (pos1.salaryRange[1] - pos1.salaryRange[0])) + pos1.salaryRange[0]
|
|
|
- },
|
|
|
- emp2: {
|
|
|
- name: getRandomName(),
|
|
|
- position: pos2.title,
|
|
|
- salary: Math.floor(Math.random() * (pos2.salaryRange[1] - pos2.salaryRange[0])) + pos2.salaryRange[0]
|
|
|
- }
|
|
|
- };
|
|
|
- });
|
|
|
- };
|
|
|
-
|
|
|
- const data = generateData();
|
|
|
- const shouldScroll = Vue.ref(data.length > 15);
|
|
|
- const isPaused = Vue.ref(false);
|
|
|
- const scrollSpeed = Vue.ref(50); // 动画时长,值越大滚动越慢
|
|
|
-
|
|
|
- const speedLabel = Vue.computed(() => {
|
|
|
- if (scrollSpeed.value === 30) return '快速滚动';
|
|
|
- if (scrollSpeed.value === 70) return '慢速滚动';
|
|
|
- return '中速滚动';
|
|
|
- });
|
|
|
-
|
|
|
- const toggleScroll = () => {
|
|
|
- isPaused.value = !isPaused.value;
|
|
|
- };
|
|
|
-
|
|
|
- const resetScroll = () => {
|
|
|
- const table = document.querySelector('.scrolling-table');
|
|
|
- if (table) {
|
|
|
- table.style.animation = 'none';
|
|
|
- setTimeout(() => {
|
|
|
- table.style.animation = `scrollUp ${scrollSpeed.value}s linear infinite`;
|
|
|
- table.style.animationPlayState = isPaused.value ? 'paused' : 'running';
|
|
|
- }, 10);
|
|
|
- }
|
|
|
- isPaused.value = false;
|
|
|
- };
|
|
|
-
|
|
|
- const toggleSpeed = () => {
|
|
|
- if (scrollSpeed.value === 50) {
|
|
|
- scrollSpeed.value = 30; // 快速
|
|
|
- } else if (scrollSpeed.value === 30) {
|
|
|
- scrollSpeed.value = 70; // 慢速
|
|
|
- } else {
|
|
|
- scrollSpeed.value = 50; // 中速
|
|
|
- }
|
|
|
-
|
|
|
- // 应用新的速度
|
|
|
- const table = document.querySelector('.scrolling-table');
|
|
|
- if (table) {
|
|
|
- table.style.animationDuration = `${scrollSpeed.value}s`;
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- // 动态更新动画时长
|
|
|
- Vue.onMounted(() => {
|
|
|
- const table = document.querySelector('.scrolling-table');
|
|
|
- if (table && shouldScroll.value) {
|
|
|
- table.style.animationDuration = `${scrollSpeed.value}s`;
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- return {
|
|
|
- data,
|
|
|
- shouldScroll,
|
|
|
- isPaused,
|
|
|
- speedLabel,
|
|
|
- toggleScroll,
|
|
|
- resetScroll,
|
|
|
- toggleSpeed
|
|
|
- };
|
|
|
- }
|
|
|
- }).mount('#app');
|
|
|
-</script>
|
|
|
-</body>
|
|
|
-</html>
|