zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    获得自动增长的MySQL主键
    HTTP协议状态码的含义
    HttpServletResponse接口
    http header详解
    ORACLE中大数据量查询实现优化
    amqp rabbitMQ docker-composer
    阿里云OSS上传Invalid Object Name错误
    PHP7**幂运算执行顺序
    MySQL join 连表查询索引问题
    Composer改阿里国内镜像
  • 原文地址:https://www.cnblogs.com/timmer/p/6531622.html
Copyright © 2011-2022 走看看