VUE实现一个TODO 可本地存储任务数据

话不多说,直接上代码:

HTML

引入了font-awesome主要利用他的ICON,vue.js这个必不可少,页面样式style.css,页面逻辑代码script.js

<!DOCTYPE html>
<html lang="en" >
<head>
  <meta charset="UTF-8">
  <title>Vue.js任务列表DEMO演示</title>
  <link rel="stylesheet" href="normalize.min.css">
<link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css'>
<link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Source+Sans+Pro'><link rel="stylesheet" href="style.css">

</head>
<body>
<!-- partial:index.partial.html -->
<div class="app" id="app">
  <form class="form" v-on:submit="addTodo">
    <input class="input form__input" v-model="inputVal"/>
    <button class="btn form__submit-btn" type="submit">Add</button>
  </form>
  <transition-group tag="ol" name="list" class="todo-list">
    <li
      class="todo-list__item"
      v-bind:class="{ complete: todo.complete }"
      v-bind:key="index"
      v-for="(todo, index) in filteredTodos">
      <button
        class="todo-list__item-content"
        v-on:click="toggleTodo(todo)">
        {{ todo.text }}
      </button>
      <button
        class="btn todo-list__item-remove"
        v-on:click="deleteTodo(index)">
        <i class="fa" v-bind:class="[todo.complete ? 'fa-check' : 'fa-times']"></i>
      </button>
    </li>
  </transition-group>
  <div class="filters">
    <button 
      class="btn filters__btn filters__btn--all" 
      v-on:click="filterTodos('all')">
      All
    </button>
    <button 
      class="btn filters__btn filters__btn--complete" 
      v-on:click="filterTodos('complete')">
      Complete
    </button>
    <button 
      class="btn filters__btn filters__btn--incomplete" 
      v-on:click="filterTodos('incomplete')">
      Incomplete
    </button>
  </div>
</div>
<!-- partial -->
<script src='vue.js'></script>
<script  src="script.js"></script>

</div>

</body>
</html>

CSS

*, *:before, *:after {
  box-sizing: border-box;
}

html {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-feature-settings: "liga", "kern";
  overflow-y: scroll;
  overflow-x: hidden;
  height: 100%;
  background: linear-gradient(210deg, #9adbbe, #4fc08d);
}

body {
  height: 100%;
  align-items: center;
  justify-content: center;
  font-family: "Source Sans Pro", sans-serif;
}

button {
  background: none;
  border: none;
  color: inherit;
  font-size: inherit;
  font-family: inherit;
  font-weight: inherit;
}
button:focus {
  outline: none;
}
button:hover {
  cursor: pointer;
}

.app {
  width: 420px;
  min-height: 50vh;
  margin: 50px auto;
  justify-content: space-between;
  border-radius: 1em;
  background: #fff;
  overflow: hidden;
  box-shadow: 0 0 5px rgba(25, 25, 25, 0.25);
}

.btn {
  font-size: 14px;
  margin: 0 0.5em;
  border-radius: 2em;
  padding: 0.75em 1.5em;
  cursor: pointer;
  background: none;
  color: #2d7c58;
  border: 1px solid;
  letter-spacing: 1px;
  font-family: "Source Sans Pro", sans-serif;
  color: #4fc08d;
  border: #4fc08d 1px solid;
  transition: 250ms ease-out;
}
.btn:hover, .btn:focus {
  color: #fff;
  background: #4fc08d;
}

.form {
  width: 100%;
  padding: 1.5rem 1rem 0 1rem;
  display: flex;
}
.form__input {
  width: 100%;
  font-size: 14px;
  margin: 0 0.5em;
  border-radius: 2em;
  padding: 0.75em 1.5em;
  background: none;
  font-family: "Source Sans Pro", sans-serif;
  border: #e3e3e3 1px solid;
  transition: border 250ms ease-out;
}
.form__input:focus {
  border: #4fc08d 1px solid;
  outline: none;
}
.todo-list {
  width: 100%;
  padding: 0 1rem;
  flex: 1;
}
.todo-list__item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.5em;
  margin-bottom: 0.5em;
  border-radius: 3px;
  transition: 200ms;
  color: #4fc08d;
}
.todo-list__item:last-child {
  margin-bottom: 0;
}
.todo-list__item.complete {
  color: lightgreen;
}
.todo-list__item.complete .todo-list__item-content:after {
  background: lightgreen;
}
.todo-list__item-content {
  position: relative;
}
.todo-list__item-content:after {
  content: "";
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  height: 1px;
  background: #4fc08d;
  transition: 250ms ease-out;
  transform-origin: center;
  transform: scalex(0);
}
.todo-list__item-content:hover:after, .todo-list__item-content:focus:after {
  transform: scalex(1);
}
.todo-list__item-remove {
  margin-left: 0.5em;
  background: none;
  border: 1px solid;
  color: inherit;
  padding: 0;
  line-height: 1;
  width: 2em;
  height: 2em;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  font-size: 80%;
}

.filters {
  width: 100%;
  display: flex;
  justify-content: space-around;
  padding: 0 1rem 1.5rem 1rem;
}

.list-move,
.list-leave-active,
.list-enter-active {
  transition: 500ms cubic-bezier(0.87, -0.41, 0.19, 1.44);
}

.list-enter,
.list-leave-active {
  transform: translate(100%, 0);
  opacity: 0;
}

js

var filters = {
  all: function(todos) {
    return todos;
  },
  complete: function(todos) {
    return todos.filter(function(todo) {
      return todo.complete;
    });
  },
  incomplete: function(todos) {
    return todos.filter(function(todo) {
      return !todo.complete;
    });
  }
}

var STORAGE_KEY = 'vue-js-todo-P7oZi9sL'
var todoStorage = {
  fetch: function () {
    var todos = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]');
    return todos;
  },
  save: function (todos) {
    localStorage.setItem(STORAGE_KEY, JSON.stringify(todos));
  }
}

var app = new Vue({
  el: '#app',
  data: {
    inputVal: '',
    todos: todoStorage.fetch(),
    visibility: 'all'
  },
  watch: {
    todos: {
      handler: function(todos) {
        todoStorage.save(todos);
      }
    }
  },
  computed: {
    filteredTodos: function () {
      return filters[this.visibility](this.todos);
    }
  },
  methods: {
    addTodo: function(e) {
      e.preventDefault();
      if (this.inputVal) {
        this.todos.push({
          text: this.inputVal,
          complete: false
        });
      }
      this.inputVal = '';
    },
    toggleTodo: function(todo) {
      todo.complete = !todo.complete;
    },
    filterTodos: function(filter) {
      this.visibility = filter;
    },
    deleteTodo: function(index) {
      this.todos.splice(index, 1);
    }
  }
});

演示效果

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值