介绍
印象笔记是一家非常受欢迎的记笔记工具,实现类似的页面设计可以让我们的应用更加用户友好。Vue 提供了很多方便的工具,让我们能够快速地构建现代化的应用程序。在这篇文章中,我们将探讨 Vue 中如何实现仿印象笔记的页面设计。
技术栈
在开始之前,我们需要先介绍一些技术栈:
Vue:一个用于构建用户界面的渐进式框架
Vuex:一个用于 Vue 应用程序的状态管理模式
Vue Router:一个用于 Vue 应用程序的路由管理器
ElementUI:一个基于 Vue 的组件库,提供了丰富的 UI 组件和功能
Moment.js:一个 JavaScript 日期处理库,用于格式化日期和时间
页面结构
印象笔记的页面结构可分为三个部分:侧边栏、笔记列表和笔记详情。我们将使用 Vue、Vuex 和 Vue Router 来实现这个结构。
侧边栏
我们将侧边栏放在应用程序的左侧,用于管理笔记本和标签。
// Sidebar.vue
<template>
<div class="sidebar">
<div class="sidebar-header">
<img src="./assets/logo.png" alt="logo">
<h1>我的笔记</h1>
</div>
<div class="sidebar-body">
<ul class="sidebar-nav">
<li v-for="notebook in notebooks" :key="notebook.id">
<router-link :to="'/notebook/' + notebook.id">
{{ notebook.name }}
</router-link>
</li>
</ul>
<hr>
<h2>标签</h2>
<ul class="sidebar-nav">
<li v-for="tag in tags" :key="tag.id">
<router-link :to="'/tag/' + tag.id">
{{ tag.name }}
</router-link>
</li>
</ul>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
export default {
computed: {
...mapGetters(['notebooks', 'tags'])
}
};
</script>
<style scoped>
.sidebar {
width: 200px;
height: 100%;
background-color: #f7f7f7;
display: flex;
flex-direction: column;
}
.sidebar-header {
padding: 20px;
border-bottom: 1px solid #e7e7e7;
display: flex;
align-items: center;
}
.sidebar-header img {
margin-right: 10px;
width: 40px;
height: 40px;
}
.sidebar-header h1 {
font-size: 18px;
margin: 0;
}
.sidebar-body {
flex: 1;
padding: 20px;
overflow-y: auto;
}
.sidebar-nav {
list-style: none;
margin: 0;
padding: 0;
}
.sidebar-nav li {
margin: 10px 0;
}
</style>
在上面的代码中,我们使用了 Vuex 的 mapGetters 辅助函数来获取笔记本和标签的列表。
笔记列表
笔记列表位于侧边栏下方,用于显示笔记本或标签下的所有笔记。
// NoteList.vue
<template>
<div class="note-list">
<div class="note-list-header">
<h2>{{ title }}</h2>
</div>
<div class="note-list-body">
<div v-if="loading" class="note-list-loading">
加载中...
</div>
<div v-if="notes.length">
<ul class="note-list-items">
<li v-for="note in notes" :key="note.id">
<router-link :to="'/note/' + note.id">
<h3>{{ note.title }}</h3>
<div v-html="note.body"></div>
<p><strong>修改时间:</strong>{{ note.updatedAt }}</p>
</router-link>
</li>
</ul>
</div>
<div v-else-if="error" class="note-list-error">
加载出错,错误信息:{{ error }}
</div>
<div v-else class="note-list-empty">
没有笔记
</div>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import moment from 'moment';
export default {
props: ['type', 'id'],
computed: {
...mapGetters(['notes', 'loading', 'error']),
title() {
if (this.type === 'notebook') {
const notebook = this.notebooks.find(notebook => notebook.id === this.id);
return notebook ? notebook.name : '未知笔记本';
} else if (this.type === 'tag') {
const tag = this.tags.find(tag => tag.id === this.id);
return tag ? tag.name : '未知标签';
} else {
return '';
}
},
filteredNotes() {
if (this.type === 'notebook') {
return this.notes.filter(note => note.notebookId === this.id);
} else if (this.type === 'tag') {
return this.notes.filter(note => note.tags.includes(this.id));
} else {
return [];
}
}
},
filters: {
formatDate(value, format = 'YYYY-MM-DD HH:mm:ss') {
return moment(value).format(format);
}
}
};
</script>
<style scoped>
.note-list {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.note-list-header {
padding: 20px;
border-bottom: 1px solid #e7e7e7;
}
.note-list-header h2 {
margin: 0;
font-size: 18px;
}
.note-list-body {
flex: 1;
padding: 20px;
overflow-y: auto;
}
.note-list-loading,
.note-list-error,
.note-list-empty {
text-align: center;
}
.note-list-items {
list-style: none;
margin: 0;
padding: 0;
}
.note-list-items li {
margin: 20px 0;
}
.note-list-items h3 {
font-size: 18px;
margin: 0;
}
.note-list-items p {
font-size: 12px;
margin: 10px 0;
}
.note-list-items p strong {
font-weight: 600;
}
</style>
在上面的代码中,我们使用了 props 接收父组件传递的笔记本或标签的 ID 和类型。然后,我们使用 Vuex 的 mapGetters 辅助函数获取笔记列表、加载状态和错误信息。在 computed 属性中,我们定义了一个 title 方法返回标题,一个 filteredNotes 方法返回过滤后的笔记列表。在 filters 中,我们定义了 formatDate 方法来格式化日期。
笔记详情
笔记详情位于笔记列表的右侧,用于显示选中的笔记的详细信息。
// NoteDetail.vue
<template>
<div class="note-detail">
<div class="note-detail-header">
<h1>{{ note.title }}</h1>
<p><strong>创建时间:</strong>{{ note.createdAt | formatDate }}</p>
<p><strong>修改时间:</strong>{{ note.updatedAt | formatDate }}</p>
</div>
<div v-html="note.body" class="note-detail-body"></div>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import moment from 'moment';
export default {
computed: {
...mapGetters(['note']),
},
filters: {
formatDate(value, format = 'YYYY-MM-DD HH:mm:ss') {
return moment(value).format(format);
}
}
};
</script>
<style scoped>
.note-detail {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.note-detail-header {
padding: 20px;
border-bottom: 1px solid #e7e7e7;
}
.note-detail-header h1 {
margin: 0;
font-weight: 600;
font-size: 24px;
}
.note-detail-header p {
font-size: 12px;
margin: 10px 0;
}
.note-detail-header p strong {
font-weight: 600;
}
.note-detail-body {
flex: 1;
padding: 20px;
overflow-y: auto;
}
</style>
在上面的代码中,我们使用了 Vuex 的 mapGetters 辅助函数获取选中的笔记。在 filters 中,我们定义了 formatDate 方法来格式化日期。
应用程序
现在,我们已经将侧边栏、笔记列表和笔记详情都创建好了,下面是如何将它们组合到一起的。
// App.vue
<template>
<div id="app">
<sidebar />
<div class="main">
<router-view/>
</div>
</div>
</template>
<script>
import Sidebar from './components/Sidebar.vue';
export default {
name: 'App',
components: {
Sidebar
}
};
</script>
<style scoped>
#app {
height: 100%;
display: flex;
}
.main {
flex: 1;
height: 100%;
overflow-y: auto;
}
</style>
在上面代码中,我们在 App.vue 中放置了 Sidebar 组件,并在 .main div 中使用了
// router.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import NoteList from './components/NoteList.vue';
import NoteDetail from './components/NoteDetail.vue';
Vue.use(VueRouter);
const routes = [
{ path: '/', redirect: '/notebook/1' },
{ path: '/notebook/:id', component: NoteList, props: { type: 'notebook' } },
{ path: '/tag/:id', component: NoteList, props: { type: 'tag' } },
{ path: '/note/:id', component: NoteDetail },
];
const router = new VueRouter({
routes,
});
export default router;
在上面的代码中,我们定义了三个路由:一个用于显示笔记本下的笔记,一个用于显示标签下的笔记,一个用于显示笔记详情。我们使用了 props 属性传递了笔记本或标签的 ID 和类型。
总结
在本文中,我们学习了如何使用 Vue、Vuex 和 Vue Router 实现仿印象笔记的页面设计。我们创建了侧边栏、笔记列表和笔记详情三个组件,并在 App.vue 中使用了这些组件。最后,我们定义了路由表以将组件集成到应用程序中。