基于vue2.0+vuex+localStorage开发的本地记事本示例


Posted in Javascript onFebruary 28, 2017

本文采用vue2.0+vuex+localStorage+sass+webpack,实现一个本地存储的记事本。兼容PC端和移动端。

实现效果

基于vue2.0+vuex+localStorage开发的本地记事本示例

功能说明

  • 支持回车添加事件
  • 支持事件状态切换
    • 添加事件 -> 进入未完成列表
    • 未完成 -> 已完成(勾选checkbox)
    • 未完成 -> 已取消(点击取消按钮)
    • 已完成 -> 未完成(取消勾选checkbox)
    • 已取消 -> 未完成(点击恢复按钮)
  • 支持控制台打印所有事件数据
  • 支持筛选事件
  • 支持编辑事件
  • 支持删除事件
  • 支持清空所有事件
  • 支持本地化存储
  • 支持折叠面板

项目笔记

本项目是使用vue-cli脚手架生成的项目,项目代码可以到我的github上clone下来。clone下来之后可进入文件目录

// 执行
npm install
// 安装依赖完成之后再执行
npm run dev
// 即可在本地开启 http://localhost:8080 访问该项目

// 如果 node-sass 安装失败,可使用 cnpm 安装
npm install cnpm -g --registry=https://registry.npm.taobao.org
cnpm -v       // 查看cnpm版本号确认安装成功
cnpm install node-sass -D

//安装成功后再看看是否可以正确运行了

一、目录结构

|——notepad/
|  |——build/
|  |——confg/
|  |——node_modules/
|  |——src/
|  |  |——assets/
|  |  |——components/
|  |  |  |——add_event.vue    //添加事件组件
|  |  |  |——dialog.vue     //弹出框组件
|  |  |  |——event_table.vue   //表格组件
|  |  |  |——header.vue     //头部组件
|  |  |  |——tools.vue      //工具栏组件
|  |  |——store/         //存放vuex代码
|  |  |  |——actions.js     //vuex的action文件
|  |  |  |——index.js      //vuex核心代码
|  |  |——App.vue         //父组件
|  |  |——main.js         //入口文件
|  |——static/
|  |——.babelrc
|  |——.editorconfig
|  |——.gitgnore
|  |——index.html
|  |——package.json
|  |——README.md

二、主要难点

1.折叠面板

难点:点击折叠面板title,要动画实现sliderUp和sliderDown,但是div高度auto,使用transition: height .3s无效。

解决方法:点击时候获取div高度值,赋值给style.height,然后再改变高度为0,这样transition才会生效。

代码如下:

<template>
  <div id="app">
    <div class="event-tab" @click="changeCollapse(0,$event)">未完成</div>
    <ul class="event-box" :style="{'height':'auto','display':'block'}">
      <li class="event-list" v-for="value in getToDo">
        <div>{{value.content}}</div>
      </li>
    </ul>
  </div>
</template>
<script>
  export default {
    data(){
      return {
        collapse:[
          {
            show: true,           // show == true, 表示当前折叠面板显示
            contentHeight: 'auto'      // contentHeight, 存储当前折叠面板高度
          }
        ]
      }
    },
    methods:{
      changeCollapse(num,event){         // 根据折叠面板当前状态进行显示或折叠
        if(this.collapse[num].show){
          this.closeCollapse(num,event);
          this.collapse[num].show = false;
        }else{
          this.openCollapse(num,event);
          this.collapse[num].show = true;
        }
      },
      closeCollapse(num,event){          // closeCollapse,关闭折叠面板
        const ulElement = event.currentTarget.nextElementSibling;
        ulElement.style.height = ulElement.offsetHeight + 'px';
        this.collapse[num].contentHeight = ulElement.offsetHeight;
        setTimeout(function () {
          ulElement.style.height = '0px';
          setTimeout(function () {
            ulElement.style.display = 'none';
          },300)
        },10)

      },
      openCollapse(num,event){          // openCollapse,显示折叠面板
        const ulElement = event.currentTarget.nextElementSibling,
            self = this;
        ulElement.style.display = 'block';
        setTimeout(function () {
          ulElement.style.height = self.collapse[num].contentHeight + 'px';
          setTimeout(function () {
            ulElement.style.height = 'auto';
          },300)
        },10)
      }
    }
  }
</script>
<style lang="scss" rel="stylesheet/scss">
  ul.event-box{
    list-style: none;
    overflow: hidden;
    border:{
      left:1px solid #eee;
      right:1px solid #eee;
    }
    transition: height .3s;             // transition,添加折叠或显示时的动画效果
  }
</style>

2.切换状态

难点:在不同的状态间切换,实时地把事件在不同状态列表中显示出来

解决方法:利用vuex进行状态管理,把所有事件和状态存储在store对象中,在组件中通过计算属性获得事件,因此就有了实时性。

代码如下:

// store/index.js
import Vue from 'vue';
import Vuex from 'vuex';
import * as actions from './actions.js';
Vue.use(Vuex);
const state = {
  event: [] // event,用来存储所有事件
}
const mutations = {
  EVENTDONE(states,obj){ // EVENTDONE,用来修改事件的状态为已完成
    for (let i = 0; i < states.event.length; i++) {
      if (states.event[i].id === obj.id) {
        states.event[i].type = 2;  // type == 2,表示状态为已完成
        break;
      }
    }
  }
}
export default new Vuex.Store({
  state,
  actions,
  mutations
})

// store/actions.js
export const eventdone = ({ commit }, param) =>{
  commit('EVENTDONE',{id: param});
}

// App.vue
<template>
  <div id="app">
    <ul class="event-box">
      <li class="event-list" v-for="value in getToDo">
        <input type="checkbox" @click="moveToDone(value.id,$event)">
        <div>{{value.content}}</div>
      </li>
    </ul>
  </div>
</template>
<script>
  export default {
    computed:{
      getToDo(){  // getToDo,实时获取状态为未完成的事件
        return this.$store.state.event.filter(function(d){
          if(d.type === 1){  // type == 1,表示状态为未完成
            return d;
          }
        });
      }
    },
    methods:{
      moveToDone(id,event){ // moveToDone,选中checkbox将事件移至已完成
        this.$store.dispatch('eventdone',id);
      }
    }
  }
</script>

3.本地存储

知识点:localStorage是HTML5提供的一种在客户端存储数据的新方法,没有时间限制,第二天、第二周或下一年之后,数据依然可用。

用法:

1)存储数据:localStorage.setItem(item, value)

2)获取数据:localStorage.getItem(item)

3)移除数据:localStorage.removeItem(item)

代码如下:

// store/index.js
const LocalEvent = function(item){     // 定义一个本地存储的构造函数
  this.get = function () {        // 拿数据
    return JSON.parse(localStorage.getItem(item));
  }
  this.set = function (obj) {       // 存数据
    localStorage.setItem(item,JSON.stringify(obj));
  }
  this.clear = function () {       // 删数据
    localStorage.removeItem(item);
  }
}
const local = new LocalEvent('lx_notepad'); // 创建一个本地存储的事例
const state = local.get() || {
  event: [],
  count: 0
}
const mutations = {
  ADDEVENT(states,obj){          // ADDEVENT,添加新的事件,并存储到localStorage里
    states.count++;
    obj.items.id = states.count;
    states.event.unshift(obj.items);
    local.set(states);
  }
}

4.父子组件间的通讯

知识点:组件实例的作用域是孤立的。这意味着不能并且不应该在子组件的模板内直接引用父组件的数据。

1)父组件可以使用 props 把数据传给子组件。

2)子组件可以使用 $emit 触发父组件的自定义事件。

代码如下:

// App.vue
<template>
  <div id="app">
    // 通过 isShow、msg 把数据传个子组件,监听自定义事件cancel、sure。
    <n-dialog :is-show="dialog" :msg="tips" @cancel="dialog = false" @sure="sureDialog"></n-dialog>
  </div>
</template>
<script>
  import nDialog from './components/dialog.vue';
  export default {
    data(){
      return {
        dialog: true,
        tips: '清除后无法恢复,确认清除吗?'
      }
    },
    components: {
      nDialog
    },
    methods:{
      sureDialog(){
        this.$store.dispatch('clearevent');
        this.dialog = false;
      }
    }
  }
</script>

// dialog.vue
<template>
  <div class="dialog" :class="{'dialog-show':isShow}">
    <div class="dialog-wrapper">
      <div class="dialog-content">
        {{msg}}
      </div>
      <div class="dialog-btns">
        <button type="button" class="cancel-btn" @click="cancelEvent">取消</button>
        <button type="button" class="sure-btn" @click="sureEvent">确定</button>
      </div>
    </div>
  </div>
</template>
<script>
  export default {
    props:['isShow','msg'], // 通过 props 属性获得父组件传递过来的数据
    methods: {
      cancelEvent(){
        this.$emit('cancel'); // 取消按钮触发父组件的 cancel 自定义事件
      },
      sureEvent(){
        this.$emit('sure');  // 确认按钮触发父组件的 sure 自定义事件
      }
    }
  }
</script>

5.筛选功能

功能描述:可根据 类型 和 关键词 进行筛选

知识点:在返回所有事件的计算属性上,使用过滤器( filter ),进行对 type 和 content 的筛选,返回符合条件的事件。

代码如下:

<script>
  export default {
    data: function(){
      return {
        screen_type: 0,                           // 筛选类型,0 表示不筛选
        screen_title: '',                          // 筛选关键词,'' 表示不筛选
      }
    },
    computed:{
      notapad(){
        var self = this;
        return self.$store.state.event.filter(function(d){         // 使用过滤器
          if(self.screen_type !== 0 && self.screen_title === ''){     // 只筛选类型
            if( d.type === self.screen_type ){
              return d;
            }
          }else if(self.screen_type !== 0 && self.screen_title !== ''){  // 筛选类型和关键词
            if( d.type === self.screen_type && d.content.indexOf(self.screen_title) !== -1){
              return d;
            }
          }else if(self.screen_type === 0 && self.screen_title !== ''){  // 只筛选关键词
            if(d.content.indexOf(self.screen_title) !== -1){
              return d;
            }
          }else{                             // 不进行筛选
            return d;
          }
        });
      }
    }
  }  
</script>

总结

虽然只是做了个小小的记事本,但是我感觉收获还是很大的,很多知识点掌握得更加的牢固。这个记事本只做了一个页面,就没有用vue-router,路由也是vue里很强大的功能。

做这个记事本的初衷,是因为在工作中,我都会把最近要做的事情给记在本子上,完成之后就会打钩,所以想把这个给放到电脑上去实现。

demo下载地址:notepad_3water.rar

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
封装好的省市地区联动控件附下载
Aug 13 Javascript
js中的eventType事件及其浏览器支持性介绍
Nov 29 Javascript
JS通过分析userAgent属性来判断浏览器的类型及版本
Mar 28 Javascript
了不起的node.js读书笔记之node.js中的特性
Dec 22 Javascript
原生js实现的贪吃蛇网页版游戏完整实例
May 18 Javascript
sso跨域写cookie的一段js脚本(推荐)
May 25 Javascript
JavaScript基础心法 深浅拷贝(浅拷贝和深拷贝)
Mar 05 Javascript
vue使用jsonp抓取qq音乐数据的方法
Jun 21 Javascript
JavaScript遍历数组和对象的元素简单操作示例
Jul 09 Javascript
Vue父子传递实例讲解
Feb 14 Javascript
详细分析JavaScript中的深浅拷贝
Sep 17 Javascript
微信小程序tab左右滑动切换功能的实现代码
Feb 08 Javascript
原生js仿淘宝网商品放大镜效果
Feb 28 #Javascript
原生js实现可拖拽效果
Feb 28 #Javascript
javascript 面向对象function详解及实例代码
Feb 28 #Javascript
正则验证小数点后面只能有两位数的方法
Feb 28 #Javascript
原生js实现鼠标跟随效果
Feb 28 #Javascript
canvas实现简易的圆环进度条效果
Feb 28 #Javascript
JS实现的tab切换选项卡效果示例
Feb 28 #Javascript
You might like
基于Zend的Captcha机制的应用
2013/05/02 PHP
一个严格的PHP Session会话超时时间设置方法
2014/06/10 PHP
destoon整合ucenter后注册页面不跳转的解决方法
2014/06/21 PHP
php生成html文件方法总结
2014/12/01 PHP
PHP中使用Imagick读取pdf并生成png缩略图实例
2015/01/21 PHP
js的hasownproperty使用示例
2014/03/02 Javascript
Mac OS X 系统下安装和部署Egret引擎开发环境
2014/09/03 Javascript
Javascript实现禁止输入中文或英文的例子
2014/12/09 Javascript
jquery实现手风琴效果
2015/11/20 Javascript
jQuery源码解读之extend()与工具方法、实例方法详解
2017/03/30 jQuery
Angular CLI在Angular项目中如何使用scss详解
2018/04/10 Javascript
微信小程序wx.navigateTo中events属性实现页面间通信传值,数据同步
2019/07/13 Javascript
Python操作列表的常用方法分享
2014/02/13 Python
Python3生成手写体数字方法
2018/01/30 Python
python去掉空白行的多种实现代码
2018/03/19 Python
python修改list中所有元素类型的三种方法
2018/04/09 Python
python 3.6.2 安装配置方法图文教程
2018/09/18 Python
Python中安装easy_install的方法
2018/11/18 Python
Python3匿名函数lambda介绍与使用示例
2019/05/18 Python
django中SMTP发送邮件配置详解
2019/07/19 Python
浅谈Python 递归算法指归
2019/08/22 Python
解决Atom安装Hydrogen无法运行python3的问题
2019/08/28 Python
pyecharts绘制中国2020肺炎疫情地图的实例代码
2020/02/12 Python
TensorFlow2.1.0最新版本安装详细教程
2020/04/08 Python
详解pycharm配置python解释器的问题
2020/10/15 Python
Ellos丹麦:时尚和服装在线
2016/09/19 全球购物
优衣库美国官网:UNIQLO美国
2018/04/14 全球购物
面向对象编程OOP的优点
2013/01/22 面试题
世界经理人咨询有限公司面试
2014/09/23 面试题
一份报关员的职业规划范文
2014/01/08 职场文书
培训班主持词
2014/03/28 职场文书
安全月活动总结
2014/05/05 职场文书
给校长的建议书作文300字
2015/09/14 职场文书
修改MySQL的数据库引擎为INNODB的方法
2021/05/26 MySQL
详解Java实现数据结构之并查集
2021/06/23 Java/Android
在 HTML 页面中使用 React的场景分析
2022/01/18 Javascript