HTML5 拖拽 API 深度解析

在这里插入图片描述

一、HTML5 拖拽 API 深度解析

1.1 背景与发展

HTML5 的拖拽 API 是为了解决传统拖拽操作复杂而设计的。传统方法依赖鼠标事件和复杂的逻辑计算,而 HTML5 提供了标准化的拖拽事件和数据传递机制,使得开发者能够快速实现从一个元素拖拽到另一个元素的交互。

1.2 拖拽 API 的核心工作原理

HTML5 拖拽 API 的核心包括以下几个步骤:

  1. 定义可拖拽元素
    设置 HTML 元素的 draggable 属性为 true

    <div id="drag-item" draggable="true">可拖拽元素</div>
    
  2. 处理拖拽事件
    拖拽相关事件包括:

    • dragstart:拖拽开始。
    • drag:拖拽中(可用于实时显示位置)。
    • dragend:拖拽结束。
    • dragover:目标区域悬停。
    • drop:放置到目标区域。
  3. 数据传递机制
    使用 dataTransfer 对象存储拖拽时传递的数据:

    event.dataTransfer.setData("text/plain", event.target.id);
    

1.3 dataTransfer 对象详解

dataTransfer 是 HTML5 拖拽 API 的核心对象,用于在拖拽操作中传递数据。常用方法包括:

  • setData(format, data):设置数据。
  • getData(format):获取数据。
  • clearData():清除数据。

示例:

function dragStart(event) {
    event.dataTransfer.setData("text/plain", event.target.id);
}

二、需求分析

2.1 用户场景与功能拆解

实现一个课程表的核心目标是简化用户的课程安排操作,同时提供良好的交互体验。为了实现这些目标,我们需要从多个角度拆解用户的场景和功能需求。

2.1.1 用户场景
  1. 学生场景
    • 学生可以根据自己的课程需求,自由安排每周的课程表。例如,用户可以将数学课安排在周一上午 9 点,并在拖拽过程中动态调整课程顺序。
    • 用户希望避免时间冲突,例如将两个课程拖到同一时间段,系统应该给出明确的提示,并阻止冲突安排。
    • 需要课程表的持久化功能,用户希望安排好的课程表能在下次打开页面时自动加载,而不需要重新编辑。
  2. 教师场景
    • 教师可以拖动课程安排授课时间,避免重复调整。
    • 支持批量拖动课程,例如一门课分为多个时间段,可以快速将课程拖放到多个时间段中。
    • 教师需要避免误操作,例如误将课程拖到错误时间段的功能需要撤销或调整。
  3. 管理员场景
    • 课程管理员可以通过后台数据动态生成课程表,支持根据学生或教师的需求提供个性化课程安排模板。
    • 拖拽交互需要支持多角色数据权限控制。例如,管理员可能需要调整多个学生的课程安排,但不能修改教师的授课时间。
2.1.2 功能拆解

为了满足上述用户场景,我们可以将课程表的功能需求拆解如下:

  1. 基础功能:拖拽课程到时间段
    • 课程表需要左侧提供可拖拽的课程元素。
    • 时间表按天和时间段分为多个区域,允许用户将课程拖拽到指定时间段中。
    • 拖拽时提供即时的视觉反馈,例如高亮显示拖拽目标区域。
  2. 冲突检测与提示
    • 在同一时间段只能安排一门课程,如果用户尝试将多个课程拖入同一时间段,系统应实时检测冲突,并通过提示框、警告样式或动画效果提醒用户。
    • 课程安排冲突时,课程返回初始位置,不影响其他已安排的课程。
  3. 数据持久化
    • 使用 localStorage 或后端 API 保存用户的课程安排。用户关闭页面后再次打开时,可以加载之前的安排。
    • 支持导出课程表为 JSON 格式,便于与后端系统对接。
  4. 撤销与重置
    • 用户可以撤销最近一次操作,将课程恢复到拖拽前的位置。
    • 提供一键重置功能,清空当前所有课程安排。
  5. 扩展功能
    • 支持移动端操作,例如触摸屏拖拽课程到时间段。
    • 多用户支持,允许不同用户登录后加载属于自己的课程表。
    • 添加课程备注功能,用户可以为每门课程添加备注信息,例如课室、教师等。

2.2 课程表的交互设计

2.2.1 界面布局
  1. 左侧课程列表
    • 左侧为垂直排列的课程列表,包含所有可供拖拽的课程。每个课程元素以方块形式显示课程名称,颜色区分课程类型(例如数学为蓝色,英语为绿色)。
    • 列表支持滚动,便于在大量课程中快速找到目标课程。
  2. 右侧时间表
    • 时间表按周展示,分为多个天(如周一至周五)。每一天分为固定的时间段(如上午、下午、晚上)。
    • 每个时间段是一个可拖拽的目标区域,当用户拖拽课程到该区域时,显示高亮边框。
    • 时间段内显示当前安排的课程。如果没有课程,显示占位文本(例如“拖拽课程到此处”)。
2.2.2 视觉反馈设计
  1. 拖拽反馈
    • 当用户开始拖拽课程时,课程元素变为半透明状态,表示该课程已被选中。
    • 鼠标移动到目标时间段时,时间段高亮显示,表示可以放置课程。
  2. 冲突提示
    • 如果拖拽课程到已被占用的时间段,时间段边框变为红色,显示错误提示“时间冲突”。
    • 放置失败时,课程返回到原位置,并弹出警告提示。
  3. 保存状态提示
    • 用户点击保存按钮后,显示“保存成功”提示,并在页面顶部显示保存时间。
2.2.3 用户操作流程

以下是典型的用户交互流程:

  1. 用户浏览左侧课程列表,选择需要安排的课程(例如“数学”)。
  2. 拖动课程到右侧时间表的目标时间段(如周一上午 9 点)。
    • 如果时间段为空,课程成功放置。
    • 如果时间段已被占用,课程返回到原位置,并显示冲突提示。
  3. 用户点击“保存”按钮,将当前课程安排保存到本地或后端。
  4. 刷新页面后,课程表根据保存的数据自动加载。

2.2.4 交互案例分析

以下为几个典型交互案例及其逻辑设计:

  1. 成功放置课程
    • 场景:用户将“数学”课程拖动到周一上午 9 点,时间段为空。
    • 预期行为:
      • 时间段接收“数学”课程,课程从左侧列表消失。
      • 课程表更新,显示“数学”课程。
  2. 时间冲突
    • 场景:用户尝试将“英语”课程拖动到已被“数学”课程占用的时间段。
    • 预期行为:
      • 显示冲突提示,时间段边框变为红色。
      • 课程返回原位置,用户需要重新选择时间段。
  3. 保存并恢复
    • 场景:用户完成课程安排后,点击“保存”按钮。
    • 预期行为:
      • 数据保存到 localStorage 或后端。
      • 用户刷新页面后,课程表自动加载之前保存的内容。

2.2.5 功能模块化设计

为确保代码结构清晰,我们将课程表功能划分为以下模块:

  1. 课程管理模块
    • 负责加载、显示和操作课程列表。
    • 提供课程数据的动态加载与更新接口。
  2. 时间表模块
    • 负责生成右侧时间表的布局和交互逻辑。
    • 提供时间段与课程的关联关系管理。
  3. 拖拽模块
    • 监听拖拽事件,处理数据传递与放置逻辑。
    • 提供冲突检测与错误提示功能。
  4. 数据存储模块
    • 负责课程表数据的保存与加载。
    • 支持本地存储和后端接口两种方式。
  5. UI 反馈模块
    • 提供高亮、动画等视觉反馈功能。
    • 集成错误提示与状态消息展示

三、实现课程表:详细代码与逐步讲解

3.1 静态 HTML 结构

首先,课程表的静态HTML结构需要清晰地定义课程列表和时间表。以下是完整的HTML结构:

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>课程表实现</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 20px;
            display: flex;
            flex-direction: row;
            justify-content: space-between;
        }
        .courses, .schedule {
            border: 1px solid #ccc;
            border-radius: 5px;
            padding: 10px;
            background: #f9f9f9;
        }
        .courses {
            width: 200px;
        }
        .course {
            background: lightblue;
            margin: 5px 0;
            padding: 10px;
            cursor: move;
            text-align: center;
            border: 1px solid #007bff;
            border-radius: 5px;
        }
        .schedule {
            flex: 1;
            display: flex;
            flex-direction: column;
        }
        .day {
            margin-bottom: 15px;
        }
        .day h3 {
            margin: 0;
            padding: 5px;
            background: #007bff;
            color: white;
            text-align: center;
            border-radius: 5px;
        }
        .time-slot {
            border: 1px dashed #ccc;
            padding: 20px;
            margin: 5px 0;
            background: #fff;
            border-radius: 5px;
            text-align: center;
        }
        .time-slot:hover {
            border-color: #007bff;
        }
    </style>
</head>
<body>
    <div class="courses">
        <h3>课程列表</h3>
        <div class="course" id="course1" draggable="true">数学</div>
        <div class="course" id="course2" draggable="true">英语</div>
        <div class="course" id="course3" draggable="true">历史</div>
    </div>
    <div class="schedule">
        <div class="day" id="monday">
            <h3>周一</h3>
            <div class="time-slot" ondrop="drop(event)" ondragover="allowDrop(event)">09:00 - 10:00</div>
            <div class="time-slot" ondrop="drop(event)" ondragover="allowDrop(event)">10:00 - 11:00</div>
        </div>
        <div class="day" id="tuesday">
            <h3>周二</h3>
            <div class="time-slot" ondrop="drop(event)" ondragover="allowDrop(event)">09:00 - 10:00</div>
            <div class="time-slot" ondrop="drop(event)" ondragover="allowDrop(event)">10:00 - 11:00</div>
        </div>
    </div>
    <script src="drag-drop.js"></script>
</body>
</html>

展开

解释:

  • 课程列表:左侧区域,使用.courses类来定义。课程通过.course类定义为可拖拽的元素。
  • 时间表:右侧区域,使用.schedule类定义。分为天(如周一、周二),每天包含多个时间段.time-slot

3.2 样式优化

在基本结构样式的基础上,我们添加了一些视觉效果:

  1. 课程元素:
    • 使用圆角边框和浅蓝背景区分课程。
    • 鼠标悬停时增加光标样式反馈。
  2. 时间段:
    • 使用虚线边框表示空闲区域。
    • 鼠标悬停时,边框颜色变为蓝色,提示用户该区域可放置课程。

3.3 JavaScript 功能实现

3.3.1 拖拽功能基础实现

拖拽操作分为三个核心事件:dragstartdragoverdrop

// 开始拖拽:记录被拖拽元素的ID
function dragStart(event) {
    event.dataTransfer.setData("text/plain", event.target.id);
    console.log(`开始拖拽:${event.target.id}`);
}

// 允许放置:阻止默认行为
function allowDrop(event) {
    event.preventDefault();
}

// 放置到目标区域
function drop(event) {
    event.preventDefault();
    const courseId = event.dataTransfer.getData("text/plain");
    const course = document.getElementById(courseId);

    // 检查目标是否为空
    if (event.target.classList.contains("time-slot") && event.target.children.length === 0) {
        event.target.appendChild(course);
        console.log(`课程 ${courseId} 已放置到时间段`);
    } else {
        alert("时间段已被占用!");
    }
}

核心逻辑分析:

  1. dragStart
    • 当用户开始拖拽课程时,将课程的ID存入dataTransfer对象中,以便在drop事件中获取。
  2. allowDrop
    • 默认情况下,HTML元素不允许拖拽放置。通过event.preventDefault(),显式允许拖拽操作。
  3. drop
    • 当课程放置到时间段中时,检查时间段是否为空。
    • 如果为空,则将课程追加到目标时间段;否则,提示冲突。

3.3.2 冲突检测与用户反馈

为了防止时间冲突,我们在放置时加入检测逻辑:

function drop(event) {
    event.preventDefault();
    const courseId = event.dataTransfer.getData("text/plain");
    const course = document.getElementById(courseId);

    if (event.target.classList.contains("time-slot")) {
        if (event.target.children.length === 0) {
            event.target.appendChild(course);
            event.target.style.borderColor = "green"; // 提供成功反馈
        } else {
            alert("时间段已被占用,请选择其他时间!");
            event.target.style.borderColor = "red"; // 提供错误反馈
            setTimeout(() => {
                event.target.style.borderColor = "#ccc"; // 恢复边框颜色
            }, 1000);
        }
    }
}

3.3.3 数据持久化

我们使用localStorage实现课程表数据的保存和加载。

保存课程表:

function saveSchedule() {
    const scheduleData = {};
    document.querySelectorAll(".time-slot").forEach((slot, index) => {
        if (slot.children.length > 0) {
            scheduleData[index] = slot.children[0].id;
        }
    });
    localStorage.setItem("schedule", JSON.stringify(scheduleData));
    alert("课程表已保存!");
}

加载课程表:

function loadSchedule() {
    const scheduleData = JSON.parse(localStorage.getItem("schedule"));
    if (scheduleData) {
        Object.keys(scheduleData).forEach((index) => {
            const courseId = scheduleData[index];
            const slot = document.querySelectorAll(".time-slot")[index];
            const course = document.getElementById(courseId);
            slot.appendChild(course);
        });
    }
}
window.onload = loadSchedule;

保存按钮:
在HTML中添加保存按钮:

<button onclick="saveSchedule()">保存课程表</button>

3.4 测试与调试

  1. 功能测试:
    • 拖拽课程到空闲时间段,课程应正确显示。
    • 同一时间段不能安排多个课程。
    • 保存后刷新页面,课程表应自动恢复。
  2. 错误处理:
    • 如果localStorage不可用,提示用户保存失败。
    • 当用户拖拽到非法区域(非.time-slot),课程应回到原位。

通过这些实现,我们完成了课程表的核心功能,包括拖拽、冲突检测和数据持久化。接下来可以进行扩展,例如响应式布局、动画效果等。


四、高级功能扩展

在基础功能实现的基础上,我们可以通过数据持久化、响应式设计、高级用户交互等功能进一步扩展课程表的能力。以下是详细的高级功能扩展方案。


4.1 数据持久化

数据持久化是课程表的重要功能,用户可以保存课程表的当前状态并在刷新或重新打开页面时自动加载。

4.1.1 保存课程表到 localStorage

以下代码将课程表中的数据保存为 JSON 格式并存储到浏览器的 localStorage

function saveSchedule() {
    const slots = document.querySelectorAll(".time-slot");
    const schedule = {}; // 用于保存课程安排的数据

    slots.forEach((slot, index) => {
        if (slot.children.length > 0) {
            schedule[index] = slot.children[0].id; // 保存课程 ID 与时间段索引的对应关系
        }
    });

    localStorage.setItem("schedule", JSON.stringify(schedule));
    alert("课程表已成功保存!");
}
4.1.2 加载课程表数据

当页面加载时,我们可以读取 localStorage 中保存的课程表数据并自动将课程安排到对应的时间段中:

function loadSchedule() {
    const schedule = JSON.parse(localStorage.getItem("schedule"));

    if (schedule) {
        Object.keys(schedule).forEach(index => {
            const courseId = schedule[index];
            const course = document.getElementById(courseId);
            const slot = document.querySelectorAll(".time-slot")[index];

            if (course && slot) {
                slot.appendChild(course); // 恢复课程到对应的时间段
            }
        });
    }
}

// 在页面加载时调用 loadSchedule
window.onload = loadSchedule;
4.1.3 删除课程表数据

增加一个功能,用于清空保存的课程表数据:

function clearSchedule() {
    localStorage.removeItem("schedule");
    alert("课程表数据已清空!");
    location.reload(); // 刷新页面以恢复默认状态
}

扩展按钮:
在 HTML 中添加保存和清除按钮:

<button onclick="saveSchedule()">保存课程表</button>
<button onclick="clearSchedule()">清除课程表</button>

4.2 响应式设计与移动端适配

4.2.1 响应式布局

在移动设备上,课程表应能自动调整布局。例如,将时间表从横向排列改为纵向排列。以下是适配方案:

/* 针对桌面端 */
.schedule {
    display: flex;
    justify-content: space-between;
}

/* 针对移动端 */
@media (max-width: 600px) {
    .schedule {
        flex-direction: column; /* 将时间表改为纵向排列 */
    }

    .time-table {
        margin-bottom: 20px;
    }
}
4.2.2 触摸屏支持

在触摸屏上使用原生拖拽可能不够友好,可以使用 JavaScript 手势库(如 Hammer.js)来支持触摸拖动。例如:

// 简单触摸拖动示例(需要引入手势库)
let draggedElement = null;

function touchStart(event) {
    draggedElement = event.target; // 记录触摸的课程元素
}

function touchMove(event) {
    const touch = event.touches[0];
    draggedElement.style.position = "absolute";
    draggedElement.style.left = `${touch.pageX}px`;
    draggedElement.style.top = `${touch.pageY}px`;
}

function touchEnd(event) {
    draggedElement.style.position = "static"; // 放置后恢复原样
    draggedElement = null;
}

绑定触摸事件到课程元素:

document.querySelectorAll('.course').forEach(course => {
    course.addEventListener('touchstart', touchStart);
    course.addEventListener('touchmove', touchMove);
    course.addEventListener('touchend', touchEnd);
});

4.3 增强交互反馈

4.3.1 拖拽动画效果

在拖拽时为课程添加动画效果,使用户操作更流畅:

.course {
    transition: transform 0.2s ease; /* 拖拽时平滑移动 */
}

.course.dragging {
    opacity: 0.5;
    transform: scale(1.2); /* 放大效果 */
}

在拖拽事件中添加样式:

function dragStart(event) {
    event.target.classList.add("dragging");
    event.dataTransfer.setData("text/plain", event.target.id);
}

function dragEnd(event) {
    event.target.classList.remove("dragging");
}

绑定事件:

document.querySelectorAll('.course').forEach(course => {
    course.addEventListener('dragstart', dragStart);
    course.addEventListener('dragend', dragEnd);
});
4.3.2 高亮目标区域

当拖拽课程悬停到时间段时,为时间段添加高亮效果:

.time-slot.drag-over {
    background-color: #e0f7fa;
    border-color: #007bff;
}

dragoverdragleave 事件中添加逻辑:

function allowDrop(event) {
    event.preventDefault();
    event.target.classList.add("drag-over");
}

function dragLeave(event) {
    event.target.classList.remove("drag-over");
}

绑定事件:

document.querySelectorAll('.time-slot').forEach(slot => {
    slot.addEventListener('dragover', allowDrop);
    slot.addEventListener('dragleave', dragLeave);
});

五、性能优化与最佳实践

5.1 DOM 操作优化

频繁操作 DOM 会导致性能瓶颈,尤其是在课程表元素较多时。以下是优化策略:

5.1.1 使用 DocumentFragment

批量操作时使用 DocumentFragment,减少重绘和重排:

function createSchedule(days, timeSlots) {
    const fragment = document.createDocumentFragment();

    days.forEach(day => {
        const dayContainer = document.createElement('div');
        dayContainer.className = 'day';

        const header = document.createElement('h3');
        header.textContent = day;
        dayContainer.appendChild(header);

        timeSlots.forEach(slot => {
            const timeSlot = document.createElement('div');
            timeSlot.className = 'time-slot';
            timeSlot.setAttribute('ondrop', 'drop(event)');
            timeSlot.setAttribute('ondragover', 'allowDrop(event)');
            timeSlot.textContent = slot;

            dayContainer.appendChild(timeSlot);
        });

        fragment.appendChild(dayContainer);
    });

    document.querySelector('.schedule').appendChild(fragment);
}
5.1.2 减少事件监听

避免为每个课程或时间段单独绑定事件,改为事件委托:

document.querySelector('.schedule').addEventListener('dragover', event => {
    if (event.target.classList.contains('time-slot')) {
        allowDrop(event);
    }
});

document.querySelector('.schedule').addEventListener('drop', event => {
    if (event.target.classList.contains('time-slot')) {
        drop(event);
    }
});

六、拓展应用场景

6.1 文件拖拽上传

拖拽文件上传是拖拽 API 的常见应用场景:

const dropZone = document.getElementById('drop-zone');

dropZone.addEventListener('dragover', event => {
    event.preventDefault();
    dropZone.classList.add('drag-over');
});

dropZone.addEventListener('drop', event => {
    event.preventDefault();
    dropZone.classList.remove('drag-over');
    const files = event.dataTransfer.files;

    // 显示文件列表
    Array.from(files).forEach(file => {
        console.log(`上传文件:${file.name}`);
    });
});

HTML:

<div id="drop-zone" style="border: 2px dashed #ccc; padding: 20px; text-align: center;">
    将文件拖到此处上传
</div>

6.2 看板系统

在看板系统中,用户可以将任务卡片拖放到不同列(如待办、进行中、已完成):

function dropTask(event) {
    const taskId = event.dataTransfer.getData('text/plain');
    const task = document.getElementById(taskId);

    if (event.target.classList.contains('task-column')) {
        event.target.appendChild(task);
    }
}

在这里插入图片描述

七、总结

通过高级功能扩展,课程表的功能变得更加强大和实用。我们实现了数据持久化、响应式设计、触摸屏支持、拖拽动画等功能,并探讨了性能优化策略和其他应用场景(如文件上传和看板系统)。这些功能的实现使得课程表不仅限于简单的拖拽交互,还可以扩展为复杂的多功能应用。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/935869.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

阿里云-通义灵码:测试与实例展示

目录 一.引子 二.例子 三.优点 四.其他优点 五.总结 一.引子 在软件开发的广袤天地中&#xff0c;阿里云通义灵码宛如一座蕴藏无尽智慧的宝库&#xff0c;等待着开发者们去深入挖掘和探索。当我们跨越了入门的门槛&#xff0c;真正开始使用通义灵码进行代码生成和开发工作…

第P2周:Pytorch实现CIFAR10彩色图片识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 目标 实现CIFAR-10的彩色图片识别实现比P1周更复杂一点的CNN网络 具体实现 &#xff08;一&#xff09;环境 语言环境&#xff1a;Python 3.10 编 译 器: …

【数字花园】数字花园(个人网站、博客)搭建经历汇总教程

目录 写在最最前面第一章&#xff1a;netlify免费搭建数字花园相关教程使用的平台步骤信息管理 第二章&#xff1a;本地部署数字花园数字花园网站本地手动部署方案1. 获取网站源码2.2 安装 Node.js 3. 项目部署3.1 安装项目依赖3.2 构建项目3.3 启动http服务器 4. 本地预览5. 在…

Hadoop一课一得

Hadoop作为大数据时代的奠基技术之一&#xff0c;自问世以来就深刻改变了海量数据存储与处理的方式。本文将带您深入了解Hadoop&#xff0c;从其起源、核心架构、关键组件&#xff0c;到典型应用场景&#xff0c;并结合代码示例和图示&#xff0c;帮助您更好地掌握Hadoop的实战…

使用 GD32F470ZGT6,手写 I2C 的实现

我的代码&#xff1a;https://gitee.com/a1422749310/gd32_-official_-code I2C 具体代码位置&#xff1a;https://gitee.com/a1422749310/gd32_-official_-code/blob/master/Hardware/i2c/i2c.c 黑马 - I2C原理 官方 - IIC 协议介绍 个人学习过程中的理解&#xff0c;有错误&…

WPF Prism ViewInjection

ViewInjection介绍 ViewInjection是Prism框架提供的一种机制&#xff0c;用于将视图动态地注入到指定的容器&#xff08;Region&#xff09;中。这种注入方式允许你在运行时动态地添加、移除或替换视图&#xff0c;从而实现更灵活的用户界面设计。 ViewInjection示例 GitHub…

软考高级架构 - 11.1- 信息物理系统CPS

信息物理系统CPS 信息物理系统(CPS)是控制系统、嵌入式系统的扩展与延伸。通过集成先进的感知、计算、通信、控制等信息技术和自动控制技&#xff0c;构建了物理空间与信息空间中人、机、物、环境、信息等要素相互映射、适时交互、高效协同的夏杂系统。 CPS的本质是基于…

后端开发工程师需要掌握哪些设计模式?

大家好&#xff0c;我是袁庭新。 作为后端开发者&#xff0c;学习和掌握设计模式是非常有必要的。不仅可以帮助后端开发者更好地设计和实现软件架构&#xff0c;还可以提高代码的质量和可维护性。此外&#xff0c;设计模式也是后端开发面试中常见的考点之一&#xff0c;掌握它…

【Android Studio】学习——数据存储管理

AndroidStudio实验——数据存储管理 文章目录 AndroidStudio实验——数据存储管理[toc]一&#xff1a;实验目标和实验内容&#xff1a;二&#xff1a;数据库的CRUD操作【一】创建&#xff08;Create&#xff09;【2】读取&#xff08;Read&#xff09;【3】更新&#xff08;Upd…

科研绘图系列:R语言绘制热图和散点图以及箱线图(pheatmap, scatterplot boxplot)

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍加载R包数据下载图1图2图3系统信息参考介绍 R语言绘制热图和散点图以及箱线图(pheatmap, scatterplot & boxplot) 加载R包 library(magrittr) library(dplyr) library(ve…

【Qt】信号、槽

目录 一、信号和槽的基本概念 二、connect函数&#xff1a;关联信号和槽 三、自定义信号和槽 1.自定义槽函数 2.自定义信号函数 例子&#xff1a; 四、带参的信号和槽 例子&#xff1a; 五、Q_OBJECT宏 六、断开信号和槽的连接 例子&#xff1a; 一、信号和槽的基本…

一种构建网络安全知识图谱的实用方法

文章主要工作 论述了构建网络安全知识库的三个步骤&#xff0c;并提出了一个构建网络安全知识库的框架;讨论网络安全知识的推演 1.框架设计 总体知识图谱框架如图1所示&#xff0c;其包括数据源&#xff08;结构化数据和非结构化数据&#xff09;、信息抽取及本体构建、网络…

JAVA后端实现全国区县下拉选择--树形结构

设计图如图&#xff1a; 直接上代码 数据库中的格式&#xff1a; JAVA实体类&#xff1a; Data public class SysAreaZoningDO {private Long districtId;private Long parentId;private String districtName;private List<SysAreaZoningDO> children; } MapperSQL语句…

青少年夏令营管理系统的设计与开发(社团管理)(springboot+vue)+文档

&#x1f497;博主介绍&#x1f497;&#xff1a;✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 温馨提示&#xff1a;文末有 CSDN 平台官方提供的老师 Wechat / QQ 名片 :) Java精品实战案例《700套》 2025最新毕业设计选题推荐…

安卓低功耗蓝牙BLE官方开发例程(JAVA)翻译注释版

官方原文链接 https://developer.android.com/develop/connectivity/bluetooth/ble/ble-overview?hlzh-cn 目录 低功耗蓝牙 基础知识 关键术语和概念 角色和职责 查找 BLE 设备 连接到 GATT 服务器 设置绑定服务 设置 BluetoothAdapter 连接到设备 声明 GATT 回…

Windows 系统中的组策略编辑器如何打开?

组策略是 Windows 操作系统中用于设置计算机和用户配置的重要工具。它允许管理员控制各种系统功能&#xff0c;从桌面背景到安全设置等。对于 Windows 专业版、企业版和教育版用户来说&#xff0c;可以通过组策略编辑器&#xff08;Group Policy Editor&#xff09;来管理这些设…

MySQL删除外键报错check that column/key exists

在我们删除外键的时候&#xff0c;报了check that column/key exists这个错误&#xff0c;这是因为你的外键名字没写对&#xff0c;我们以为我们写的字段名就是我们的外键其实并不是&#xff0c;我们可以通过show create table[ ]来查看外键的名字 所以删除外键的时候应该这样…

python学opencv|读取图像(十)用numpy创建彩色图像

【1】引言 前序文章中&#xff0c;我们已经学会了用numpy规划数据控制像素大小&#xff0c;然后用像素规划矩阵&#xff0c;对矩阵赋值后输出灰度图&#xff0c;相关链接为&#xff1a; python学opencv|读取图像&#xff08;八&#xff09;用numpy创建纯黑灰度图-CSDN博客 p…

线程池(ThreadPoolExecutor)

目录 一、线程池 标准提供的线程池 ThreadPoolExecutor 自定义线程池 一、线程池 为什么要引入线程池? 这个原因我们需要追溯到线程&#xff0c;我们线程存在的意义在于&#xff0c;使用进程进行并发编程太重了&#xff0c;所以引入了线程&#xff0c;因为线程又称为 “轻…

hbase读写操作后hdfs内存占用太大的问题

hbase读写操作后hdfs内存占用太大的问题 查看内存信息hbase读写操作 查看内存信息 查看本地磁盘的内存信息 df -h查看hdfs上根目录下各个文件的内存大小 hdfs dfs -du -h /查看hdfs上/hbase目录下各个文件的内存大小 hdfs dfs -du -h /hbase查看hdfs上/hbase/oldWALs目录下…