前言
Vue 和 Webpack 是前端开发中最常用的两个工具之一,在实际项目中可以说是不可或缺的。本文将通过一个示例,详细介绍 Vue 和 Webpack 的使用以及如何开发一个知识管理系统。
知识管理系统的功能
知识管理系统是一个用于管理自己的学习笔记和知识点的工具。系统可以实现以下功能:
- 用户登录和注册;
- 查看、添加、编辑、删除自己的笔记;
- 查看、添加、编辑、删除自己的知识点;
- 实现搜索功能;
- 数据持久化。
技术栈
我们将使用以下技术栈来开发知识管理系统:
- 前端框架:Vue;
- 脚手架:Vue CLI;
- 打包工具:Webpack;
- 数据库:JSON Server。
安装和配置
安装 Vue CLI
npm install -g vue-cli
创建项目
使用 Vue CLI 创建一个新项目:
vue create knowledge-management-system
项目创建完成后,进入项目目录并启动开发服务器:
cd knowledge-management-system npm run serve
安装依赖
安装以下依赖:
npm install --save axios vue-router json-server npm install --save-dev sass-loader node-sass
目录结构
// javascriptcn.com 代码示例 knowledge-management-system/ ├── public/ │ └── index.html └── src/ ├── assets/ # 静态资源文件夹 ├── components/ # 组件文件夹 ├── router/ # 路由文件夹 ├── store/ # Vuex 文件夹 ├── views/ # 视图文件夹 ├── App.vue └── main.js
实现登录和注册功能
创建登录和注册视图
在 src/views
文件夹下新建 Login.vue
和 Register.vue
文件。
Login.vue
代码如下:
// javascriptcn.com 代码示例 <template> <div> <h1>登录</h1> <form @submit.prevent="login"> <label> 账号: <input type="text" v-model="username" required autofocus> </label> <br> <label> 密码: <input type="password" v-model="password" required> </label> <br> <button type="submit">登录</button> </form> </div> </template> <script> export default { data() { return { username: '', password: '' } }, methods: { login() { // ... } } } </script>
Register.vue
代码如下:
// javascriptcn.com 代码示例 <template> <div> <h1>注册</h1> <form @submit.prevent="register"> <label> 账号: <input type="text" v-model="username" required autofocus> </label> <br> <label> 密码: <input type="password" v-model="password" required> </label> <br> <label> 确认密码: <input type="password" v-model="confirmPassword" required> </label> <br> <button type="submit">注册</button> </form> </div> </template> <script> export default { data() { return { username: '', password: '', confirmPassword: '' } }, methods: { register() { // ... } } } </script>
创建路由
在 src/router
文件夹下新建 index.js
文件,代码如下:
// javascriptcn.com 代码示例 import Vue from 'vue'; import VueRouter from 'vue-router'; import Login from '../views/Login.vue'; import Register from '../views/Register.vue'; Vue.use(VueRouter); const routes = [ { path: '/login', component: Login }, { path: '/register', component: Register } ]; const router = new VueRouter({ mode: 'history', routes }); export default router;
实现登录和注册功能
在 src/store
文件夹下新建 auth.js
文件,代码如下:
// javascriptcn.com 代码示例 import axios from 'axios'; const state = { user: null }; const mutations = { setUser(state, user) { state.user = user; } }; const actions = { async login({ commit }, { username, password }) { const response = await axios.post('http://localhost:3000/login', { username, password }); const user = response.data; commit('setUser', user); return user; }, async register({ commit }, { username, password }) { const response = await axios.post('http://localhost:3000/register', { username, password }); const user = response.data; commit('setUser', user); return user; } }; export default { namespaced: true, state, mutations, actions };
在 src/store/index.js
中引入 auth.js
文件,代码如下:
// javascriptcn.com 代码示例 import Vue from 'vue'; import Vuex from 'vuex'; import auth from './auth'; Vue.use(Vuex); export default new Vuex.Store({ modules: { auth }, state: {}, mutations: {}, actions: {} });
最后,在 src/main.js
文件中引入路由和 Vuex,代码如下:
// javascriptcn.com 代码示例 import Vue from 'vue'; import App from './App.vue'; import router from './router'; import store from './store'; Vue.config.productionTip = false; new Vue({ router, store, render: h => h(App) }).$mount('#app');
这样,我们就实现了登录和注册功能。
实现笔记功能
创建笔记视图
在 src/views
文件夹下新建 Note.vue
文件,代码如下:
// javascriptcn.com 代码示例 <template> <div> <h1>我的笔记</h1> <form @submit.prevent="submit"> <label> 标题: <input type="text" v-model="title" required autofocus> </label> <br> <label> 内容: <textarea v-model="content" required></textarea> </label> <br> <button type="submit">{{ isEdit ? '保存' : '添加' }}</button> <button type="button" @click="cancel">{{ isEdit ? '取消' : '清空' }}</button> </form> <hr> <ul> <li v-for="(note, index) in notes" :key="note.id"> <h2>{{ note.title }}</h2> <button type="button" @click="edit(index)">编辑</button> <button type="button" @click="deleteNote(index)">删除</button> <p>{{ note.content }}</p> </li> </ul> </div> </template> <script> import axios from 'axios'; export default { data() { return { title: '', content: '', notes: [], isEdit: false, index: null }; }, async mounted() { const response = await axios.get('http://localhost:3000/notes'); this.notes = response.data.filter(note => note.user_id === this.$store.state.auth.user.id); }, methods: { async submit() { if (this.isEdit) { const response = await axios.patch(`http://localhost:3000/notes/${this.notes[this.index].id}`, { title: this.title, content: this.content }); this.notes.splice(this.index, 1, response.data); this.isEdit = false; } else { const response = await axios.post('http://localhost:3000/notes', { user_id: this.$store.state.auth.user.id, title: this.title, content: this.content }); this.notes.push(response.data); } this.title = ''; this.content = ''; }, cancel() { this.title = ''; this.content = ''; this.isEdit = false; this.index = null; }, edit(index) { this.title = this.notes[index].title; this.content = this.notes[index].content; this.isEdit = true; this.index = index; }, async deleteNote(index) { await axios.delete(`http://localhost:3000/notes/${this.notes[index].id}`); this.notes.splice(index, 1); } } }; </script>
创建笔记路由
在 src/router/index.js
中添加笔记路由,代码如下:
// javascriptcn.com 代码示例 import Vue from 'vue'; import VueRouter from 'vue-router'; import Login from '../views/Login.vue'; import Register from '../views/Register.vue'; import Note from '../views/Note.vue'; Vue.use(VueRouter); const routes = [ { path: '/login', component: Login }, { path: '/register', component: Register }, { path: '/note', component: Note, meta: { requiresAuth: true } } ]; const router = new VueRouter({ mode: 'history', routes }); router.beforeEach((to, from, next) => { if (to.matched.some(record => record.meta.requiresAuth)) { if (!store.state.auth.user) { next({ path: '/login' }) } else { next() } } else { next() } }) export default router;
创建笔记模块
在 src/store
文件夹下新建 note.js
文件,代码如下:
// javascriptcn.com 代码示例 import axios from 'axios'; const state = { notes: [] }; const mutations = { setNotes(state, notes) { state.notes = notes; } }; const actions = { async fetchNotes({ commit }, userId) { const response = await axios.get('http://localhost:3000/notes'); const notes = response.data.filter(note => note.user_id === userId); commit('setNotes', notes); } }; export default { namespaced: true, state, mutations, actions };
在 src/store/index.js
中引入 note.js
文件,代码如下:
// javascriptcn.com 代码示例 import Vue from 'vue'; import Vuex from 'vuex'; import auth from './auth'; import note from './note'; Vue.use(Vuex); export default new Vuex.Store({ modules: { auth, note }, state: {}, mutations: {}, actions: {} });
这样,我们就实现了笔记功能。
实现知识点功能
创建知识点视图
在 src/views
文件夹下新建 Knowledge.vue
文件,代码如下:
// javascriptcn.com 代码示例 <template> <div> <h1>我的知识点</h1> <form @submit.prevent="submit"> <label> 标题: <input type="text" v-model="title" required autofocus> </label> <br> <label> 内容: <textarea v-model="content" required></textarea> </label> <br> <button type="submit">{{ isEdit ? '保存' : '添加' }}</button> <button type="button" @click="cancel">{{ isEdit ? '取消' : '清空' }}</button> </form> <hr> <ul> <li v-for="(knowledge, index) in knowledgeList" :key="knowledge.id"> <h2>{{ knowledge.title }}</h2> <button type="button" @click="edit(index)">编辑</button> <button type="button" @click="deleteKnowledge(index)">删除</button> <p>{{ knowledge.content }}</p> </li> </ul> </div> </template> <script> import axios from 'axios'; export default { data() { return { title: '', content: '', knowledgeList: [], isEdit: false, index: null }; }, async mounted() { const response = await axios.get('http://localhost:3000/knowledge'); this.knowledgeList = response.data.filter(knowledge => knowledge.user_id === this.$store.state.auth.user.id); }, methods: { async submit() { if (this.isEdit) { const response = await axios.patch(`http://localhost:3000/knowledge/${this.knowledgeList[this.index].id}`, { title: this.title, content: this.content }); this.knowledgeList.splice(this.index, 1, response.data); this.isEdit = false; } else { const response = await axios.post('http://localhost:3000/knowledge', { user_id: this.$store.state.auth.user.id, title: this.title, content: this.content }); this.knowledgeList.push(response.data); } this.title = ''; this.content = ''; }, cancel() { this.title = ''; this.content = ''; this.isEdit = false; this.index = null; }, edit(index) { this.title = this.knowledgeList[index].title; this.content = this.knowledgeList[index].content; this.isEdit = true; this.index = index; }, async deleteKnowledge(index) { await axios.delete(`http://localhost:3000/knowledge/${this.knowledgeList[index].id}`); this.knowledgeList.splice(index, 1); } } }; </script>
创建知识点路由
在 src/router/index.js
中添加知识点路由,代码如下:
// javascriptcn.com 代码示例 import Vue from 'vue'; import VueRouter from 'vue-router'; import Login from '../views/Login.vue'; import Register from '../views/Register.vue'; import Note from '../views/Note.vue'; import Knowledge from '../views/Knowledge.vue'; Vue.use(VueRouter); const routes = [ { path: '/login', component: Login }, { path: '/register', component: Register }, { path: '/note', component: Note, meta: { requiresAuth: true } }, { path: '/knowledge', component: Knowledge, meta: { requiresAuth: true } } ]; const router = new VueRouter({ mode: 'history', routes }); router.beforeEach((to, from, next) => { if (to.matched.some(record => record.meta.requiresAuth)) { if (!store.state.auth.user) { next({ path: '/login' }) } else { next() } } else { next() } }) export default router;
创建知识点模块
在 src/store
文件夹下新建 knowledge.js
文件,代码如下:
// javascriptcn.com 代码示例 import axios from 'axios'; const state = { knowledgeList: [] }; const mutations = { setKnowledgeList(state, knowledgeList) { state.knowledgeList = knowledgeList; } }; const actions = { async fetchKnowledgeList({ commit }, userId) { const response = await axios.get('http://localhost:3000/knowledge'); const knowledgeList = response.data.filter(knowledge => knowledge.user_id === userId); commit('setKnowledgeList', knowledgeList); } }; export default { namespaced: true, state, mutations, actions };
在 src/store/index.js
中引入 knowledge.js
文件,代码如下:
// javascriptcn.com 代码示例 import Vue from 'vue'; import Vuex from 'vuex'; import auth from './auth'; import note from './note'; import knowledge from './knowledge'; Vue.use(Vuex); export default new Vuex.Store({ modules: { auth, note, knowledge }, state: {}, mutations: {}, actions: {} });
这样,我们就实现了知识点功能。
实现搜索功能
创建搜索视图
在 src/views
文件夹下新建 Search.vue
文件,代码如下:
// javascriptcn.com 代码示例 <template> <div> <h1>搜索</h1> <form @submit.prevent="search"> <label> 搜索关键词: <input type="text" v-model="searchKey" required autofocus> </label> <br> <label> 搜索类型: <select v-model="searchType"> <option value="note">笔记</option> <option value="knowledge">知识点</option> </select> </label> <br> <button type="submit">搜索</button> </form> <hr> <ul> <li v-for="(item, index) in list" :key="item.id"> <h2>{{ item.title }}</h2> <button type="button" @click="edit(index)">编辑</button> <button type="button" @click="deleteItem(index)">删除</button> <p>{{ item.content }}</p> </li> </ul> </div> </template> <script> import axios from 'axios'; export default { data() { return { searchKey: '', searchType: 'note', list: [] }; }, async created() { await this.search(); }, methods: { async search() { let response; if (this.searchType === 'note') { response = await axios.get('http://localhost:3000/notes'); this.list = response.data.filter(note => note.user_id === this.$store.state.auth.user.id && note.title.includes(this.searchKey)); } else { response = await axios.get('http://localhost:3000/knowledge'); this.list = response.data.filter(knowledge => knowledge.user_id === this.$store.state.auth.user.id && knowledge.title.includes(this.searchKey)); } }, async edit(index) { const item = this.list[index]; if (this.searchType === 'note') { this.$router.push({ path: '/note', query: { id: item.id } }); } else { this.$router.push({ path: '/knowledge', query: { id: item.id } }); } }, async deleteItem(index) { const id = this.list[index].id; await axios.delete(`http://localhost:3000/${this.searchType}/${id}`); this.list.splice(index, 1); } } }; </script>
创建搜索路由
在 src/router
文件夹下新建 search.js
文件,代码如下:
// javascriptcn.com 代码示例 import Search from '../views/Search.vue'; export default { path: '/search', component: Search, meta: { requiresAuth: true } };
在 src/router/index.js
中引入搜索路由,代码如下:
// javascriptcn.com 代码示例 import Vue from 'vue'; import VueRouter from 'vue-router'; import Login from '../views/Login.vue'; import Register from '../views/Register.vue'; import Note from '../views/Note.vue'; import Knowledge from '../views/Knowledge.vue'; import searchRoute from './search'; Vue.use(VueRouter); const routes = [ { path: '/login', component: Login }, { path: '/register', component: Register }, { path: '/note', component: Note, meta: { requiresAuth: true } }, { path: '/knowledge', component: Knowledge, meta: { requiresAuth: true } } ]; const router = new VueRouter({ mode: 'history', routes }); router.beforeEach((to, from, next) => { if (to.matched.some(record => record.meta.requiresAuth)) { if (!store.state.auth.user) { next({ path: '/login' }) } else { next() } } else { next() } }) router.addRoutes([searchRoute]) export default router;
创建搜索模块
在 src/store
文件夹下新建 search.js
文件,代码如下:
// javascriptcn.com 代码示例 const state = { searchKey: '', searchType: '' }; const mutations = { setSearchKey(state, searchKey) { state.searchKey = searchKey; }, setSearchType(state, searchType) { state.searchType = searchType; } }; export default { namespaced: true, state, mutations };
在 src/main.js
中引入搜索模块,代码如下:
// javascriptcn.com 代码示例 import Vue from 'vue'; import App from './App.vue'; import router from './router'; import store from './store'; import './assets/styles/index.scss'; Vue.config.productionTip = false; new Vue({ router, store, render: h => h(App) }).$mount('#app');
这样,我们就实现了搜索功能。
实现数据持久化
配置 JSON Server
在项目根目录下新建 db.json
文件,代码如下:
// javascriptcn.com 代码示例 { "users": [ { "id": 1, "username": "admin", "password": "123456" } ], "notes": [ ], "knowledge": [ ] }
安装 json-server
:
npm install -g json-server
启动 JSON Server:
json-server --watch db.json --port 3000
可以通过访问 http://localhost:3000/notes
或 http://localhost:3000/knowledge
查看数据。
修改 API 地址
将使用 axios
请求数据,需要在 src/store
中的每个模块中修改 API 地址:
// javascriptcn.com 代码示例 import axios from 'axios'; const API_URL = 'http://localhost:3000'; const state = { notes: [] }; const mutations = { setNotes(state, notes) { state.notes = notes; } }; const actions = { async fetchNotes({ commit }, userId) { const response = await axios.get(`${API_URL}/notes`); const notes = response.data.filter(note => note.user_id === userId); commit('setNotes', notes); } }; export default { namespaced: true, state, mutations, actions };
将 sudo vue-cli-service serve
的方式改成 npm run serve
。
这样,在启动开发服务器时可以修改 API 地址,从而获取到 JSON Server 的数据。
总结
本文主要介绍了 Vue 和 Webpack 的使用以及如何开发一个知识管理系统。通过本项目,可以掌握 Vue 和 Webpack 的使用,以及如何在实际项目中使用这两个工具。同时,也介绍了一些实际开发中常用的技术和方法,如路由、Vuex、axios 等,希望能对前端开发者有所帮助。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/6530fbe87d4982a6eb29010d