vue全家桶实现笔记本功能
Posted timmer
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue全家桶实现笔记本功能相关的知识,希望对你有一定的参考价值。
一个通过vue实现的练手小项目,数据保存和导出通过node进行处理
成品截图:
安装vue-cli,webpack:
cnpm install webpack -g
cnpm install vue-cli -g
通过vue-cli搭建项目:
需要使用vuex管理数据,添加store文件夹,最终目录结构:
----vue_notes
|--components
|--router
|--store
编辑入口文件 main.js
//引入Vue import Vue from \'vue\' //引入vuere-source,该组件为网络请求组件 import VueResource from "vue-resource" //引入store,vuex对象 import store from \'./store\' //引入入口页面 import App from \'./App\' //使用vue-resource中间件挂载网络请求组件 Vue.use(VueResource); /* 实例化vue项目 */ new Vue({ el: \'#app\', store, ...App })
vuex出口文件 store/index.js
import Vue from \'vue\' import Vuex from \'vuex\' import mutations from \'./mutations\' import actions from \'./actions\' import getters from \'./getters\' //添加vuex中间件 Vue.use(Vuex); //使用数据结构 const state = { isAllList: true, notes: [], activeNote: {}, } export default new Vuex.Store({ state, mutations, actions, getters, })
vuex方法声明 /store/mutation-types.js
//修改日记列表状态,是否查看全部 export const changeListStatus = "changeListStatus"; //新增日记 export const addNote = "addNote"; //编辑当前日记 export const editNote = "editNote"; //删除所选日记 export const deleteNote = "deleteNote"; //切换收藏状态 export const toggleFavorite = "toggleFavorite"; //切换当前日记 export const setActiveNote = "setActiveNote"; //初始化日记数据 export const initNotes = \'initNotes\'; //编辑当前日记标题 export const eidtNoteTitle = \'eidtNoteTitle\';
store/mutations.js 声明方法
import * as types from \'./mutation-types\' export default { [types.changeListStatus](state, bool) { state.isAllList = bool; }, [types.addNote](state) { const newNote = { text: \'New note\', title: \'New\', favorite: !state.isAllList, _rm: Math.random(), } state.notes.push(newNote); state.activeNote = newNote; }, [types.editNote](state, text) { state.activeNote.text = text; }, [types.deleteNote](state) { let rm = state.activeNote[\'_rm\']; let index = state.notes.findIndex(function(v, i) { if(rm == v[\'_rm\']) return true; return false; }); if(index >= 0) state.notes.splice(index, 1); state.activeNote = state.notes[0] || {}; }, [types.toggleFavorite](state) { state.activeNote[\'favorite\'] = !state.activeNote[\'favorite\'] }, [types.setActiveNote](state, note) { state.activeNote = note; }, [types.initNotes](state, notes) { for(let i of notes.notes) { if(i._rm === notes.activeNote._rm) { notes.activeNote = i; break; } } state.isAllList = notes.isAllList; state.notes = notes.notes; state.activeNote = notes.activeNote; window.state = state; }, [types.eidtNoteTitle](state, title) { state.activeNote.title = title; } }
/store/actions.js 声明异步方法
import * as types from \'./mutation-types\' export default { [types.changeListStatus]({ commit }, { bool }) { commit(\'changeListStatus\', bool); }, [types.addNote]({ commit }) { commit(\'addNote\'); }, [types.editNote]({ commit }, { text }) { commit(\'editNote\', text); }, [types.deleteNote]({ commit }) { commit(\'deleteNote\'); }, [types.toggleFavorite]({ commit }) { commit(\'toggleFavorite\'); }, [types.setActiveNote]({ commit }, { note }) { commit(\'setActiveNote\', note); }, [types.initNotes]({ commit }, { notes }) { commit(\'initNotes\', notes); }, [types.eidtNoteTitle]({ commit }, { title }) { commit(\'eidtNoteTitle\', title); } }
/store/getters.js 声明获取数据方法
export default { favoriteNotes: state => { return state.notes.filter((v, i) => v[\'favorite\']); } }
App.vue 外层组件
<template> <div id="app"> <toolbar></toolbar> <notes-list></notes-list> <notes-editor></notes-editor> </div> </template> <script> import Vue from \'vue\' import { mapActions, mapState } from \'vuex\' import Toolbar from "./components/Toolbar.vue"; import NotesList from "./components/NotesList.vue"; import NotesEditor from "./components/NotesEditor.vue"; export default { name: \'app\', components: { Toolbar, NotesList, NotesEditor }, computed: { //引入vuex状态生成对应计算属性 ...mapState({ isAllList: state => state.isAllList, notes: state => state.notes, activeNote: state => state.activeNote, }) }, //钩子方法,创建dom之前抓取数据进行初始化 beforeCreate() { this.$http.get(\'/test.action\').then(function(res) { return res.json(); }).then((data) => this.initNotes({notes: data})); }, methods: { //引入vuex initNotes方法 ...mapActions([\'initNotes\']), save() { this.$http.post(\'/save.action\', this.$store.state).then((res) => res.json()).then((data) => console.log(data)); } }, //监听数据变化,如果出现变化,重新保存到后台 watch: { \'isAllList\': function() { return this.save; }, \'notes\': function() { return this.save; }, \'activeNote\': { handler: function() { return this.save; }, deep: true }, } } </script>
Toolbar.vue 操作日记按钮组件
<template> <div id="toolbar"> <i class="glyphicon glyphicon-plus" @click="addNote"></i> <i class="glyphicon glyphicon-star" :class="{starred: activeNote[\'favorite\']}" @click="toggleFavorite"></i> <i class="glyphicon glyphicon-remove" @click="deleteNote"></i> <i class="glyphicon glyphicon-save" @click="down"></i> </div> </template> <script> import { mapState, mapActions } from "Vuex"; export default { computed: { ...mapState({ activeNote: state => state.activeNote, }) }, methods: { ...mapActions({ addNote: \'addNote\', toggleFavorite: \'toggleFavorite\', deleteNote: \'deleteNote\' }), down() { window.open(\'/down.action\', \'_blank\'); } } } </script>
NodeList.vue 日记列表组件
<template> <div id="notes-list"> <div id="list-header"> <h2>Notes | coligo</h2> <div class="btn-group btn-group-justified" role="group"> <div class="btn-group" role="group"> <button type="button" class="btn btn-default" :class="{active:isAllList}" @click="changeStatus(\'isAll\')"> All Notes </button> </div> <div class="btn-group" role="group"> <button type="button" class="btn btn-default" :class="{active:!isAllList}" @click="changeStatus(\'isFavorite\')"> Favorites </button> </div> </div> </div> <div id="container"> <div class="list-group"> <a class="list-group-item" href="javascript:;" v-for="(v,k) in list" :class="{active: v[\'_rm\']==activeNote[\'_rm\']}" @click="setActiveNote({note:v})"> <h4 class="list-group-item-heading">{{ v[\'title\'].length>10 ? v[\'title\'].substring(0,10) + "..." : v[\'title\'] }}</h4> </a> </div> </div> </div> </template> <script> import { mapState, mapGetters, mapActions } from "Vuex"; export default { data() { return { list: [], } }, computed: { ...mapState({ isAllList: state => state.isAllList, notes: state => state.notes, activeNote: state => state.activeNote, }), ...mapGetters({ favoriteNotes: \'favoriteNotes\', }), }, methods: { ...mapActions({ setActiveNote: \'setActiveNote\', changeListStatus: \'changeListStatus\', }), changeStatus(s) { if(s == \'isAll\') { this.changeListStatus({ bool: true }); } else if(s == \'isFavorite\') { this.changeListStatus({ bool: false }); } }, changeList() { if(this.isAllList) { this.$data.list = this.notes; } else { this.$data.list = this.favoriteNotes; } }, }, watch: { notes: function() { this.changeList(); }, isAllList: function() { this.changeList(); }, }, mounted: function() { //数据更新重新更新this.$data中数据再执行dom更新 this.$nextTick(function() { this.$data.list = this.notes; }); } } </script> <style> </style>
NotesEditor 编辑框组件
<template> <div id="note-editor"> <input type="text" v-model="textTitle" @change="eidtNoteTitle({title: textTitle})" /> <textarea class="form-control" v-model="textVal" @change="editNote({text: textVal})"></textarea> </div> </template> <script> import { mapState, mapActions } from "Vuex"; export default { data() { return { textVal: "", textTitle: "" } }, computed: { ...mapState({ activeNote: state => state.activeNote, }) }, methods: { ...mapActions({ editNote: \'editNote\', eidtNoteTitle: \'eidtNoteTitle\' }), }, watch: { activeNote: function() { this.$data.textVal = this.activeNote[\'text\']; this.$data.textTitle = this.activeNote[\'title\']; }, } } </script>
服务端功能,服务端文件build/dev-server.js
//引入文件操作模块 var fs = require(\'fs\'); //post解码模块 var bodyParser = require(\'body-parser\'); // 创建 application/x-www-form-urlencoded 编码解析 var urlencodedParser = bodyParser.urlencoded({ extended: false }); //使用中间件解码 app.use(bodyParser.json()); app.use(urlencodedParser); //查询数据 app.all(\'/test.action\', function(req, res) { fs.readFile(\'./static/data/data.json\', \'utf-8\', function(err, data) { res.json(JSON.parse(data)); }) }) //保存数据 app.all(\'/save.action\', function(req, res) { fs.writeFile(\'./static/data/data.json\', JSON.stringify(req.body, null, \'\\t\'), function(err) { if(err) { console.log(err); res.json({satus: 400}); } else { res.json({satus: 200}); } }) }) //保存功能,将json文件读取解析为txt文件,然后发送到前端下载 app.all(\'/down.action\', function(req, res) { fs.readFile(\'./static/data/data.json\', \'utf-8\', function(err, data) { if(err) { res.json({status: 500}); } else { let string = []; let jsonData = JSON.parse(data); for(let i of jsonData.notes) { string.push(`##${i.title}##\\r\\n${i.text}`) } fs.writeFile(\'./static/data/down.txt\', string.join(`\\r\\n******************************************************\\r\\n`), function(err) { if(err) { res.json({status: 500}); } else { res.download(\'./static/data/down.txt\', \'notes.txt\'); } }) } }) })
代码已上传至github
以上是关于vue全家桶实现笔记本功能的主要内容,如果未能解决你的问题,请参考以下文章
万字长文 Vue全家桶从入门到实战,超详细笔记整理 ( 三 ) (建议收藏)