用Vue搭建一个运用盒子(一):todo-list

最近在研讨vue的相干学问,最好的进修要领莫过于本身开辟一个SPA,如许带着题目来进修,提高天然飞速。因而边查边写差不多花了2周写完了一个todo-list,功用不够完整,然则麻雀虽小,却也是五脏俱全,基础功用是可以满足的了。话不多说,直接来看项目吧。

手艺栈

  • vue百口桶(vue、vuex、vue-router)
  • webpack完成打包和热加载
  • ES6
  • UI框架用的是bootstrap
  • rem要领完成适配挪动端
  • localstorage完成数据的保留
  • node和npm(真是零基础啊,npm都是现学现卖的…)

以上。

接下来就是代码剖析了。

一、用vue-cli设置一个项目

这一个步骤没什么好说的,网上教程一大堆,随意找一个照着走就好了。
完成后,你应当有一个项目标文件夹,内里应当有这几个文件:
README.md、build、config、index.html、package.json、src、static
嗯,就如许。

二、装置相干依靠和一堆玩意。

设置vue-router和bootstrap

先装置依靠,敕令行到对应根目录文件夹实行以下敕令(引荐VS code,自带敕令行输入,轻易!)

npm install

稍等片刻完成(假如太慢,推动啊淘宝镜像的cnpm装置)
装置好今后,继承装置:

npm install vuex vue-router bootstrap --save

装置完成后,须要设置以下文件,确保可以运用。
翻开:xx(项目文件夹)-src-main.js
以下:

import Vue from 'vue'
import VueRouter from 'vue-router'

import App from './App'

import 'bootstrap/dist/css/bootstrap.css'

Vue.use(VueRouter)

const routes=[
  {
    path:'/',
    component:Home
  },
  {
    path:'/todolist',
    component:todolist
  }
];

const router=new VueRouter({routes});

/* eslint-disable no-new */

const app=new Vue({
  router,
  el:'#app',
  render:h=>h(App)   //ES6语法 
})

这里设置了vue-router和bootstrap,项目中可以运用了,接着我们还须要设置vuex和jQuery。

设置vuex和jQuery

首先在根目录竖立一个文件夹,命名为vuex,在内里竖立一个store.js文件,
设置以下:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex);

const state={
    
}
const getters={
    
}
const mutations={
   
}

export default new Vuex.Store({
  state,
  getters,
  mutations
})

const是ES6的语法,这里getters,state,mutations都不急着用,先设置好。

设置好store.js,回到main.js继承设置。

增添一些内容:

import Vue from 'vue'
import VueRouter from 'vue-router'
import store from './vuex/store'

import App from './App'
import Home from './components/Home.vue'
import todolist from './components/todolist.vue'

import 'bootstrap/dist/css/bootstrap.css'

Vue.use(VueRouter)

const routes=[
  {
    path:'/',
    component:Home
  },
  {
    path:'/todolist',
    component:todolist
  }
];

const router=new VueRouter({routes});

/* eslint-disable no-new */

const app=new Vue({
  router,
  store,
  el:'#app',
  render:h=>h(App)   //ES6语法 
})

好了,vuex就设置完了。接着我们设置JQuery,由于bootstrap依靠JQuery,所以这里也必需放上去。
老例子,先用npm装置JQuery。

npm install jquery --save

翻开xx-build-webpack-base.conf.js,在module.exports内里增加以下代码:

plugins:[
    new webpack.optimize.CommonsChunkPlugin('common.js'),
    new webpack.ProvidePlugin({
         jQuery: "jquery",
         $: "jquery"
    })
  ]

翻开main.js设置JQuery和bootstrap的动效。
增加一点内容:

import $ from 'jquery'
import 'bootstrap/dist/js/bootstrap.min.js'

OK,至此,一切的前期设置就完成了,可以最先正式的代码誊写了。

三、组件构造和完成

Vue最堡垒的处所就是它的组件式开辟,所以这个头脑是我们在写代码式要时刻注重的,怎样合理的离别本身的组件,是一件很须要思索的事,接下来我将细致引见我的组件内容和完成的功用。

下面是我的组件构造:
在src文件夹里,有一个主组件:app.vue,有一个组件文件夹:conponents,在这内里我放了4个组件,以下:
Home.vue ———— 首页
todolist.vue ———— todolist 运用主页面
sidebar.vue ———— todolist使命列表
editor.vue ———— todolist使命编辑
我会一个个引见功用。

app.vue

在首页里,我们会用bootstrap写一个导航,经由过程vue-router的路由导航到差别的运用。
代码以下:

<template>
  <div id="app">
    <!--nav start-->
    <nav class="navbar navbar-default">
      <div class="container-fluid">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#"><i class="glyphicon glyphicon-home"></i></a>
        </div>
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
          <ul class="nav navbar-nav">
            <li><router-link to="/todolist">Todo List</router-link></li>
            <li><a href="#">开辟中...</a></li>
          </ul>
        </div><!-- /.navbar-collapse -->
      </div><!-- /.container-fluid -->
    </nav>
    <!--nav end-->

    <!--content-->
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'app',
  data(){
    return{
      
    }
  }
}
</script>

<style>
</style>

首页的上部份是一个导航,导航的UI和款式用的是bootstrap,导航用路由完成链接到差别的运用,要注重的是,差别的运用我们用差别的组件封装,比方这个待办事项的运用,我们用的是todolist.vue。还要注重的是,这些组件的注册和路由链接都须要在main.js中设置。不要遗忘了。
返回检察main.js看看代码是怎样写的。
设置完后,我们的主页面上只需一个导航。接着我们设置主页。

Home.vue

我们在xx-src-components文件夹里竖立一个新的组件:Home.vue。这个组件是我们的首页内容,这里我放了一张图,和一句话:迎接!这里有你须要的App。这里一样用到了bootstrap的栅格体系,如许就可以兼容挪动端了。
看代码:

<template>
  <div class="Home">
    <div class="container">
      <div class="col-sm-8">
        <div class="jumbotron">
          <img src="../assets/home-l-img.jpg">
        </div>
      </div>
      <div class="col-sm-4">
        <div class="jumbotron">
          <h2>迎接你!</h2>
          <p>这里有你须要的app</p>
        </div>
      </div>
    </div>
    
  </div>
</template>

<script>
export default {
  name: 'Home',
  data () {
    return {
      
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
  .col-sm-8 .jumbotron{
    padding: 0;
  }
  .jumbotron img{
    width: 100%;
  }
</style>

代码不庞杂,就不诠释了。接下来就是重头戏了。

todolist.vue

这是这个运用的主组件,在这个组件里还会包含两个子组件:sidebar.vue和editor.vue,所以在这个组件里,我们要完成的是一个新建使命的功用。新建的使命会显现在左侧的使命列表sidebar.vue组件里,然后点击某个使命的编辑按钮,我们可以在右侧的使命编辑editor.vue组件里修正。这就是这个运用的架构思绪。下面来看看代码:

<template>
  <div class="todolist">
    <div class="container addInput">
      <input type="text" v-model="taskText" class="form-control col-sm-12" placeholder="新建一个使命" v-on:keyup.enter="addTask">
    </div>
    <div class="container">
      <div class="col-sm-6">
        <sidebar></sidebar>
      </div>
      <div class="col-sm-6">
        <editor></editor>
      </div>
    </div>
  </div>
</template>

<script>
import sidebar from './sidebar.vue'
import editor from './editor.vue'

export default {
  name: 'todolist',
  data(){
    return{
      taskText:''
    }
  },
  components: {
    sidebar,
    editor
  },
  methods:{
    addTask(){
      if(this.taskText==''){
        alert('请输入具体使命内容!')
      }else{
        this.$store.commit('addTask',this.taskText);
        this.taskText=''
      }
    }
  }
}
</script>
  

<style scoped>
  .addInput {
    margin-bottom: .75rem;
  }
</style>

代码量不算大,除了一个输入框以外就是两个组件的标签<sidebar></sidebar>、<editor></editor>了。这里会有一个commit(),它内里引号的内容是一个函数,这个函数在store.js内里的mutations里编写。
要注重的点:
1.两个子组件要在父组件内里注册引入才运用。
2.这里最先触及到了Vuex的功用,简朴申明一下,我们在输入使命后,这个使命的相干数据会被保留到状况治理store内里,然后经由过程mutations的操纵,把输入的内容保留在子组件sidebar里。

明显设置完这里照样没法运用新建使命的,我们还须要两步操纵。

第一步:设置sidebar.vue:
这个子组件是完成使命列表的衬着。看代码:

<template>
  <div class="sidebar">
    <div class="panel panel-default">
      <div class="panel-heading">
        <h4 class="text-left">
          使命列表
          <i class="glyphicon glyphicon-refresh pull-right"></i>
        </h4>   
      </div>
      <div class="panel-body sidebar-context">
        <div>
          <div v-for="(item,index) in items" class="panel panel-default">
            <div class="panel-heading">
              <h4>
                <input type="checkbox">
                {{item.task}}
                <i class="glyphicon glyphicon-remove pull-right"></i>
                <i class="glyphicon glyphicon-edit pull-right"></i>
              </h4>
            </div>
            <div class="panel-body">
              <p>
                {{item.setTime}}<br>
                {{item.details}}
              </p>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
  export default {
    name: 'sidebar',
    data() {
      return {
        
      }
    },
    computed:{
      items(){
        return this.$store.getters.items;
      }
    },
    methods:{
      
    }
  }

</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
  ul {
    list-style: none;
  }
  .sidebar-context{
    max-height: 8rem;
    overflow: scroll; 
  }
  i.glyphicon{
    font-size: .275rem;
    cursor: pointer;
    margin-left: .25rem;
  }

</style>

可以细致考虑一下代码的誊写,在<script> 里设置computed,不然保留在store.js的值没法输出到子组件sidebar.vue里。

第二步,设置store.js:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex);

const state={
    items:[]
}
const getters={
    items:state=>state.items
}
const mutations={
    addTask(state,task){
        var myDate=new Date();
        var y=myDate.getFullYear();
        var m,
            mm=myDate.getMonth()+1;
        if(mm<10){
            m="0"+mm;
        }else{
            m=mm;
        }
        var d,
            dd=myDate.getDate();
        if(dd<10){
            d="0"+dd;
        }else{
            d=dd;
        }
        var currentTime=y+m+d;
        state.items.push({
            task,
            isFinished:false,
            details:"this is a new task",
            setTime:currentTime
        })
    }
   
}

export default new Vuex.Store({
  state,
  getters,
  mutations
})

这一段代码,我们会把输入的值作为一项新建使命的task值保留,并衬着到sidebar上,固然,作为一项待办使命,只需称号是不够的,所以我们为它增加了默许的形貌details和默许的完成时刻setTime,setTime是当前日期。

看到commit相干的函数了吗?

OK,至此,这个todolist运用最基础的新建使命就完成了。

editor.vue

接着,我们完成编辑、删除、标记已完成使命的功用。编辑功用在editor.vue组件内操纵,删除功用则在sidebar.vue内里完成即可。让我们先编辑sidebar.vue。
下面这一段代码我会一次性增添删除编辑和编辑已完成的功用,你可以先敲出来,思索一下道理,也可以跳过这一段,随着背面的步骤一步步增加功用。

<template>
  <div class="sidebar">
    <div class="panel panel-default">
      <div class="panel-heading">
        <h4 class="text-left">
          使命列表
          <i class="glyphicon glyphicon-refresh pull-right" v-on:click="reList"></i>
        </h4>   
      </div>
      <div class="panel-body sidebar-context">
        <div>
          <div v-for="(item,index) in items" class="panel panel-default">
            <div class="panel-heading">
              <h4>
                <input @click="itemCheck(index)" type="checkbox">
                {{item.task}}
                <i class="glyphicon glyphicon-remove pull-right" v-on:click="deleteTask(index)"></I>    
                <i class="glyphicon glyphicon-edit pull-right" v-on:click="clickTask(item)"></i>
              </h4>
            </div>
            <div class="panel-body">
              <p>
                {{item.setTime}}<br>
                {{item.details}}
              </p>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
  export default {
    name: 'sidebar',
    data() {
      return {
        
      }
    },
    computed:{
      items(){
        return this.$store.getters.items;
      },
      activeTask(){
        return this.$store.getters.activeTask;
      }
    },
    methods:{
      deleteTask(index){
        this.$store.commit('deleteTask',index);
      },
      itemCheck(index){
        this.$store.commit('toggleCheck',index);
      },
      clickTask(item){
        this.$store.commit('setActivetask',item);
      },
      reList(){
        this.$store.commit('reList')
      }
    }
  }

</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
  ul {
    list-style: none;
  }
  .sidebar-context{
    max-height: 8rem;
    overflow: scroll; 
  }
  i.glyphicon{
    font-size: .275rem;
    cursor: pointer;
    margin-left: .25rem;
  }

</style>

在这里,我一次性把编辑、删除、标记已完成使命的功用三个功用都加上了(偷懒…)我会一个个来诠释。

1.删除
看名字能看的出来,我在一个删除图标(照样bootstrap啦~)上绑定了一个点击事宜deleteTask,内里的内容是实行store.js里一个deleteTask的函数,同时传入一个index的参数。而在相干的store.js里,我们在mutations里增加deleteTask函数相干的代码:

deleteTask(state,index){
        state.items.splice(index,1)
}

删除对应的数组数据。也就是删除指定index的相干数据。使命就搞定了。

2.编辑
这是一个难点。触及到数据在兄弟组件之间的交流,我们依然运用vuex。

先说说思绪,我们点击sidebar组件里的编辑按钮(删除旁边的按钮),然后把这个使命设置为运动使命,然后显现在右侧的编辑组件editor上。在editor上编辑完成后,点击完成按钮,修正的使命被更新到左侧的使命列表sidebar上。

好了,看上面sidebar.vue的代码,我们先要完成设置运动使命(activeTask):
computed内里须要设置要领:

activeTask(){
    return this.$store.getters.activeTask;
}

然后在编辑按钮上绑定点击事宜,把当前的使命设置为运动使命:

clickTask(item){
    this.$store.commit('setActivetask',item);
}

sidebar.vue里的内容就编辑完了。接着我们须要在components文件夹竖立一个组件editor.vue(遗忘前面有无竖立了…),最先写这一段的代码:

这里须要提早声明的是,下面这一段的代码是我最没把握的代码,由于我不一定这一段是不是是有效率的,然则它一定是能跑起来的。

<template>
  <div class="sidebar">
    <div class="panel panel-default">
      <div class="panel-heading">
        <h3 class="text-left">使命编辑</h3>
      </div>
      <div class="panel-body">
         <p>使命称号</p>
         <input type="text" class="form-control task-input" placeholder="使命称号" v-bind:value="task" v-on:input="saveTask">
         <p>使命概况</p>
         <textarea class="form-control details-input" rows="3" placeholder="使命概况" v-bind:value="details" v-on:input="saveDetails"></textarea>
         <p>使命限期</p>
         <input type="text" class="form-control settime-input" placeholder="花样:20170606" v-bind:value="setTime" v-on:input="saveSettime">
         <h3><i class="glyphicon glyphicon-ok pull-right" v-on:click="save"></i></h3>
      </div>
    </div>
  </div>
</template>

<script>
  export default {
    name: 'editor',
    data() {
      return {

      }
    },
    computed:{
      items(){
        return this.$store.getters.items;
      },
      task(){
        this.taskInput=this.$store.getters.activeTask.task;
        return this.$store.getters.activeTask.task;
      },
      details(){
        this.detailsInput=this.$store.getters.activeTask.details;
        return this.$store.getters.activeTask.details;
      },
      setTime(){
        this.settimeInput=this.$store.getters.activeTask.setTime;
        return this.$store.getters.activeTask.setTime;
      }
    },
    methods:{
      saveTask(e){
        this.taskInput=e.target.value;
      },
      saveDetails(e){
        this.detailsInput=e.target.value;
      },
      saveSettime(e){
        this.settimeInput=e.target.value;
      },
      save(){
        this.$store.commit('editTask',this.taskInput);
        this.$store.commit('editDetails',this.detailsInput);
        this.$store.commit('editSettime',this.settimeInput);
        this.$store.commit('clearAll');
      }
    }
  }

</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
 input,textarea{
     margin-bottom: .3rem;
 }
 i{
   cursor: pointer;
   margin-right: .2rem;
 }
</style>

申明以下:
1.computed里的要领离别对应的是items使命数组(包含一切竖立的使命数据)、task使命称号数据、details使命形貌数据、setTime使命时刻数据。这几个要领,除了第一个,其他的功用都是在对应的input表单显现运动使命(activeTask)的值。

2.methods里的要领,前三个都是在对应的input输入新值时触发事宜,它会把新输入的值离别保留在一个处所。(比方task值就会保留在this.taskInput,taskInput是类名为task-input的input,其他两个以此类推)第四个save(),会把前面保留的三个值赋给运动使命。这也是我不敢一定的处所,由于代码如许写,有多少个差别的值就要用多少个函数,很不环保。

这些commit里的函数都放在store.js的mutations里,下面再说。

以上就把editor.vue的代码编辑完了,接着编辑store.js。
我们增加一下内容:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex);

const state={
    items:[],
    activeTask:{}
}
const getters={
    items:state=>state.items,
    activeTask:state=>state.activeTask
}
const mutations={
    addTask(state,task){
        var myDate=new Date();
        var y=myDate.getFullYear();
        var m,
            mm=myDate.getMonth()+1;
        if(mm<10){
            m="0"+mm;
        }else{
            m=mm;
        }
        var d,
            dd=myDate.getDate();
        if(dd<10){
            d="0"+dd;
        }else{
            d=dd;
        }
        var currentTime=y+m+d;
        state.items.push({
            task,
            isFinished:false,
            details:"this is a new task",
            setTime:currentTime
        })
    },
    deleteTask(state,index){
        state.items.splice(index,1)
    },
    setActivetask(state,item){
        state.activeTask=item
    },
    editTask(state,task){
        state.activeTask.task=task;
        for(let i in state.items){
            if(i==state.activeTask){
                i.task=task;
            }
        }
    },
    editDetails(state,details){
        state.activeTask.details=details;
        for(let i in state.items){
            if(i==state.activeTask){
                i.details=details;
            }
        }
    },
    editSettime(state,settime){
        state.activeTask.setTime=settime;
        for(let i in state.items){
            if(i==state.activeTask){
                i.setTime=settime;
            }
        }
    }
}

export default new Vuex.Store({
  state,
  getters,
  mutations
})

ok,主如果在state和getters里增加了运动使命,mutations里增加了前面提到的相干函数,对照一下看看有无脱漏。

到这里,这个todolist最中心的使命就完成了。然则我们还须要一些细节:
1.修正使命后,把右侧的运动使命清空,复兴初始状况。
2.修正使命的完成时刻后,须要晓得哪些使命越发紧要,须要让使命列表从新排序。
3.修正使命完成状况。

我们来顺次完成:
1.这个比较简朴,我们只需修正完后点击完成按钮时触发一个设置运动使命(activeTask)为空的要领就好了。
在editor.vue组件的save()要领增加:

this.$store.commit('clearAll');

在store.js的mutations增加:

clearAll(state){
        state.activeTask={};
},

done!

2.我们在左侧的使命列表上放一个革新按钮,点击时,会依据使命数据的setTime属性从新排序,时刻近的在前面,时刻远的在背面。
sidebar.vue的methods增加:

reList(){
        this.$store.commit('reList')
}

在store.js的mutations增加:

reList(state){
        function compare(propertyName){
            return function(obj1,obj2){
                var value1=obj1[propertyName];
                var value2=obj2[propertyName];
                if(value2<value1){
                    return 1;
                }else if(value2>value1){
                    return -1;
                }else{
                    return 0;
                }
            }
        }

        state.items.sort(compare('setTime'));
}

这里用到了一个基础的比较大小从新排序的功用。done!

3.这个也不庞杂,我们在使命列表组件sidebar.vue组件的多选框上增加点击事宜,methods里增加:

itemCheck(index){
        this.$store.commit('toggleCheck',index);
},

在store.js的mutations增加:

toggleCheck(state,index){
        state.items[index].isFinished=!state.items[index].isFinished
},

由于在竖立使命时,我们会增加一个isFinished的属性,默许为false,经由过程以上要领,我们就可以切换isFinished的值,也就是切换使命的是不是完成状况。搞定。

到这里,这个todo-list基础就算完成了。

四、适配挪动端和贮存功用

接下来另有一些须要调解的,首先是挪动端的适配,我们要先翻开根目录的index.html,增加一下内容:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name = "viewport" content = "width = device-width, initial-scale = 1.0, maximum-scale = 1.0, user-scalable = 0" />
    <title>todolist</title>
  </head>
  <body>
    <div id="app"></div>
    <!-- 下面是我增加的 -->
    <script>
      let html = document.documentElement;
      window.rem = html.getBoundingClientRect().width / 25 ;
      html.style.fontSize = window.rem + 'px';
    </script>
  </body>
</html>

增加meta和一段JS完成bootstrap的适应和rem要领自适应大小。

第二是localstorage完成存储。毕竟是一个todolist运用,每次翻开都要从新建使命怎样行?
这里我用了一个vue的localstorage插件:地点
npm装置插件:

npm install vue-localstorage --save

store.js设置:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex);

import VueLocalStorage from 'vue-localstorage'
Vue.use(VueLocalStorage)

const STORAGE_KEY='myapp-todolist'
const state={
    items:JSON.parse(window.localStorage.getItem(STORAGE_KEY) || '[]'),
    activeTask:{}
}
const getters={
    items:state=>state.items,
    activeTask:state=>state.activeTask
}
const mutations={
    addTask(state,task){
        var myDate=new Date();
        var y=myDate.getFullYear();
        var m,
            mm=myDate.getMonth()+1;
        if(mm<10){
            m="0"+mm;
        }else{
            m=mm;
        }
        var d,
            dd=myDate.getDate();
        if(dd<10){
            d="0"+dd;
        }else{
            d=dd;
        }
        var currentTime=y+m+d;
        state.items.push({
            task,
            isFinished:false,
            details:"this is a new task",
            setTime:currentTime
        })
    },
    deleteTask(state,index){
        state.items.splice(index,1)
    },
    toggleCheck(state,index){
        state.items[index].isFinished=!state.items[index].isFinished
    },
    setActivetask(state,item){
        state.activeTask=item
    },
    editTask(state,task){
        state.activeTask.task=task;
        for(let i in state.items){
            if(i==state.activeTask){
                i.task=task;
            }
        }
    },
    editDetails(state,details){
        state.activeTask.details=details;
        for(let i in state.items){
            if(i==state.activeTask){
                i.details=details;
            }
        }
    },
    editSettime(state,settime){
        state.activeTask.setTime=settime;
        for(let i in state.items){
            if(i==state.activeTask){
                i.setTime=settime;
            }
        }
    },
    clearAll(state){
        state.activeTask={};
    },
    reList(state){
        function compare(propertyName){
            return function(obj1,obj2){
                var value1=obj1[propertyName];
                var value2=obj2[propertyName];
                if(value2<value1){
                    return 1;
                }else if(value2>value1){
                    return -1;
                }else{
                    return 0;
                }
            }
        }

        state.items.sort(compare('setTime'));
    }
}

const localStoragePlugin = store=>{
    store.subscribe((mutation,{items})=>{
        window.localStorage.setItem(STORAGE_KEY,JSON.stringify(items))
    })
}


export default new Vuex.Store({
  state,
  getters,
  mutations,
  plugins:[localStoragePlugin]
})

要改的解放并不多,主如果把使命数据的数组转换成localstorage的花样。
完成了!撒花~~

五、源码和参考文献

这个todo-list实在是大略不堪,然则基础不好的我也差不多花了2个礼拜才写完,在写这个运用的时刻我是抱着老实的立场的,所以也确切花了很多的心血,包含进修敕令行,npm、搭建项目脚手架、查找材料,中心的考验和波折也没必要多说,一切的辛劳都在看着这个运用可以运转的那一刻云消雾散了。

写了一篇这么长的,我只管用我以为最邃晓清晰的言语来表达,中心一定有很多毛病和疏漏,迎接大神拍砖、指导。写这篇blog的目标也就是从新梳理一下代码的思绪,我是抱着进修的立场来写的。中心的代码有很多反复的处所,在大神看来,无疑是有着占篇幅的怀疑,但也是希望能越发清晰地表述,轻易新人明白。我也是刚入此门,非常能明白代码不细致带来的疑心。

在起名字的时刻,我没有直接说这是一个todo-list,而说是一个运用盒子,是由于我想把它作为一个我的代表项目,内里会集成很多的运用,todolist、音乐、计算器等等,一方面练手,一方面攒一个拿得脱手的项目,轻易今后求职。

说了这么多空话,下面是干货:
todo-list源码(我的github,迎接star,fork)
Vue2.0 新手完整填坑攻略(假如你还没学过Vue,先看这个入门)
vue2.0 构建单页运用最好实战(bootstrap+vue架构一个todolist)
Vue.js+Vuex:一个简朴的记事本(引见vuex项目实战最清晰的教程)
固然,官方文档也是非常重要的,看着教程你可以写出须要的代码,然则只需看着文档,你才晓得为何要如许写。
vue官方文档
vuex官方文档

that’s all~

    原文作者:WE2008311
    原文地址: https://segmentfault.com/a/1190000013056647
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞