文章目录
- 1. 项目介绍
- 2. 开发环境准备
- 3. 设计应用界面
- 4. 创建Vue实例和数据模型
- 5. 实现记事本功能
- 5.1 添加新记事项
- 5.2 删除记事项
- 5.3 清空所有记事
- 6. 添加样式
- 7. 功能扩展:显示创建时间
- 8. 功能扩展:记事项搜索
- 9. 完整代码
- 10. Vue知识点解析
- 10.1 数据绑定
- 10.2 列表渲染
- 10.3 条件渲染
- 10.4 事件处理
- 10.5 计算属性
- 10.6 侦听器
- 10.7 生命周期钩子
- 11. 功能扩展思路
- 12. 总结
1. 项目介绍
本教程将带领新手开发一个基于Vue.js的记事本应用,不需要使用脚手架,仅通过引入Vue.js库即可完成。通过这个项目,你将学习Vue的基础知识,包括:
- 数据绑定和响应式原理
- 列表渲染
- 事件处理
- 计算属性
- 条件渲染
- 本地存储
完成后的记事本应用具有以下功能:
- 显示所有记事项
- 添加新记事项
- 删除单个记事项
- 显示记事项总数
- 一键清空所有记事项
- 数据持久化(浏览器本地存储)
2. 开发环境准备
对于初学者,我们采用最简单的方式搭建环境:通过CDN引入Vue.js。
创建一个基本的HTML文件结构:
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Vue记事本</title><!-- 引入Vue.js --><script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script><!-- 添加一些基本样式 --><style>/* 样式稍后添加 */</style>
</head>
<body><div id="app"><!-- 这里将是我们的应用 --></div><script>// Vue代码将写在这里</script>
</body>
</html>
3. 设计应用界面
我们设计一个简洁的记事本界面,包含以下部分:
- 标题
- 输入框和添加按钮
- 记事项列表(每项包含内容和删除按钮)
- 底部统计栏(显示数量和清空按钮)
更新HTML结构:
<div id="app"><div class="notepad"><h1>{{ title }}</h1><!-- 添加记事项 --><div class="add-note"><input type="text" v-model="newNote" @keyup.enter="addNote" placeholder="请输入记事内容..."><button @click="addNote">添加</button></div><!-- 记事项列表 --><ul class="note-list"><li v-for="(note, index) in notes" :key="index"><span>{{ note.text }}</span><button @click="deleteNote(index)">删除</button></li><li v-if="notes.length === 0" class="empty-note">暂无记事项</li></ul><!-- 底部统计 --><div class="note-stats" v-show="notes.length > 0"><span>共 {{ notes.length }} 条记事</span><button @click="clearAll">清空记事</button></div></div>
</div>
4. 创建Vue实例和数据模型
在script标签中,我们创建Vue实例并定义数据模型:
new Vue({el: '#app',data: {title: 'Vue记事本',newNote: '', // 用于存储新输入的记事内容notes: [], // 用于存储所有记事项},// 在实例创建时从本地存储加载数据created() {// 从localStorage读取保存的笔记const savedNotes = JSON.parse(localStorage.getItem('vue-notes') || '[]');this.notes = savedNotes;},// 方法将在下一步定义methods: {// 方法将在这里实现},// 侦听器:当notes变化时保存到本地存储watch: {notes: {handler(newNotes) {// 将笔记保存到localStoragelocalStorage.setItem('vue-notes', JSON.stringify(newNotes));},deep: true}}
});
5. 实现记事本功能
5.1 添加新记事项
首先,我们实现添加记事项的功能。在methods对象中添加addNote方法:
methods: {// 添加新记事项addNote() {// 去除首尾空格const text = this.newNote.trim();// 如果输入为空,则不添加if (text === '') {return;}// 创建新记事项对象const note = {text: text,createdAt: new Date().toLocaleString() // 添加创建时间};// 将新记事项添加到数组this.notes.push(note);// 清空输入框this.newNote = '';},// 其他方法将在下面实现
}
5.2 删除记事项
接下来,实现删除单个记事项的功能:
// 添加到methods对象中
deleteNote(index) {// 确认删除if (confirm('确定要删除这条记事吗?')) {// 使用splice方法从数组中删除指定索引的记事项this.notes.splice(index, 1);}
}
5.3 清空所有记事
最后,实现清空所有记事项的功能:
// 添加到methods对象中
clearAll() {// 确认清空if (confirm('确定要清空所有记事吗?')) {// 将记事项数组清空this.notes = [];}
}
6. 添加样式
为了让应用看起来更美观,我们添加一些CSS样式:
/* 将这些样式添加到<style>标签中 */
body {font-family: 'Microsoft YaHei', sans-serif;background-color: #f5f5f5;padding: 20px;
}.notepad {max-width: 600px;margin: 0 auto;background-color: white;padding: 20px;border-radius: 8px;box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}h1 {text-align: center;color: #333;margin-top: 0;border-bottom: 1px solid #eee;padding-bottom: 10px;
}.add-note {display: flex;margin-bottom: 20px;
}.add-note input {flex: 1;padding: 10px;border: 1px solid #ddd;border-radius: 4px 0 0 4px;outline: none;
}.add-note button {padding: 10px 15px;background-color: #4CAF50;color: white;border: none;border-radius: 0 4px 4px 0;cursor: pointer;
}.note-list {list-style: none;padding: 0;margin: 0;
}.note-list li {display: flex;justify-content: space-between;align-items: center;padding: 10px;border-bottom: 1px solid #eee;
}.note-list li:hover {background-color: #f9f9f9;
}.note-list li span {flex: 1;
}.note-list li button {padding: 5px 10px;background-color: #f44336;color: white;border: none;border-radius: 4px;cursor: pointer;
}.empty-note {text-align: center;color: #999;padding: 20px 0;
}.note-stats {display: flex;justify-content: space-between;align-items: center;margin-top: 20px;padding-top: 10px;border-top: 1px solid #eee;
}.note-stats button {padding: 5px 10px;background-color: #ff9800;color: white;border: none;border-radius: 4px;cursor: pointer;
}button:hover {opacity: 0.9;
}button:active {opacity: 0.8;
}
7. 功能扩展:显示创建时间
现在让我们扩展记事项,显示每条记事的创建时间。修改列表渲染部分:
<!-- 更新记事项列表 -->
<ul class="note-list"><li v-for="(note, index) in notes" :key="index"><div class="note-content"><span class="note-text">{{ note.text }}</span><span class="note-time">{{ note.createdAt }}</span></div><button @click="deleteNote(index)">删除</button></li><li v-if="notes.length === 0" class="empty-note">暂无记事项</li>
</ul>
添加对应的样式:
.note-content {flex: 1;
}.note-text {display: block;margin-bottom: 5px;
}.note-time {display: block;font-size: 12px;color: #999;
}
8. 功能扩展:记事项搜索
让我们增加一个搜索功能,帮助用户快速找到特定记事项:
在HTML中添加搜索框:
<!-- 在添加记事项的下方添加 -->
<div class="search-note"><input type="text" v-model="searchText" placeholder="搜索记事...">
</div>
在Vue实例中添加数据和计算属性:
data: {// 添加到现有data对象中searchText: '', // 用于存储搜索文本
},
computed: {// 过滤后的记事项列表filteredNotes() {const searchText = this.searchText.trim().toLowerCase();if (!searchText) {return this.notes;}// 返回包含搜索文本的记事项return this.notes.filter(note => note.text.toLowerCase().includes(searchText));}
}
然后,修改列表渲染,使用过滤后的记事项:
<!-- 更新记事项列表,使用filteredNotes替代notes -->
<ul class="note-list"><li v-for="(note, index) in filteredNotes" :key="index"><div class="note-content"><span class="note-text">{{ note.text }}</span><span class="note-time">{{ note.createdAt }}</span></div><button @click="deleteNote(notes.indexOf(note))">删除</button></li><li v-if="filteredNotes.length === 0" class="empty-note">{{ notes.length === 0 ? '暂无记事项' : '没有匹配的记事项' }}</li>
</ul>
添加搜索框样式:
.search-note {margin-bottom: 20px;
}.search-note input {width: 100%;padding: 10px;border: 1px solid #ddd;border-radius: 4px;outline: none;box-sizing: border-box;
}
9. 完整代码
以下是完整的HTML文件代码:
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Vue记事本</title><script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script><style>body {font-family: 'Microsoft YaHei', sans-serif;background-color: #f5f5f5;padding: 20px;}.notepad {max-width: 600px;margin: 0 auto;background-color: white;padding: 20px;border-radius: 8px;box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);}h1 {text-align: center;color: #333;margin-top: 0;border-bottom: 1px solid #eee;padding-bottom: 10px;}.add-note {display: flex;margin-bottom: 20px;}.add-note input {flex: 1;padding: 10px;border: 1px solid #ddd;border-radius: 4px 0 0 4px;outline: none;}.add-note button {padding: 10px 15px;background-color: #4CAF50;color: white;border: none;border-radius: 0 4px 4px 0;cursor: pointer;}.search-note {margin-bottom: 20px;}.search-note input {width: 100%;padding: 10px;border: 1px solid #ddd;border-radius: 4px;outline: none;box-sizing: border-box;}.note-list {list-style: none;padding: 0;margin: 0;}.note-list li {display: flex;justify-content: space-between;align-items: center;padding: 10px;border-bottom: 1px solid #eee;}.note-list li:hover {background-color: #f9f9f9;}.note-content {flex: 1;}.note-text {display: block;margin-bottom: 5px;}.note-time {display: block;font-size: 12px;color: #999;}.note-list li button {padding: 5px 10px;background-color: #f44336;color: white;border: none;border-radius: 4px;cursor: pointer;}.empty-note {text-align: center;color: #999;padding: 20px 0;}.note-stats {display: flex;justify-content: space-between;align-items: center;margin-top: 20px;padding-top: 10px;border-top: 1px solid #eee;}.note-stats button {padding: 5px 10px;background-color: #ff9800;color: white;border: none;border-radius: 4px;cursor: pointer;}button:hover {opacity: 0.9;}button:active {opacity: 0.8;}</style>
</head>
<body><div id="app"><div class="notepad"><h1>{{ title }}</h1><!-- 添加记事项 --><div class="add-note"><input type="text" v-model="newNote" @keyup.enter="addNote" placeholder="请输入记事内容..."><button @click="addNote">添加</button></div><!-- 搜索记事项 --><div class="search-note"><input type="text" v-model="searchText" placeholder="搜索记事..."></div><!-- 记事项列表 --><ul class="note-list"><li v-for="(note, index) in filteredNotes" :key="index"><div class="note-content"><span class="note-text">{{ note.text }}</span><span class="note-time">{{ note.createdAt }}</span></div><button @click="deleteNote(notes.indexOf(note))">删除</button></li><li v-if="filteredNotes.length === 0" class="empty-note">{{ notes.length === 0 ? '暂无记事项' : '没有匹配的记事项' }}</li></ul><!-- 底部统计 --><div class="note-stats" v-show="notes.length > 0"><span>共 {{ notes.length }} 条记事</span><button @click="clearAll">清空记事</button></div></div></div><script>new Vue({el: '#app',data: {title: 'Vue记事本',newNote: '',notes: [],searchText: ''},computed: {// 过滤后的记事项列表filteredNotes() {const searchText = this.searchText.trim().toLowerCase();if (!searchText) {return this.notes;}// 返回包含搜索文本的记事项return this.notes.filter(note => note.text.toLowerCase().includes(searchText));}},created() {// 从localStorage读取保存的笔记const savedNotes = JSON.parse(localStorage.getItem('vue-notes') || '[]');this.notes = savedNotes;},methods: {// 添加新记事项addNote() {// 去除首尾空格const text = this.newNote.trim();// 如果输入为空,则不添加if (text === '') {return;}// 创建新记事项对象const note = {text: text,createdAt: new Date().toLocaleString()};// 将新记事项添加到数组this.notes.push(note);// 清空输入框this.newNote = '';},// 删除记事项deleteNote(index) {// 确认删除if (confirm('确定要删除这条记事吗?')) {// 使用splice方法从数组中删除指定索引的记事项this.notes.splice(index, 1);}},// 清空所有记事clearAll() {// 确认清空if (confirm('确定要清空所有记事吗?')) {// 将记事项数组清空this.notes = [];}}},watch: {// 监听notes变化,保存到localStoragenotes: {handler(newNotes) {localStorage.setItem('vue-notes', JSON.stringify(newNotes));},deep: true}}});</script>
</body>
</html>
10. Vue知识点解析
通过这个项目,我们学习了以下Vue的知识点:
10.1 数据绑定
v-model:用于表单输入和应用数据之间的双向绑定- 插值表达式
{{ }}:显示变量内容
10.2 列表渲染
v-for:遍历数组渲染列表项:key:为列表项提供唯一标识符,帮助Vue优化渲染
10.3 条件渲染
v-if/v-else:根据条件决定是否渲染元素v-show:根据条件切换元素的显示和隐藏(CSS的display属性)
10.4 事件处理
@click(即v-on:click):监听点击事件@keyup.enter:监听按下回车键事件
10.5 计算属性
computed:基于响应式依赖进行缓存,只有依赖更新时才重新计算
10.6 侦听器
watch:监听数据变化,执行相应操作deep选项:深度监听对象内部变化immediate选项:组件创建时立即执行一次
10.7 生命周期钩子
created:实例创建后执行代码(如从本地存储加载数据)
11. 功能扩展思路
以下是一些可以进一步扩展记事本功能的思路:
-
优先级标记:允许用户为记事项设置不同的优先级,并可按优先级排序。
-
分类功能:添加分类标签,对记事项进行分组管理。
-
编辑功能:允许用户编辑已添加的记事项。
-
完成状态:添加复选框,标记记事项为已完成或未完成状态。
-
拖拽排序:使用拖拽功能调整记事项的顺序。
-
导入/导出:支持将记事数据导出为文件,或从文件导入记事。
-
日期筛选:按照创建日期筛选记事项。
-
数据统计:显示更多统计信息,如已完成/未完成的任务数量。
-
夜间模式:添加切换夜间/日间模式的功能。
-
云同步:结合后端服务,实现记事内容的云端同步。
12. 总结
通过本教程,我们使用Vue.js构建了一个功能完整的记事本应用。虽然这是一个小型应用,但它涵盖了Vue的核心概念和实践技巧。作为新手,你可以通过这个项目了解Vue的数据驱动、组件化和响应式的特性,为进一步学习Vue打下基础。
要深入学习Vue,建议接下来了解Vue CLI、Vue Router、Vuex等进阶工具和概念,并尝试使用组件化的方式重构此应用。
