纯vue实现笔记系统
前言
最近研究了一个笔记记录系统,然后突然想到一个问题,我该如何才能只用前端就实现笔记的记录系统?经过这两天的研究将其做出来了,接下来将分享实现的过程
✨✨✨✨✨✨✨✨✨✨
项目演示
在我的项目中,是可以适配移动端,以及电脑端的,跟着编写代码在两个地方运行完全没有问题,首先我以移动端的页面进行演示
🎈🎈🎈🎈🎈🎈🎈🎈
打开项目会看到保存的笔记
❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️
点击右上角的+号可以新增编辑笔记
🎈🎈🎈🎈🎈🎈🎈🎈🎈🎈🎈
进行编辑,可添加文字,图片,表格
❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️
点击完成可以保存笔记
🎈🎈🎈🎈🎈🎈🎈🎈🎈🎈🎈
当新建多个笔记可以筛选
点右上角放大镜筛选
❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️
演示电脑版样式
🏷️🏷️🏷️🏷️🏷️🏷️🏷️🏷️🏷️🏷️🏷️
实现功能
在我的项目实现了基础的笔记记录功能主要有如下
- 笔记展示
- 笔记编辑
- 笔记新增
- 笔记筛选
- 笔记修改
- 笔记添加文本,图片,表格
- 样式适配
- 笔记回退,还原
- 文本样式修改,富文本
🔶🔶🔶🔶🔶🔶🔶🔶🔶🔶🔶🔶
使用框架
- element-ui
- quill富文本
- indexDB
逻辑实现
项目搭建
使用指令
vue create 项目名
或者
vue ui
打开创建项目的ui界面
创建vue2
项目
ps:如果提示不是内部命令信息提示,就需要安装vue组件
命令行输入:
npm install -g vue
npm install -g @vue/cli
✒️✒️✒️✒️✒️✒️✒️✒️✒️✒️✒️✒️✒️
依赖安装
npm i element-ui S
npm i quill
npm i quill-better-table
npm i quill-delta
npm i quill-table
npm i quill-table-ui
npm i vue-router@3.0.1
main.js
import Vue from 'vue'
import App from './App.vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import 'quill/dist/quill.snow.css'
import router from "./router/index"Vue.config.productionTip = false
Vue.use(ElementUI)
new Vue({router,render: h => h(App),
}).$mount('#app')
App.vue
<template><div id="app"><router-view/></div>
</template><script>export default {name: 'App'
}
</script><style>
#app {font-family: Avenir, Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-align: center;color: #2c3e50;position: absolute;width: 100%;height: 100%;overflow-y: hidden;
}
</style>
🎧🎧🎧🎧🎧🎧🎧🎧🎧🎧🎧🎧
新建quill封装组件
建立一个
QuillEditor.vue
文件
代码如下:
<template><keep-alive><div class="editor-container"><div class="quillEditor"></div></div></keep-alive>
</template>
<script>
import Quill from 'quill'
import 'quill/dist/quill.snow.css'const titleConfig = {'ql-bold': '加粗','ql-color': '颜色','ql-font': '字体','ql-code': '插入代码','ql-italic': '斜体','ql-link': '添加链接','ql-background': '颜色','ql-size': '字体大小','ql-strike': '删除线','ql-script': '上标/下标','ql-underline': '下划线','ql-blockquote': '引用','ql-header': '标题','ql-indent': '缩进','ql-list': '列表','ql-align': '文本对齐','ql-direction': '文本方向','ql-code-block': '代码块','ql-formula': '公式','ql-image': '图片','ql-video': '视频','ql-clean': '清除字体样式','ql-upload': '文件','ql-table': '插入表格','ql-table-insert-row': '插入行','ql-table-insert-column': '插入列','ql-table-delete-row': '删除行','ql-table-delete-column': '删除列'
}
export default {name: 'quillEditor',props: {value: Object},data() {return {quill: null,options: {theme: 'snow',modules: {toolbar: {container: [['bold', 'italic', 'underline', 'strike'],[{header: 1}, {header: 2}],[{list: 'ordered'}, {list: 'bullet'}],[{indent: '-1'}, {indent: '+1'}],[{color: []}, {background: []}],[{font: []}],[{align: []}],['clean'],[{table: 'TD'},{'table-insert-row': 'TIR'},{'table-insert-column': 'TIC'},{'table-delete-row': 'TDR'},{'table-delete-column': 'TDC'}]],handlers: {table: function (val) {console.log(val)this.quill.getModule('table').insertTable(2, 3)},'table-insert-row': function () {this.quill.getModule('table').insertRowBelow()},'table-insert-column': function () {this.quill.getModule('table').insertColumnRight()},'table-delete-row': function () {this.quill.getModule('table').deleteRow()},'table-delete-column': function () {this.quill.getModule('table').deleteColumn()}}},table: true},placeholder: ''}}},methods: {addQuillTitle() {const oToolBar = document.querySelector('.ql-toolbar')const aButton = oToolBar.querySelectorAll('button')const aSelect = oToolBar.querySelectorAll('select')aButton.forEach(function (item) {if (item.className === 'ql-script') {item.value === 'sub' ? (item.title = '下标') : (item.title = '上标')} else if (item.className === 'ql-indent') {item.value === '+1' ? (item.title = '向右缩进') : (item.title = '向左缩进')} else {item.title = titleConfig[item.classList[0]]}})aSelect.forEach(function (item) {item.parentNode.title = titleConfig[item.classList[0]]})},getContentData() {return this.quill.getContents()},getQuillInstance() {return this.quill;}},mounted() {const dom = this.$el.querySelector('.quillEditor')this.quill = new Quill(dom, this.options)this.quill.on('text-change', () => {this.$emit('contentData', this.quill.root.innerHTML)})this.$el.querySelector('.ql-table-insert-row').innerHTML = `<svg t="1591862376726" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6306" width="18" height="200"><path d="M500.8 604.779L267.307 371.392l-45.227 45.27 278.741 278.613L779.307 416.66l-45.248-45.248z" p-id="6307"></path></svg>`this.$el.querySelector('.ql-table-insert-column').innerHTML = `<svg t="1591862238963" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6509" width="18" height="200"><path d="M593.450667 512.128L360.064 278.613333l45.290667-45.226666 278.613333 278.762666L405.333333 790.613333l-45.226666-45.269333z" p-id="6510"></path></svg>`this.$el.querySelector('.ql-table-delete-row').innerHTML = `<svg t="1591862253524" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6632" width="18" height="200"><path d="M500.8 461.909333L267.306667 695.296l-45.226667-45.269333 278.741333-278.613334L779.306667 650.026667l-45.248 45.226666z" p-id="6633"></path></svg>`this.$el.querySelector('.ql-table-delete-column').innerHTML = `<svg t="1591862261059" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6755" width="18" height="200"><path d="M641.28 278.613333l-45.226667-45.226666-278.634666 278.762666 278.613333 278.485334 45.248-45.269334-233.365333-233.237333z" p-id="6756"></path></svg>`this.addQuillTitle()},activated() {this.quill.setContents({})}
}
</script>
<style scoped>
.quillEditor {width: auto; /* 允许宽度根据内容自适应 */display: inline-block; /* 让宽度根据内容自适应 */
}.quillEditor .ql-editor {width: 100%; /* 确保编辑器内容区域宽度为 100% */
}.quillEditor .ql-editor table {width: 100%; /* 确保表格宽度自适应容器宽度 */
}.quillEditor .ql-editor table {width: max-content; /* 根据表格内容的宽度来调整宽度 */
}/* 模态框背景 */
.image-modal {position: fixed;top: 0;left: 0;width: 100%;height: 100%;background: rgba(0, 0, 0, 0.8);display: flex;justify-content: center;align-items: center;z-index: 1000;
}/* 放大图片样式 */
.large-image {max-width: 90%;max-height: 90%;
}/* 关闭按钮样式 */
.close-button {position: absolute;top: 10px;right: 10px;font-size: 24px;color: white;cursor: pointer;
}
</style>
✏️✏️✏️✏️✏️✏️✏️✏️✏️✏️✏️✏️✏️
新建indexDB.js工具类
export default class IndexedDBUtil {constructor(dbName, storeName) {this.dbName = dbName;this.storeName = storeName;this.db = null;this.initDB();}// 打开并初始化数据库initDB() {return new Promise((resolve, reject) => {const request = indexedDB.open(this.dbName, 1);request.onupgradeneeded = event => {this.db = event.target.result;if (!this.db.objectStoreNames.contains(this.storeName)) {const objectStore = this.db.createObjectStore(this.storeName, { keyPath: 'id', autoIncrement: true });objectStore.createIndex('name', 'name', { unique: false });}};request.onsuccess = event => {this.db = event.target.result;resolve();};request.onerror = event => {console.error('打开数据库失败:', event.target.error);reject(event.target.error);};});}// 增加记录add(data) {return this.initDB().then(() => {return new Promise((resolve, reject) => {const transaction = this.db.transaction([this.storeName], 'readwrite');const objectStore = transaction.objectStore(this.storeName);const request = objectStore.add(data);request.onsuccess = () => resolve(request.result);request.onerror = () => reject(request.error);});});}// 根据 ID 获取记录getById(id) {return this.initDB().then(() => {return new Promise((resolve, reject) => {const transaction = this.db.transaction([this.storeName]);const objectStore = transaction.objectStore(this.storeName);const request = objectStore.get(id);request.onsuccess = () => {if (request.result) {resolve(request.result);} else {console.warn(`未找到 ID 为 ${id} 的记录`); // 输出警告信息resolve(null); // No result found}};request.onerror = () => {console.error('获取记录失败:', request.error); // 输出错误信息reject(request.error);};});});}// 获取所有记录getAll() {return this.initDB().then(() => {return new Promise((resolve, reject) => {const transaction = this.db.transaction([this.storeName]);const objectStore = transaction.objectStore(this.storeName);const request = objectStore.getAll();request.onsuccess = () => resolve(request.result);request.onerror = () => reject(request.error);});});}// 根据 ID 更新记录update(data) {return this.initDB().then(() => {return new Promise((resolve, reject) => {const transaction = this.db.transaction([this.storeName], 'readwrite');const objectStore = transaction.objectStore(this.storeName);const request = objectStore.put(data);request.onsuccess = () => resolve(request.result);request.onerror = () => reject(request.error);});});}// 根据 ID 删除记录delete(id) {return this.initDB().then(() => {return new Promise((resolve, reject) => {const transaction = this.db.transaction([this.storeName], 'readwrite');const objectStore = transaction.objectStore(this.storeName);const request = objectStore.delete(id);request.onsuccess = () => resolve();request.onerror = () => reject(request.error);});});}// 清空对象存储中的所有记录clearAll() {return this.initDB().then(() => {return new Promise((resolve, reject) => {const transaction = this.db.transaction([this.storeName], 'readwrite');const objectStore = transaction.objectStore(this.storeName);const request = objectStore.clear();request.onsuccess = () => resolve();request.onerror = () => reject(request.error);});});}// 删除整个数据库deleteDatabase() {return new Promise((resolve, reject) => {const request = indexedDB.deleteDatabase(this.dbName);request.onsuccess = () => resolve();request.onerror = () => reject(request.error);request.onblocked = () => console.warn('删除数据库请求被阻塞');});}
}
🔔🔔🔔🔔🔔🔔🔔🔔🔔🔔🔔🔔
新建笔记入口
新建文件Note.vue
<template><div class="note-page"><!-- 上部分 --><div class="header"><div class="title">简易笔记</div><div class="actions"><el-button icon="el-icon-search" circle @click="showSearchDialog = true"></el-button><el-button icon="el-icon-plus" circle @click="addNote"></el-button></div></div><!-- 中间内容区 --><div class="content"><div v-if="filteredNotes.length != 0"><el-card v-for="note in filteredNotes" :key="note.id" class="note-card"><div class="note-content"><div class="note-main" @click="editNote(note)"><h3 class="note-title">{{ note.title }}</h3><p class="note-summary">{{ note.summary }}</p><p class="note-time">{{ note.date }}</p></div><div class="note-delete"><el-button type="danger" icon="el-icon-delete" @click="deleteNote(note)" class="delete-button"></el-button></div></div></el-card></div><div v-else class="note-no-content">暂未新建笔记</div></div><!-- 下部分菜单栏 --><div class="footer"><el-menu mode="horizontal" class="footer-menu" :default-active="currentMenuItem"><el-menu-item index="1">笔记</el-menu-item><el-menu-item index="2">我的</el-menu-item></el-menu></div><!-- 弹出层 --><el-dialogtitle="检索笔记":visible.sync="showSearchDialog"width="100%":fullscreen="false"class="search-dialog":before-close="handleClose"><div class="dialog-content"><div class="input-container"><el-inputv-model="searchQuery"placeholder="请输入标题关键字"clearable@input="filterNotes"></el-input></div> <div class="button-container"><el-button type="primary" @click="showSearchDialog = false">确认</el-button></div></div></el-dialog></div>
</template>
<script>
import IndexedDBUtil from "@/utils/IndexDB";export default {name: 'noteApp',data() {return {currentMenuItem: '1',notes: [],showSearchDialog: false,searchQuery: '',filteredNotes: [],dbUtil: null, // IndexedDB 工具类实例};},created() {this.dbUtil = new IndexedDBUtil('NotesDatabase', 'NotesStore');this.getAllNote()},methods: {filterNotes() {if (this.searchQuery.trim() === '') {this.filteredNotes = this.notes;} else {const query = this.searchQuery.toLowerCase();this.filteredNotes = this.notes.filter(note =>note.title.toLowerCase().includes(query));}},safeSubstring(str, start, end) {// 检查起始位置和结束位置是否有效if (start < 0 || end < 0 || start >= str.length) {return ''; // 返回空字符串}// 如果结束位置超出字符串长度,调整结束位置if (end > str.length) {end = str.length;}return str.substring(start, end);},deleteNote(note) {this.$confirm('确认删除?', '确认信息', {type: 'warning',confirmButtonText: '删除',cancelButtonText: '取消',center: true}).then(() => {this.deleteNoteById(note)this.getAllNote();}).catch(action => {console.log("取消删除", action)});console.log('笔记', note)},deleteNoteById(note) {console.log('需要删除笔记:', note)this.dbUtil.delete(note.id)},handleClose(done) {this.showSearchDialog = false;done();},addNote() {this.$router.push({ path: "/noteAdd2" })},getAllNote() {this.dbUtil.getAll().then(result => {console.log('所有数据', result);if (result) {for (let i = 0; i < result.length; i ++) {let obj = JSON.parse(result[i].delta)if (obj && obj.insert) {result[i].summary = this.safeSubstring(obj.insert, 0, 10)}}this.notes = result}}).catch(error => {console.error('获取所有数据失败', error);});},editNote(note) {this.$router.push({ path: '/noteAdd2', query: { id: note.id } });// this.$router.push({// path: "/noteAdd2",// params: {// id: note.id// }// })}},watch: {notes: 'filterNotes',searchQuery: 'filterNotes',},mounted() {this.filteredNotes = this.notes; // 初始化时显示所有笔记},
};
</script>
<style scoped>
.note-page {display: flex;flex-direction: column;height: 100vh;overflow: hidden; /* 避免整个页面滚动 */
}.header, .footer {background-color: #f5f5f5;padding: 10px;box-shadow: 0 1px 5px rgba(0, 0, 0, 0.1);
}.header {display: flex;justify-content: space-between;align-items: center;
}.title {font-size: 18px;font-weight: bold;
}.actions el-button {margin-left: 10px;
}.content {flex: 1;padding: 10px;overflow-y: auto; /* 允许内部滚动 */
}.note-card {margin-bottom: 10px;
}.note-content {display: flex;justify-content: space-between;align-items: center;
}note-no-content {font-weight: bold;
}.note-main {flex: 0 0 80%; /* 主内容区占80%宽度 */
}.note-delete {flex: 0 0 20%; /* 删除区占20%宽度 */display: flex;justify-content: center; /* 水平居中 */align-items: center; /* 垂直居中 */
}.delete-button {width: 60px; /* 根据需要调整按钮大小 */height: 40px; /* 根据需要调整按钮大小 */
}.note-title {font-size: 16px;font-weight: bold;
}.note-summary {margin: 5px 0;
}.note-time {font-size: 12px;color: #888;
}.footer {background-color: #fff;padding: 10px;
}.footer-menu {text-align: center;
}.footer-menu .el-menu-item {line-height: 40px;
}/* 弹出层内部容器样式 */
.search-dialog .dialog-content {display: flex; /* 使用Flex布局 */align-items: center; /* 垂直居中 */
}/* 输入框样式 */
.search-dialog .input-container {flex: 0 0 80%; /* 输入框占80%宽度 */
}/* 按钮样式 */
.search-dialog .button-container {flex: 0 0 20%; /* 按钮占20%宽度 */
}/* 确保按钮填满其容器宽度 */
.search-dialog .el-button {width: 100%;
}
</style>
🎁🎁🎁🎁🎁🎁🎁🎁🎁🎁🎁🎁🎁
新建笔记编辑文件
新建NoteAdd.vue
<template><div class="note-add-page"><!-- 上部分 --><div class="header"><el-button class="back-button" icon="el-icon-arrow-left" @click="goBack"></el-button><div class="title">编辑笔记</div><el-button class="finish-button" type="primary" @click="finishNote" :disabled="noteTitle.length == 0">完成</el-button></div><!-- 中间部分编辑区 --><div class="editor-container"><el-inputv-model="noteTitle"placeholder="请输入标题"class="title-input"></el-input><div class="content-editor"><QuillEditor class='quillEditorChild' ref='quillEditor' v-model="contentArea" @contentData="change($event)"></QuillEditor></div></div><!-- 下部分区 --><div class="bottom-toolbar"><el-button icon="el-icon-back" @click="undo" class="toolbar-button"></el-button><el-button icon="el-icon-right" @click="redo" class="toolbar-button"></el-button><el-buttonicon="el-icon-plus"@click="toggleAddMenu"class="toolbar-button add-button"ref="addButton"></el-button></div><!-- 弹出层 --><el-dialog:visible.sync="addMenuVisible"width="80vw":show-close="false"custom-class="custom-add-menu":modal="false"><div class="add-menu-scroll-container"><div class="add-menu-content"><!-- 图片--><div class="add-menu-item"><div class="icon-container"><el-button @click="insertImage" class="icon-button"><i class="el-icon-picture"></i></el-button></div><div class="text-container">插入图片</div></div><div class="add-menu-item"><div class="icon-container"><el-button class="icon-button"><i class="el-icon-microphone"></i></el-button></div><div class="text-container">占位功能1</div></div><div class="add-menu-item"><div class="icon-container"><el-button class="icon-button"><i class="el-icon-tickets"></i></el-button></div><div class="text-container">占位功能2</div></div></div></div></el-dialog></div>
</template>
<script>
import QuillEditor from "@/components/QuillEditor";
import Quill from "quill";
import IndexedDBUtil from "@/utils/IndexDB";
export default {name: 'noteAdd',components: {QuillEditor},data() {return {noteId: 0,noteTitle: '',contentArea: null,addMenuVisible: false,dbUtil: null, // IndexedDB 工具类实例};},mounted() {this.loadEditNote()},created() {this.dbUtil = new IndexedDBUtil('NotesDatabase', 'NotesStore');this.noteId = Number(this.$route.query.id)console.log('noteId', this.noteId)},methods: {goBack() {this.$router.push('/');},undo() {const quill = this.$refs.quillEditor.getQuillInstance();if (quill) {quill.history.undo();}},redo() {const quill = this.$refs.quillEditor.getQuillInstance();if (quill) {quill.history.redo();}},formattedDate() {const year = new Date().getFullYear();const month = String(new Date().getMonth() + 1).padStart(2, '0'); // 月份从 0 开始,所以需要 +1const day = String(new Date().getDate()).padStart(2, '0'); // 日期是从 1 开始的return `${year}-${month}-${day}`; // 返回格式化后的日期},async finishNote() {const quill = this.$refs.quillEditor.getQuillInstance();// 获取 Delta 格式内容var delta = quill.getContents();// 获取 HTML 格式内容var html = quill.root.innerHTML;if (this.noteId) {var updateNote = {id: this.noteId,title: this.noteTitle,delta: JSON.stringify(delta),html: html,date: this.formattedDate()};try {const result = await this.dbUtil.update(updateNote);console.log('笔记已更新', result)} catch (error) {console.error('更新笔记失败:', error)}} else {var insertNote = {title: this.noteTitle,delta: JSON.stringify(delta),html: html,date: this.formattedDate()};console.log(insertNote)try {// 保存 note 对象到 IndexedDBconst result = await this.dbUtil.add(insertNote);console.log('笔记已保存:', result);} catch (error) {console.error('保存笔记失败:', error);}}this.goBack()},toggleAddMenu() {this.addMenuVisible = !this.addMenuVisible;},insertImage() {const quill = this.$refs.quillEditor.getQuillInstance();const range = quill.getSelection();let index = range ? range.index : quill.getLength();// 创建一个隐藏的文件选择对话框const input = document.createElement('input');input.type = 'file';input.accept = 'image/*'; // 只允许选择图片文件input.addEventListener('change', (event) => {const file = event.target.files[0];if (file) {const reader = new FileReader();reader.onload = (e) => {const imageURL = e.target.result;quill.insertEmbed(index, 'image', imageURL, Quill.sources.USER);};reader.readAsDataURL(file); // 读取文件内容作为 data URL}});input.click(); // 模拟点击文件选择对话框this.addMenuVisible = false;},change(event) {console.log('更新值:', event)},loadContent(content, fileName) {this.noteTitle = fileName.replace('.json','')const quill = this.$refs.quillEditor.getQuillInstance();if (fileName.endsWith('.html') || fileName.endsWith('.htm')) {quill.root.innerHTML = content;} else if (fileName.endsWith('.json')) {let delta = null;if (content) {delta = JSON.parse(content);}quill.setContents(delta);}},loadEditNote() {if (!this.noteId) {return}this.dbUtil.getById(this.noteId).then(res => {if (res) {this.loadContent(res.delta, res.title + ".json")} else {this.$message({message: '笔记加载失败,未能获取到笔记',type: 'warning'});}})},},
};
</script>
<style scoped>
.note-add-page {display: flex;flex-direction: column;height: 100vh;background-color: #fff;
}.header {display: flex;justify-content: space-between;align-items: center;padding: 10px;background-color: #f5f5f5;box-shadow: 0 1px 5px rgba(0, 0, 0, 0.1);height: 10%;
}.title {flex: 1;text-align: center;font-size: 18px;font-weight: bold;
}.finish-button {margin-left: 10px;
}.editor-container {flex: 1;display: flex;flex-direction: column;padding: 10px;overflow-y: auto;height: 80%;
}.title-input {margin-bottom: 10px;
}.content-editor {flex: 1;
}.quill-editor {height: 100%;
}.bottom-toolbar {display: flex;align-items: center;justify-content: space-between;padding: 10px;background-color: #f5f5f5;box-shadow: 0 -1px 5px rgba(0, 0, 0, 0.1);height: 10%;
}.add-menu-scroll-container {display: flex;overflow-x: auto;white-space: nowrap;padding: 10px;
}.add-menu-content {display: flex;align-items: center;
}.add-menu-item {display: flex;flex-direction: column;align-items: center;margin: 0 10px; /* 水平间距 */
}.icon-container {margin-bottom: 4px; /* 图标和文字之间的间距 */
}.text-container {text-align: center;
}/* 自定义弹出层样式 */
.custom-add-menu .el-dialog__header {display: none; /* 隐藏标题栏 */
}.custom-add-menu .el-dialog__body {padding: 0; /* 去掉默认内边距 */
}.custom-add-menu .el-dialog {position: absolute;top: 0;left: 50%;transform: translateX(-50%);margin-top: -10px; /* 根据需要调整与按钮的距离 */box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); /* 添加阴影效果 */
}
.table-controls {position: absolute;z-index: 10;background: white;border: 1px solid #ddd;padding: 10px;border-radius: 5px;
}
.table-control-button {margin: 5px;
}
</style>
🔷🔷🔷🔷🔷🔷🔷🔷🔷🔷🔷🔷🔷🔷
新建router文件
建立一个router文件夹,在其中建立index.js
import Vue from "vue"
import Router from 'vue-router'
import Note from "@/components/Note";
import NoteAdd from "@/components/NoteAdd";
Vue.use(Router)
export default new Router({routes: [{path: '/',redirect: 'note'},{path: "/note",name: "Note",component: Note},{path: "/noteAdd",name: "NoteAdd",component: NoteAdd},]
})
结语
如上就是纯vue实现笔记记录系统的全部逻辑了