网页版便签应用开发:HTML5本地存储与拖拽交互实践

文章目录

  • 摘要
  • 成品显示
  • 核心功能与实现语法
    • 1. 本地存储管理
    • 2. 拖拽功能实现
    • 3. 自动保存机制
    • 4. 时间格式化处理
  • 完整代码

摘要

本文详细介绍了一个基于HTML5的便签应用开发过程,重点讲解了如何利用localStorage实现数据持久化存储,以及如何实现流畅的拖拽交互体验。该应用具有创建、编辑、删除便签功能,自动保存用户内容,并支持多便签管理。文章将深入解析核心实现代码,并提供完整的开发案例。

成品显示

文章最后提供完整的代码,复制粘贴后保存为html文件,可以直接打开如下图,在网页上创建便签,随时记录,修改,删除,关闭网页,不删除便签。
在这里插入图片描述

核心功能与实现语法

1. 本地存储管理

使用localStorage实现便签数据的持久化存储:

note.operate = {// 存储便签数据set: function (id, content) {var notes = this.getNotes();if (notes[id]) {Object.assign(notes[id], content);} else {notes[id] = content;}localStorage.setItem(this.keyItem, JSON.stringify(notes));},// 获取便签数据getNotes: function () {return JSON.parse(localStorage.getItem(this.keyItem) || '{}');},// 删除便签remove: function (id) {var notes = this.getNotes();delete notes[id];localStorage.setItem(this.keyItem, JSON.stringify(notes));}
};

2. 拖拽功能实现

精准的拖拽位置计算和层级管理:

// 标题栏拖拽事件
titleBar.addEventListener('mousedown', function(e) {movedNote = note;var rect = note.getBoundingClientRect();startX = e.clientX - rect.left;startY = e.clientY - rect.top;// 提升当前便签的z-indexmaxZindex++;note.style.zIndex = maxZindex;
});// 全局鼠标移动事件
document.addEventListener('mousemove', function(e) {if (!movedNote) return;movedNote.style.left = (e.clientX - startX) + 'px';movedNote.style.top = (e.clientY - startY) + 'px';
});

3. 自动保存机制

使用防抖技术优化内容自动保存:

// 编辑区域事件
var inputTimer;
edit.addEventListener('input', function() {var content = edit.innerHTML;clearTimeout(inputTimer);inputTimer = setTimeout(function() {var time = Date.now();operate.set(that.note.id, {content: content,updateTime: time});that.updateTime(time);}, 500); // 500ms防抖延迟
});

4. 时间格式化处理

时间显示格式:

dateFormat: function (ms) {var d = new Date(ms);var pad = function (s) {return s.toString().padStart(2, '0');}return `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
}

完整代码

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>便签应用</title><style>* {margin: 0;padding: 0;box-sizing: border-box;}body {font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);min-height: 100vh;padding: 20px;display: flex;flex-direction: column;align-items: center;}.header {text-align: center;margin-bottom: 30px;color: white;width: 100%;max-width: 1200px;}.header h1 {font-size: 3rem;margin-bottom: 10px;text-shadow: 0 2px 10px rgba(0,0,0,0.3);}.header p {font-size: 1.2rem;opacity: 0.9;max-width: 600px;margin: 0 auto;}#u-btn-create {background: #ff9a00;color: white;border: none;padding: 15px 35px;font-size: 1.2rem;border-radius: 50px;cursor: pointer;box-shadow: 0 4px 15px rgba(0,0,0,0.2);transition: all 0.3s ease;margin-top: 20px;font-weight: bold;letter-spacing: 1px;}#u-btn-create:hover {background: #ff7b00;transform: translateY(-3px);box-shadow: 0 6px 20px rgba(0,0,0,0.25);}.m-note {position: absolute;width: 300px;background: #fff9c4;border-radius: 8px;box-shadow: 0 10px 30px rgba(0,0,0,0.15);overflow: hidden;transition: box-shadow 0.3s ease;display: flex;flex-direction: column;min-height: 320px;}.m-note:hover {box-shadow: 0 15px 40px rgba(0,0,0,0.2);}.u-title {background: #ffd54f;color: #333;padding: 12px 20px;font-weight: bold;font-size: 1.1rem;cursor: move;display: flex;justify-content: space-between;align-items: center;}.u-close {cursor: pointer;font-style: normal;font-size: 1.5rem;width: 30px;height: 30px;display: flex;align-items: center;justify-content: center;border-radius: 50%;transition: all 0.2s ease;}.u-close:hover {background: rgba(0,0,0,0.1);transform: scale(1.1);}.u-edit {flex: 1;padding: 20px;font-size: 1rem;line-height: 1.5;outline: none;min-height: 200px;max-height: 300px;overflow-y: auto;background: #fffde7;}.u-timeUpdate {background: rgba(0,0,0,0.05);padding: 10px 20px;font-size: 0.85rem;color: #666;}.time {font-weight: 600;color: #333;}.features {display: flex;justify-content: center;flex-wrap: wrap;gap: 20px;max-width: 1000px;margin: 40px auto;}.feature-card {background: rgba(255, 255, 255, 0.15);backdrop-filter: blur(10px);border-radius: 15px;padding: 25px;width: 280px;color: white;box-shadow: 0 8px 20px rgba(0,0,0,0.1);}.feature-card h3 {font-size: 1.4rem;margin-bottom: 15px;display: flex;align-items: center;}.feature-card h3 i {margin-right: 10px;font-size: 1.6rem;}.feature-card p {line-height: 1.6;opacity: 0.9;}@media (max-width: 768px) {.header h1 {font-size: 2.2rem;}.features {flex-direction: column;align-items: center;}}</style>
</head>
<body><div class="header"><h1>📝 智能便签应用</h1><p>随时随地记录您的想法、待办事项和重要信息</p><button id="u-btn-create">+ 新建便签</button></div><div class="features"><div class="feature-card"><h3><i>📌</i> 拖拽移动</h3><p>点击标题栏可以拖拽便签到任意位置,方便您整理工作区</p></div><div class="feature-card"><h3><i>🔄</i> 自动保存</h3><p>内容编辑后会自动保存到本地存储,刷新页面也不会丢失</p></div><div class="feature-card"><h3><i>⏱️</i> 时间记录</h3><p>每次更新便签内容都会记录时间,帮助您追踪进度</p></div></div><script>var note = {util: {}, //存放基础工具的方法operate: {} //存放便签相关的操作};note.util = {$: function (value, node) {return (node || document).querySelector(value);},dateFormat: function (ms) {/*格式化时间*/var d = new Date(ms);var pad = function (s) {if (s.toString().length === 1) {s = '0' + s;}return s;}var year = d.getFullYear();var month = d.getMonth() + 1;var date = d.getDate();var hour = d.getHours();var minute = d.getMinutes();var second = d.getSeconds();return year + '-' + pad(month) + '-' + pad(date) + ' ' + pad(hour) + ':' + pad(minute) + ':' + pad(second);}};note.operate = {/*本地存储的关键字*/keyItem: 'stickyNote',/*根据便签的id来获取note*/get: function (id) {var notes = this.getNotes();return notes[id] || {};},/*设置一个note的id及其内容*/set: function (id, content) {var notes = this.getNotes();if (notes[id]) {Object.assign(notes[id], content);} else {notes[id] = content;}localStorage.setItem(this.keyItem, JSON.stringify(notes));console.log('saved note: id: ' + id + ' content: ' + JSON.stringify(notes[id]));},/*根据id删除对应的便签*/remove: function (id) {var notes = this.getNotes();delete notes[id];localStorage.setItem(this.keyItem, JSON.stringify(notes));},/*获取localStorage中所有的note*/getNotes: function () {return JSON.parse(localStorage.getItem(this.keyItem) || '{}');}};/*创建note*/(function (util, operate) {var $ = util.$;var movedNote = null;var startX;var startY;var maxZindex = 0;var noteTemplate = `<div class="u-title">便签 <i class="u-close">×</i></div><div class="u-edit" contenteditable="true"></div><div class="u-timeUpdate"><span>更新时间:</span><span class="time"></span></div>`;function Note(options) {var note = document.createElement('div');note.className = 'm-note';note.id = options.id || 'm-note-' + Date.now();note.innerHTML = noteTemplate;$('.u-edit', note).innerHTML = options.content || '';note.style.left = (options.left || Math.round(Math.random() * (window.innerWidth - 320))) + 'px';note.style.top = (options.top || Math.round(Math.random() * (window.innerHeight - 320))) + 'px';note.style.zIndex = options.zIndex || maxZindex++;document.body.appendChild(note);this.note = note;this.updateTime(options.updateTime);this.addEvent();}/*时间更新方法*/Note.prototype.updateTime = function (ms) {var ts = $('.time', this.note);ms = ms || Date.now();ts.innerHTML = util.dateFormat(ms);this.updateTimeInMs = ms;}/*便签保存*/Note.prototype.save = function () {operate.set(this.note.id, {left: this.note.offsetLeft,top: this.note.offsetTop,zIndex: parseInt(this.note.style.zIndex),content: $('.u-edit', this.note).innerHTML,updateTime: this.updateTimeInMs});console.log('note saved');}/*删除此便签*/Note.prototype.close = function (e) {console.log('close note');document.body.removeChild(this.note);}Note.prototype.addEvent = function () {var that = this;var note = this.note;var titleBar = $('.u-title', note);var edit = $('.u-edit', note);var closeBtn = $('.u-close', note);// 标题栏拖拽事件titleBar.addEventListener('mousedown', function(e) {if (e.target === closeBtn) return; // 排除关闭按钮movedNote = note;var rect = note.getBoundingClientRect();startX = e.clientX - rect.left;startY = e.clientY - rect.top;// 提升当前便签的z-indexmaxZindex++;note.style.zIndex = maxZindex;operate.set(note.id, {zIndex: maxZindex});});// 编辑区域事件var inputTimer;edit.addEventListener('input', function() {var content = edit.innerHTML;clearTimeout(inputTimer);inputTimer = setTimeout(function() {var time = Date.now();operate.set(that.note.id, {content: content,updateTime: time});that.updateTime(time);}, 500);});// 关闭按钮事件closeBtn.addEventListener('click', function(e) {operate.remove(that.note.id);that.close();});}/*按钮的监听事件*/document.addEventListener('DOMContentLoaded', function (e) {$('#u-btn-create').addEventListener('click', function (e) {new Note({});});/*全局鼠标移动事件*/function mousemoveHandler(e) {if (!movedNote) return;movedNote.style.left = (e.clientX - startX) + 'px';movedNote.style.top = (e.clientY - startY) + 'px';}function mouseupHandler(e) {if (!movedNote) return;operate.set(movedNote.id, {left: movedNote.offsetLeft,top: movedNote.offsetTop});movedNote = null;}document.addEventListener('mousemove', mousemoveHandler);document.addEventListener('mouseup', mouseupHandler);/*初始化*/var notes = operate.getNotes();Object.keys(notes).forEach(function (id) {var options = notes[id];if (options.zIndex > maxZindex) {maxZindex = options.zIndex;}new Note(Object.assign(options, {id: id}));});// 确保maxZindex至少为1maxZindex = Math.max(maxZindex, 1);});})(note.util, note.operate);</script>
</body>
</html>

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker compose安装Prometheus、Grafana

1、创建目录结构 mkdir -p /opt/monitoring/{prometheus,grafana} mkdir -p /opt/monitoring/prometheus/{config,data} chmod -R 777 /opt/monitoring # 确保容器有写入权限 2、准备 Prometheus 配置文件 vi /opt/monitoring/prometheus/config/prometheus.yml global:sc…

稀土化合物在生态环境的应用

稀土化合物凭借强吸附性、催化活性及环境兼容性&#xff0c;已成为生态治理的关键材料。氧化物、氯化物、磷酸盐等基础产品&#xff0c;通过灵活复配与工艺适配&#xff0c;可高效解决水体净化、土壤修复、废气处理三大核心问题&#xff0c;推动环境治理向低耗高效转型。那么&a…

搭建网站应该怎样选择服务器?

互联网技术已经全面在各个地区进行发展&#xff0c;越来越多的企业选择线上业务&#xff0c;搭建属于自己的网站运营&#xff0c;以此来增加品牌的知名度并进行详细介绍&#xff0c;但是企业在进行搭建网站的前提&#xff0c;要选择一种合适的服务器&#xff0c;确保后续网站能…

每日算法刷题Day30 6.13:leetcode二分答案2道题,用时1h10min

5. 1201.丑数III(中等) 1201. 丑数 III - 力扣&#xff08;LeetCode&#xff09; 思想 1.丑数是可以被 a 或 b 或 c 整除的 正整数 。 给你四个整数&#xff1a;n 、a 、b 、c &#xff0c;请你设计一个算法来找出第 n 个丑数。 2.此题是4. 878.第N个神奇数字的进阶版&#…

Appium+python自动化(二十一)- Monkey指令操作手机

第一式 - 隐藏命令 monkey隐藏的两个命令&#xff1a; –pck-blacklist-file<黑名单文件><br><br>–pck-whitelist-file<白名单文件> monkey还有一个隐藏的命令那就是&#xff1a; –f<脚本文件>:可以指定monkey的自定义脚本 一般monkey测试…

微信小程序动态效果实战指南:从悬浮云朵到丝滑列表加载

小红书爆款交互设计解析&#xff0c;附完整代码&#xff01; &#x1f525; 一、为什么动态效果是小程序的关键竞争力&#xff1f; 用户留存提升&#xff1a;数据显示&#xff0c;86.3%的微商从业者依赖微信小程序&#xff0c;而动态效果能显著降低跳出率。技术赋能体验&#…

【机器学习】SAE(Sparse Autoencoders)稀疏自编码器

SAE(Sparse Autoencoders)稀疏自编码器 0.引言 大模型一直被视为一个“黑箱”&#xff0c;研究人员对其内部神经元如何相互作用以实现功能的机制尚不清楚。因此研究机理可解释性&#xff08;Mechanistic Interpretability&#xff09;就成为了一个热门研究方向。大模型的复杂…

抖音授权登录-获取用户授权调用凭证

实现微信小程序获取抖音授权,使用Java实现抖音授权登录,您需要使用抖音开放平台提供的API 第一步 :抖音获取授权码 前提条件 •需要去官网为应用申请 scope 的使用权限。•需要在本接口的 scope 传参中填上需要用户授权的 scope,多个 scope 以逗号分割。•用户授权通过后…

普通人怎样用好Deepseek?

今年4月份左右&#xff08;2025年&#xff09;&#xff0c;我在上班路上开车&#xff0c;一边听着「黑客与画家」的播客&#xff0c;一边想着字节的Trae为啥能够远程编程&#xff0c;而我的poclogsender[1] [2]却只能在本地打日志&#xff0c;3天之后&#xff0c;借助deepseek我…

Python ROS2【机器人中间件框架】 简介

销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…

织梦dedecms {dede:sql} LIKE模糊查询问题 多出‘号

我们在用到dede:sql这个标签时候&#xff0c;查询语句中 LIKE %~title~%&#xff0c;~title~这个like后会出现单引号&#xff0c;造成查询出错或者没有结果&#xff0c;下面就需要修改一下sql.lib.php这个文件&#xff0c;我们需要把自动为语句添加单引号去掉。 找到/include/…

Cursor-1.0安装Jupyter-Notebook,可视化运行.ipynb文件中Python分片代码

Cursor 1.0是AI代码编辑器的里程碑的最新版本。 Cursor - AI 代码编辑器 Cursor - The AI Code Editor 下载 Cursor 我使用的Cursor版本信息 Version: 1.0.0 (Universal) VSCode Version: 1.96.2 Commit: 53b99ce608cba35127ae3a050c1738a959750860 Date: 2025-06-04T19:21:39.…

SQL进阶之旅 Day 28:跨库操作与ETL技术

【SQL进阶之旅 Day 28】跨库操作与ETL技术 文章简述 在现代数据驱动的业务场景中&#xff0c;数据往往分布在多个数据库系统中&#xff0c;如MySQL、PostgreSQL、Oracle等。如何高效地进行跨库操作和**数据集成&#xff08;ETL&#xff09;**成为数据工程师和数据库开发人员必…

Flutter之GetX框架的使用

文章目录 前言GetX使用建议状态管理GetX快速上手GetX基本功能介绍**核心作用****代码示例****关键细节****性能建议** 参考链接 前言 在Reddit上&#xff0c;诟病GetX的声音很多&#xff0c;主要是说它做的事情太多&#xff0c;不是单一功能组件&#xff0c;违反单一职责原则。…

Kettle数据抽取(二)

一、脚本运用 从本地ORACLE11 数据库 抽取数据到 华为MYSQL8.1 数据库 抽取前先删除MYSQL8.1 数据库中emp_dept_salgrade表原有数据,避免重复 二、插入表更新 事实上前面一种方法不是增量处理,因为是全部删除合部重新写入相当于初始化一样,这种情形,如果数据量较大,如有1…

一套高质量的博客平台、社交应用UI

这是一套移动端UI设计素材包含14个高质量PSD文件&#xff0c;涵盖博客社交类APP的核心页面&#xff0c;包括登录界面、动态展示、文章详情、聊天会话等常用场景。所有素材均为可编辑PSD格式&#xff0c;支持快速二次开发&#xff0c;适用于移动网站和APP项目。资源提供完整的UI…

麒麟信安支撑2025年电力监控系统安全运维新技能推广应用示范培训班顺利举办

近日&#xff0c;由国调中心主办、国网技术学院电网运行培训部承办的“2025年电力监控系统安全运维新技能推广应用示范培训班&#xff08;第一期&#xff09;”顺利举办。电网运行培训部高度重视本次培训组织工作&#xff0c;在国调中心的指导下&#xff0c;精心编制培训方案&a…

支付系统架构图

简明产品架构图 1. 商户门户 商户通过该门户管理与支付平台的所有互动&#xff0c;包括&#xff1a; 登录&#xff1a;商户进入系统&#xff0c;进行身份验证。 入驻&#xff1a;新商户注册并加入平台&#xff0c;开始使用支付服务。 订单管理&#xff1a;商户可以管理自己…

企业如何一键复制 DolphinScheduler 项目到新项目服务器?全套自动化方案来了!(企业不外传的实用工具)

在企业生产实践中,常见的一种场景是:一个大数据调度项目需要为多个客户分别部署在不同服务器上,而每个客户的任务逻辑、工作流结构、资源文件基本相同。这种情况下,如果每次都手动创建 DolphinScheduler 项目、上传资源文件、配置流程和参数,不仅浪费大量时间,还极容易出…

Oracle中10个索引优化

Oracle数据库作为一个功能强大的企业级数据库系统&#xff0c;对于索引的优化有着丰富的技巧和方法。理解和运用这些技巧可以显著提高数据库性能。 示例代码&#xff1a; – 假设我们有一个员工表 CREATE TABLE employees ( emp_id NUMBER PRIMARY KEY, name VARCHAR2(100), de…