[聚合文章] Todos备忘录项目详解

vue.js 2017-11-12 1 阅读

今天我们要做的是个备忘录项目模仿一下Todos这是Todos的官方网址http://todomvc.com/examples/v...

操作流程

新建文件夹和文件名称

自定义文件夹和文件名称,我们用它来装我们今天的项目

打开命令行 依次输入:

npm init -y // 初始化项目

npm i -S underscore vue todomvc-app-css //下载这三个文件,因为我们后期要用到

如图这样

在index.html里边输入Vue的基本样式和引入css、html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <link rel="stylesheet" href="./node_modules/todomvc-app-css/index.css">
</head>
<body>
        <section class="todoapp">
                <header class="header">
                    <h1>todos</h1>
                    <input class="new-todo" placeholder="What needs to be done?" autofocus="" >
                </header>
                <section class="main" v-show="showList">
                    <input class="toggle-all" id="toggle-all" type="checkbox">
                    <label for="toggle-all">Mark all as complete</label>
                    <ul class="todo-list">
                        <li>
                            <div class="view">
                                <input class="toggle" type="checkbox" >
                                <label></label>
                                <button class="destroy" ></button>
                            </div>
                            <input class="edit">
                        </li>
                    </ul>
                </section>
                <footer class="footer" v-show="showList">
                    <span class="todo-count">
                        <strong></strong></span>
                    <ul class="filters">
                        <li>
                            <a class="selected" href="#/">All</a>
                        </li>
                        <li>
                            <a href="#/active" >Active</a>
                        </li>
                        <li>
                            <a href="#/completed" >Completed</a>
                        </li>
                    </ul>
        
                    <button class="clear-completed" >Clear completed</button>
        
                </footer>
            </section>
    <script src="./../../vue.js"></script>
    <script>
        var app = new Vue({
            el:".todoapp",
             data:{
                
            }
        })
    </script>
</body>
</html>

在data中加入写上一个数组,用来渲染到页面,数组里边又是一个对象,因为我们的一条数据里会有不同的数据。

 data:{
        todoList:[
            {
                text:"Vue很难",  //这个是任务的名称
                checkbox:false  // checkbox的false表示未完成,true表示已完成
            },
            {
                text:"不难,只要用心", 
                checkbox:false
            }
        ]
    }

在li里遍历一下数据并绑定,在label中加入数据

 <li v-for="(todo,index) in todoList">
    <div class="view">
        <input class="toggle" type="checkbox">
        <label>{{todo.text}}</label>
        <button class="destroy"></button>
    </div>
    <input class="edit">
</li>

给li元素动态绑定class,completed样式的值,根据todo.checked, 如果todo.checked为 true则有completed样式。

<li v-for="(todo,index) in todoList"  :class="{completed: todo.checked}">

给checkbox加上v-model,值为todo.checked, checked属性会自动和todo.checked关联

<input class="toggle" type="checkbox" v-model="todo.checked"/>

这样我们就可以看到点击复选框的效果了。

在data中加入newTodo

 data: {
    newTodo:"",
    todoList: [{
            text: "Vue很难", //这个是任务的名称
            checked: false // checkbox的false表示未完成,true表示已完成 
        },
        {
            text: "不难,只要用心",
            checked: false
        }
    ]
}

删除默认数据,因为我们要用动态去添加,给我们的输入框动态绑定数据,并添加事件来提交内容。

<input class="new-todo" placeholder="你接下来需要完成什么?" autofocus="" v-model="newTodo" @keyup.enter.trim="addTodo" />

紧接着我们写绑定事件的逻辑,新建模块methods

methods: {
    addTodo() {
        this.newTodo = this.newTodo.trim(); //这句是去除空格 
        // 判断输入内容是否为空,为空不提交  
        if (this.newTodo.length < 1) {
            return;
        }
        //把新数据添加到数组当中,默认为未完成
        this.todoList.unshift({
            text: this.newTodo,
            checked:false
        })
        this.newTodo = ""
    }
}

这样我们就能动态的添加数据了,然后我们来做删除数据功能

绑定删除事件,因为我们要用到underscore,所以引入

<button class="destroy" @click="deleteTodo(todo)"></button>

<script src="./node_modules/underscore/underscore-min.js" charset="utf-8"></script>

添加业务逻辑在methods中添加

deleteTodo(todo){

this.todoList = _.without(this.todoList, todo)

}

我们看到官网的页面是没有数据底部是消失的,所以我们来完善一下

添加计算属性

 computed:{
        showList(){
            return this.todoList.length > 0
        }
    }

添加v-show

<footer class="footer" v-show="showList">

官网是双击数据是可以进行编辑的

绑定数据

<input class="edit" type = "text" v-model = "todo.text">

在data里添加索引

editingIndex: -1

绑定双击事件

<label @dblclick="editTodo(index)">{{ todo.text }}</label>

在methods里添加

editTodo(index) {

// 设置一下当前正在编辑的索引
this.editingIndex = index;

}

加上class

<li:class="{completed: todo.checked, editing: index === editingIndex}"
v-for="(todo,index) in todoList">

自定义一个属性

// 注册一个全局自定义指令 v-focus
Vue.directive('focus', {
// 当绑定元素插入到 DOM 中。
inserted(el) {

// 聚焦元素
el.focus()

},
// 当绑定元素更新的时候
update(el) {

el.focus();

}
})

添自定义属性并绑定事件

<input class="edit" type="text" v-model="todo.text" v-focus="index === editingIndex" @blur="saveTodo(todo)" @keyup.enter="saveTodo(todo)"/>

写事件

saveTodo(todo) {

this.editingIndex = -1
if (todo.text.trim().length < 1) {
  this.deleteTodo(todo)
}

}

未完成的个数

填写逻辑在计算属性中

activeCount() {

return this.todoList.filter(item => {
  return !item.checked
}).length;

}

渲染数据

<span class="todo-count">

<strong>{{activeCount}}</strong>

</span>

当刷新页面我们希望保留数据,这就需要我们的存储数据了

新建一个store.js并引入

在store.js中填写
var STORAGE_KEY = 'todoList'
window.todoStorage = {

fetch() {
try {
  return JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]');
} catch(error) {
  return [];
}
},
save(todoList) {
    localStorage.setItem(STORAGE_KEY, JSON.stringify(todoList));
}

}

修改初始化数据

在data里添加

todoList: todoStorage.fetch()

进行监听,添加监听模块

watch: {
todoList: {

deep: true,
handler: todoStorage.save

}
}

全部完成功能的实现(选中和全选功能)

添加计算属性

// 是否所有任务都完成
allDone: {

get() {
  // 未完成的数量为0表示全部完成,全部完成返回true
  return this.activeCount === 0;
},
set(value) {
  this.todoList.forEach(todo => {
    todo.checked = value
  });
}

}

绑定数据

<input class="toggle-all" id="toggle-all" type="checkbox" v-model="allDone" />

页面切换(all、active、Completed)

实例一个对象来实现过滤逻辑

var filters = {
all: function (todos) {

return todos;

},
active: function (todos) {

return todos.filter(function (todo) {
  return !todo.checked;
});

},
completed: function (todos) {

return todos.filter(function (todo) {
  return todo.checked;
});

}
};

在data里添加一个属性visibility 来表示我们要显示所有,还是显示未完成,或已完成

visibility: 'all'

修改一下未完成的数量这个计算属性,使用上面的filters对象去过滤

computed: {
...
// 未完成的任务数量
activeCount() {

return filters.active(this.todoList).length;

},
}

添加任务过滤的计算属性:

computed: {
...
// 过滤任务列表
filteredTodoList: function () {

return filters[this.visibility](this.todoList);

}
}

在DOM当中添加点击事件,点击的时候修改visiblity属性即可

<li><a:class="{selected:visibility==='all'}"href="#/"@click="visibility='all'">all
</li>
<li>
<a
:class="{selected: visibility === 'active'}"
href="#/active"
@click="visibility = 'active'"

active
</li>
<li>
<a
:class="{selected: visibility === 'completed'}"
href="#/completed"
@click="visibility = 'completed'">completed
</li>
列表渲染的循环语句修改:

<li
:class="{completed: todo.checked, editing: index === editingIndex}"
v-for="(todo,index) in filteredTodoList" :key="'todo-'+index"

添加一个变量,得到hash值:

var visibility = location.hash.substr(location.hash.indexOf('/')+1);
visibility = visibility === '' ? 'all' : visibility

设置visibility属性的值为当前的这个变量:

data: {
visibility: visibility,
...
}

点击清空已完成功能:

添加一个已完成的任务数量计算属性:

computed: {
...
// 已完成的任务数量
completedCount() {

return filters.completed(this.todoList).length;

}
}

添加一个清空已完成的方法:

methods: {
...
// 清空已完成的任务列表
clearCompleted() {

this.todoList = filters.active(this.todoList)

}
}

DOM元素绑定事件,以及v-show:

<button class="clear-completed" @click="clearCompleted" v-show="completedCount > 0">清空已完成</button>

注:本文内容来自互联网,旨在为开发者提供分享、交流的平台。如有涉及文章版权等事宜,请你联系站长进行处理。