当前位置: 首页 > news >正文

vue3 实现记事本手机版01

在这里插入图片描述

<template><div class="notes-app"><!-- 顶部导航栏 --><nav class="app-nav" :class="{ 'nav-with-back': currentView !== 'list' }"><buttonclass="back-btn"@click="handleBack"v-if="currentView !== 'list'"><i class="icon-arrow-left"></i></button><h1 class="app-title">{{ currentView === 'list' ? '记事本' :currentView === 'detail' ? '笔记详情' :currentView === 'edit' ? '编辑笔记' : '新建笔记' }}</h1><buttonclass="add-btn"@click="goToCreateNote"v-if="currentView === 'list'"><i class="icon-plus"></i></button></nav><!-- 笔记列表视图 --><div class="view list-view" v-if="currentView === 'list'"><div class="empty-state" v-if="notes.length === 0"><div class="empty-icon">📝</div><p class="empty-text">还没有笔记</p><p class="empty-subtext">点击右上角 + 创建你的第一条笔记</p></div><ul class="notes-list" v-else><liclass="note-item"v-for="note in notes":key="note.id"@click="goToNoteDetail(note.id)"><div class="note-info"><h3 class="note-title">{{ note.title || '无标题' }}</h3><p class="note-content">{{ note.content.substring(0, 60) }}{{ note.content.length > 60 ? '...' : '' }}</p><time class="note-time">{{ formatDate(note.updatedAt) }}</time></div><div class="note-actions"><buttonclass="action-btn edit-btn"@click.stop="goToEditNote(note.id)"aria-label="编辑笔记"><i class="icon-edit"></i></button><buttonclass="action-btn delete-btn"@click.stop="showDeleteDialog(note.id)"aria-label="删除笔记"><i class="icon-delete"></i></button></div></li></ul></div><!-- 笔记详情视图 --><div class="view detail-view" v-if="currentView === 'detail'"><div class="detail-content" v-if="currentNote"><h2 class="detail-title">{{ currentNote.title || '无标题' }}</h2><time class="detail-time">{{ formatDate(currentNote.updatedAt) }}</time><div class="detail-text">{{ currentNote.content }}</div></div><div class="detail-actions"><buttonclass="detail-btn edit-detail-btn"@click="goToEditNote(currentNote?.id)"><i class="icon-edit"></i> 编辑</button><buttonclass="detail-btn delete-detail-btn"@click="showDeleteDialog(currentNote?.id)"><i class="icon-delete"></i> 删除</button></div></div><!-- 新建/编辑笔记视图 --><div class="view editor-view" v-if="currentView === 'create' || currentView === 'edit'"><div class="editor-form"><inputtype="text"v-model="noteForm.title"class="title-input"placeholder="请输入标题..."maxlength="50"><textareav-model="noteForm.content"class="content-input"placeholder="请输入笔记内容..."rows="15"></textarea></div><buttonclass="save-btn"@click="saveNote":disabled="!noteForm.title && !noteForm.content">保存</button></div><!-- 删除确认弹窗 --><div class="modal-backdrop" v-if="showDeleteModal"><div class="delete-modal"><h3 class="modal-title">确认删除</h3><p class="modal-message">你确定要删除这条笔记吗?此操作不可撤销。</p><div class="modal-buttons"><buttonclass="modal-btn cancel-btn"@click="showDeleteModal = false">取消</button><buttonclass="modal-btn confirm-btn"@click="confirmDelete">删除</button></div></div></div></div>
</template><script setup>
import { ref, computed, onMounted, watch } from 'vue';// 视图状态管理
const currentView = ref('list'); // list, detail, create, edit
const currentNoteId = ref(null);
const showDeleteModal = ref(false);
const noteToDelete = ref(null);// 笔记数据
const notes = ref([]);// 表单数据
const noteForm = ref({title: '',content: ''
});// 当前选中的笔记
const currentNote = computed(() => {return notes.value.find(note => note.id === currentNoteId.value) || null;
});// 从本地存储加载笔记
const loadNotes = () => {const savedNotes = localStorage.getItem('mobileNotes');if (savedNotes) {notes.value = JSON.parse(savedNotes);}
};// 保存笔记到本地存储
const saveNotesToStorage = () => {localStorage.setItem('mobileNotes', JSON.stringify(notes.value));
};// 初始化
onMounted(() => {loadNotes();
});// 监听笔记变化并保存
watch(notes, () => {saveNotesToStorage();
}, { deep: true });// 导航处理
const handleBack = () => {switch(currentView.value) {case 'detail':case 'create':currentView.value = 'list';break;case 'edit':currentView.value = 'detail';break;}
};// 跳转到笔记详情
const goToNoteDetail = (id) => {currentNoteId.value = id;currentView.value = 'detail';
};// 跳转到新建笔记
const goToCreateNote = () => {noteForm.value = { title: '', content: '' };currentView.value = 'create';
};// 跳转到编辑笔记
const goToEditNote = (id) => {const note = notes.value.find(n => n.id === id);if (note) {noteForm.value = {title: note.title,content: note.content};currentNoteId.value = id;currentView.value = 'edit';}
};// 保存笔记
const saveNote = () => {const now = new Date().toISOString();if (currentView.value === 'create') {// 新建笔记const newNote = {id: Date.now().toString(),title: noteForm.value.title,content: noteForm.value.content,createdAt: now,updatedAt: now};notes.value.unshift(newNote); // 添加到数组开头,最新的在前面} else {// 编辑现有笔记const index = notes.value.findIndex(n => n.id === currentNoteId.value);if (index !== -1) {notes.value[index].title = noteForm.value.title;notes.value[index].content = noteForm.value.content;notes.value[index].updatedAt = now;}}// 返回列表或详情页currentView.value = 'list';
};// 显示删除确认
const showDeleteDialog = (id) => {noteToDelete.value = id;showDeleteModal.value = true;
};// 确认删除
const confirmDelete = () => {if (noteToDelete.value) {notes.value = notes.value.filter(note => note.id !== noteToDelete.value);showDeleteModal.value = false;currentView.value = 'list';noteToDelete.value = null;}
};// 格式化日期显示
const formatDate = (isoString) => {const date = new Date(isoString);return date.toLocaleString('zh-CN', {month: 'short',day: 'numeric',hour: '2-digit',minute: '2-digit'});
};
</script><style scoped>
/* 基础样式 */
.notes-app {max-width: 500px;margin: 0 auto;min-height: 100vh;background-color: #f9f9f9;color: #333;font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;position: relative;
}/* 导航栏 */
.app-nav {display: flex;align-items: center;justify-content: center;height: 56px;background-color: #2196f3;color: white;padding: 0 16px;box-shadow: 0 2px 4px rgba(0,0,0,0.1);position: sticky;top: 0;z-index: 10;
}.nav-with-back {justify-content: flex-start;
}.app-title {font-size: 18px;font-weight: 500;margin: 0;
}.back-btn, .add-btn {width: 40px;height: 40px;border-radius: 50%;background: transparent;border: none;color: white;display: flex;align-items: center;justify-content: center;cursor: pointer;font-size: 20px;
}.back-btn {margin-right: 16px;
}.add-btn {position: absolute;right: 16px;
}/* 图标样式 */
.icon-plus::before {content: "+";font-weight: bold;
}.icon-arrow-left::before {content: "←";font-weight: bold;
}.icon-edit::before {content: "✏️";
}.icon-delete::before {content: "🗑️";
}/* 视图容器 */
.view {padding: 16px;min-height: calc(100vh - 56px);box-sizing: border-box;
}/* 列表视图 */
.notes-list {list-style: none;margin: 0;padding: 0;
}.note-item {display: flex;justify-content: space-between;align-items: center;background-color: white;border-radius: 12px;padding: 16px;margin-bottom: 12px;box-shadow: 0 1px 3px rgba(0,0,0,0.05);cursor: pointer;transition: transform 0.1s ease, box-shadow 0.1s ease;
}.note-item:active {transform: translateY(1px);box-shadow: 0 1px 2px rgba(0,0,0,0.1);
}.note-info {flex: 1;overflow: hidden;padding-right: 12px;
}.note-title {margin: 0 0 6px 0;font-size: 16px;font-weight: 500;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;
}.note-content {margin: 0 0 8px 0;font-size: 14px;color: #666;display: -webkit-box;-webkit-line-clamp: 2;-webkit-box-orient: vertical;overflow: hidden;line-height: 1.4;
}.note-time {font-size: 12px;color: #999;
}.note-actions {display: flex;gap: 8px;
}.action-btn {width: 36px;height: 36px;border-radius: 50%;border: none;background-color: #f0f0f0;display: flex;align-items: center;justify-content: center;cursor: pointer;transition: background-color 0.2s ease;
}.action-btn:active {transform: scale(0.95);
}.edit-btn {color: #2196f3;
}.delete-btn {color: #f44336;
}/* 空状态 */
.empty-state {text-align: center;padding: 60px 20px;color: #999;
}.empty-icon {font-size: 60px;margin-bottom: 20px;
}.empty-text {font-size: 18px;margin: 0 0 8px 0;
}.empty-subtext {font-size: 14px;margin: 0;color: #bbb;
}/* 详情视图 */
.detail-view {background-color: white;padding-bottom: 80px;
}.detail-content {margin-bottom: 24px;
}.detail-title {margin: 0 0 16px 0;font-size: 22px;font-weight: 500;line-height: 1.3;
}.detail-time {display: block;font-size: 14px;color: #999;margin-bottom: 24px;padding-bottom: 16px;border-bottom: 1px solid #eee;
}.detail-text {font-size: 16px;line-height: 1.6;color: #444;white-space: pre-line;
}.detail-actions {display: flex;gap: 16px;position: fixed;bottom: 20px;left: 50%;transform: translateX(-50%);max-width: calc(100% - 32px);width: 100%;
}.detail-btn {flex: 1;padding: 14px;border-radius: 8px;border: none;font-size: 16px;font-weight: 500;display: flex;align-items: center;justify-content: center;gap: 8px;cursor: pointer;transition: opacity 0.2s ease;
}.detail-btn:active {opacity: 0.8;
}.edit-detail-btn {background-color: #2196f3;color: white;
}.delete-detail-btn {background-color: #f44336;color: white;
}/* 编辑器视图 */
.editor-view {background-color: white;padding-bottom: 80px;
}.editor-form {margin-bottom: 24px;
}.title-input {width: 100%;font-size: 22px;font-weight: 500;padding: 12px 0;margin-bottom: 16px;border: none;border-bottom: 1px solid #eee;outline: none;background: transparent;color: #333;
}.title-input::placeholder {color: #ccc;
}.content-input {width: 100%;font-size: 16px;line-height: 1.6;border: none;outline: none;resize: none;background: transparent;color: #444;min-height: 300px;
}.content-input::placeholder {color: #ccc;
}.save-btn {position: fixed;bottom: 20px;left: 50%;transform: translateX(-50%);width: calc(100% - 32px);max-width: 468px;padding: 14px;background-color: #2196f3;color: white;border: none;border-radius: 8px;font-size: 16px;font-weight: 500;cursor: pointer;transition: background-color 0.2s ease, opacity 0.2s ease;
}.save-btn:disabled {background-color: #ccc;cursor: not-allowed;
}.save-btn:not(:disabled):active {opacity: 0.8;
}/* 删除确认弹窗 */
.modal-backdrop {position: fixed;top: 0;left: 0;right: 0;bottom: 0;background-color: rgba(0,0,0,0.5);display: flex;align-items: center;justify-content: center;z-index: 100;padding: 0 16px;
}.delete-modal {background-color: white;border-radius: 12px;width: 100%;max-width: 300px;padding: 24px;box-shadow: 0 4px 20px rgba(0,0,0,0.15);
}.modal-title {margin: 0 0 12px 0;font-size: 18px;font-weight: 500;text-align: center;
}.modal-message {margin: 0 0 24px 0;font-size: 14px;color: #666;text-align: center;line-height: 1.5;
}.modal-buttons {display: flex;gap: 12px;
}.modal-btn {flex: 1;padding: 10px;border-radius: 6px;font-size: 16px;font-weight: 500;cursor: pointer;transition: opacity 0.2s ease;border: none;
}.modal-btn:active {opacity: 0.8;
}.cancel-btn {background-color: #f0f0f0;color: #333;
}.confirm-btn {background-color: #f44336;color: white;
}/* 适配小屏幕 */
@media (max-width: 320px) {.app-title {font-size: 16px;}.note-title {font-size: 15px;}.note-content {font-size: 13px;}.detail-title {font-size: 20px;}
}
</style>
http://www.dtcms.com/a/540182.html

相关文章:

  • 03_全连接神经网络
  • 生成式AI重塑教学生态:理论基础、核心特征与伦理边界
  • html5手机网站调用微信分享wordpress缩略图加载慢
  • 动环监控:数据中心机房的“智慧守护者”
  • 5.6对象
  • 生命线与黑箱:LIME和Anchor作为两种事后可解释性分析
  • VMware安装配置CentOS 7
  • 链表算法题
  • 织梦制作wap网站高端网站开发建设
  • 网站建设公司销售经理职责全网最大的精品网站
  • 怎么做公司网站推广cms网站开发教程
  • 解决 OpenSSL 3.6.0 在 macOS 上 Conan 构建失败的链接错误
  • metaRTC7 mac/ios编程指南
  • Go语言-->Goroutine 详细解释
  • 船舶终端数据采集与监管平台一体化方案
  • 2025年10月28日Github流行趋势
  • 《红色脉络:一部PLMN在中国的演进史诗 (1G-6G)》 第14篇 | 6G畅想:通感一体、AI内生——下一代网络的愿景与挑战
  • 「Java EE开发指南」如何用MyEclipse设置Java项目依赖项属性?
  • 输电线路防外破在线监测装置是什么
  • MTK5G旗舰系列——天玑9500/9400/9300/9200/9000在AI和处理器性能、DDR频率及UFS的深度对比分析
  • 平板做网站服务器wordpress在线直播插件
  • 前端Jquery,后端Java实现预览Word、Excel、PPT,pdf等文档
  • 华为910B服务器(搭载昇腾Ascend 910B AI 芯片的AI服务器查看服务器终端信息
  • Spring JDBC实战:参数处理与嵌入式数据库
  • 图片转PPT:用Java高效处理PowerPoint的秘籍
  • Custom Animations for PPT (PowerPoint)
  • 沈阳网站哪家做的好做视频网站设备需求
  • 【数据工程】16. Notions of Time in Stream Processing
  • AOI在传统汽车制造领域中的应用
  • 搭建网站复杂吗微信公众号怎么做链接网站