You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用HTML/CSS和JavaScript实现带切换功能的右侧滑动菜单

滑动菜单实现方案

问题分析

你当前的代码缺少滑动菜单的核心实现:

  • 没有菜单触发按钮(如汉堡图标)
  • 没有给菜单容器设置滑入/滑出的CSS定位和过渡效果
  • 没有控制菜单显示/隐藏的JS切换逻辑

以下是完整的修改方案,保留你原有功能的同时实现右侧滑入菜单:


修改后的HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Taskboard</title>
    <link rel="stylesheet" href="/static/styling/home.css">
    <!-- 用Font Awesome汉堡图标,也可以用文字替代 -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
</head>
<body>
    <header>
        <nav>
            <h1>My New Taskboard</h1>
            <!-- 菜单触发按钮 -->
            <button id="menu-toggle" class="menu-toggle">
                <i class="fa-solid fa-bars"></i>
            </button>
            <!-- 滑动菜单容器 -->
            <div class="slide-menu">
                <ul>
                    <li><button id="update-button">Update</button></li>
                    <li><button id="edit-button">Edit</button></li>
                    <li><button id="open-button">Open</button></li>
                    <li><button id="new-button">New</button></li>
                    <li><button id="settings-button">Settings</button></li>
                </ul>
            </div>
        </nav>
    </header>
    <main>
        <section class="taskboard-grid" id="taskboard-grid">
            <!-- Task cards will be dynamically added here -->
        </section>

        <!-- Hidden form for creating a new taskboard -->
        <div id="new-taskboard-form" style="display: none;">
            <input type="text" id="new-taskboard-name" placeholder="Enter Taskboard Name">
            <input type="file" id="new-taskboard-file" accept=".xlsx">
            <button id="submit-new-taskboard">Create Taskboard</button>
        </div>
    </main>
    <script>
        // 菜单切换逻辑
        const menuToggle = document.getElementById('menu-toggle');
        const slideMenu = document.querySelector('.slide-menu');
        
        menuToggle.addEventListener('click', () => {
            slideMenu.classList.toggle('slide-menu-open');
        });

        // 保留原有业务逻辑
        document.getElementById('settings-button').addEventListener('click', function() {
            window.location.href = 'settings';
        });
        let currentTaskboard = null;

        document.getElementById('update-button').addEventListener('click', function() {
            if (!currentTaskboard) {
                alert('Please select a taskboard first.');
                return;
            }
        
            var fileInput = document.createElement('input');
            fileInput.type = 'file';
            fileInput.accept = '.xlsx';
        
            fileInput.addEventListener('change', function(event) {
                var file = event.target.files[0];
                var formData = new FormData();
                formData.append('file', file);
                formData.append('name', currentTaskboard);
        
                fetch('/upload/', {
                    method: 'POST',
                    body: formData
                })
                .then(response => response.json())
                .then(data => {
                    fetchTaskboardData(currentTaskboard);
                })
                .catch(error => {
                    console.error('Error:', error);
                });
            });
        
            fileInput.click();
        });

        document.getElementById('open-button').addEventListener('click', function() {
            fetch('/list/')
            .then(response => response.json())
            .then(taskboards => {
                showTaskboardSelector(Object.values(taskboards));
            })
            .catch(error => {
                console.error('Error fetching taskboards:', error);
            });
        });

        function showTaskboardSelector(taskboards) {
            var selector = document.createElement('select');
            selector.id = 'taskboard-selector';
            taskboards.forEach(taskboard => {
                var option = document.createElement('option');
                option.value = taskboard;
                option.textContent = taskboard;
                selector.appendChild(option);
            });

            document.body.appendChild(selector);

            selector.addEventListener('change', function() {
                currentTaskboard = this.value;
                fetchTaskboardData(currentTaskboard);
            });
        }

        function fetchTaskboardData(taskboardName) {
            fetch(`/get/?name=${encodeURIComponent(taskboardName)}`)
            .then(response => response.json())
            .then(data => {
                var taskboardGrid = document.getElementById('taskboard-grid');
                taskboardGrid.innerHTML = '';

                if (Array.isArray(data)) {
                    data.forEach(createCard);
                } else if (typeof data === 'object') {
                    Object.values(data).forEach(createCard);
                }
            })
            .catch(error => {
                console.error('Error fetching taskboard data:', error);
            });
        }

        function createCard(row) {
            var card = document.createElement('div');
            card.className = 'task-card';
            Object.keys(row).forEach(key => {
                if (row[key] !== null && row[key] !== undefined) {
                    var p = document.createElement('p');
                    p.textContent = `${key}: ${row[key]}`;
                    card.appendChild(p);
                }
            });
            document.getElementById('taskboard-grid').appendChild(card);
        }

        document.getElementById('edit-button').addEventListener('click', function() {
            if (!currentTaskboard) {
                alert('Please select a taskboard first.');
                return;
            }
            
            window.location.href = `/edit?name=${encodeURIComponent(currentTaskboard)}`;
        });
        
        document.getElementById('new-button').addEventListener('click', function() {
            document.getElementById('new-taskboard-form').style.display = 'block';
        });

        document.getElementById('submit-new-taskboard').addEventListener('click', function() {
            var taskboardName = document.getElementById('new-taskboard-name').value;
            var fileInput = document.getElementById('new-taskboard-file');
            var file = fileInput.files[0];

            if (!taskboardName || !file) {
                alert('Please enter a taskboard name and select a file.');
                return;
            }

            var formData = new FormData();
            formData.append('name', taskboardName);
            formData.append('file', file);

            fetch('/create', {
                method: 'POST',
                body: formData
            })
            .then(response => response.json())
            .then(data => {
                console.log('Taskboard created:', data);
                document.getElementById('new-taskboard-form').style.display = 'none';
                document.getElementById('new-taskboard-name').value = '';
                fileInput.value = '';
            })
            .catch(error => {
                console.error('Error:', error);
            });
        });

        document.addEventListener('DOMContentLoaded', function() {
            const urlParams = new URLSearchParams(window.location.search);
            const taskboardName = urlParams.get('name');
            if (taskboardName) {
                openTaskboard(taskboardName);
            }
        });
    
        function openTaskboard(taskboardName) {
            currentTaskboard = taskboardName;
            fetchTaskboardData(taskboardName);
        }
    </script>
</body>
</html>

修改后的CSS

body, html {
    height: 100%;
    margin: 0;
    font-family: Arial, sans-serif;
    background-color: #333;
    color: white;
    /* 防止菜单滑出时出现滚动条 */
    overflow-x: hidden;
}

header {
    background-color: #222;
    padding: 10px 20px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    /* 确保header在菜单上层 */
    position: relative;
    z-index: 100;
}

nav h1 {
    margin: 0;
}

/* 菜单触发按钮样式 */
.menu-toggle {
    background-color: #555;
    border: none;
    color: white;
    font-size: 20px;
    padding: 8px 12px;
    cursor: pointer;
    display: block;
}

.menu-toggle:hover {
    background-color: #666;
}

/* 滑动菜单容器 */
.slide-menu {
    position: fixed;
    top: 0;
    right: 0;
    width: 300px;
    height: 100vh;
    background-color: #222;
    padding: 70px 20px 20px;
    /* 默认完全滑出右侧 */
    transform: translateX(100%);
    /* 添加平滑过渡 */
    transition: transform 0.3s ease-in-out;
    z-index: 99;
}

/* 菜单展开状态 */
.slide-menu-open {
    transform: translateX(0);
}

.slide-menu ul {
    list-style: none;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 15px;
}

.slide-menu ul li button {
    background-color: #555;
    border: none;
    padding: 12px 20px;
    color: white;
    cursor: pointer;
    width: 100%;
    text-align: left;
}

.slide-menu ul li button:hover {
    background-color: #666;
}

/* 可选遮罩层,展开菜单时覆盖背景 */
.slide-menu-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0,0,0,0.5);
    z-index: 98;
    display: none;
}

.slide-menu-open + .slide-menu-overlay {
    display: block;
}

关键实现说明

  1. HTML结构调整:

    • 添加menu-toggle按钮作为菜单触发器
    • 将原按钮列表放入slide-menu容器
    • 可选添加遮罩层提升交互体验
  2. CSS核心逻辑:

    • 用position: fixed将菜单固定在右侧
    • 默认transform: translateX(100%)让菜单隐藏在视口外
    • 通过transition属性实现平滑滑入/滑出
    • 切换slide-menu-open类控制菜单显示状态
  3. JS逻辑:

    • 给触发按钮绑定点击事件,切换菜单展开类
    • 保留原有所有业务逻辑,不影响现有功能

内容的提问来源于stack exchange,提问作者FFFFFFFFF

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 18:55:54