学习todo-list源码📒 真的学会了很多开发实践!

简介: 学习todo-list源码📒 真的学会了很多开发实践!

前言

官方示例效果: todomvc.com/examples/re…

拿到这个案例之后你会怎么分析,先暂停3分钟,即便todo-list你已经做过很多次了。

我的第一个版本的todo-list,存在很多问题,例如代码的设计不合理,封装不到位等等, 我们看看官方源码是怎么设计的   sandBox

一、代码结构

1.1 DOM结构

todo-list 官方示例中关于html5的标签语义化和结构划分都非常合理。

<section>
  <header></header>
  <section></section>
  <footer></footer>
</section>

1.2 样式结构处理

在处理一些样式的时候,注意功能单一原则, 也就是html结构中不应该去处理css样式,也就是在最佳实践中不使用style内联来处理样式,更推荐使用动态类名来处理。

<li
     v-for="todo in filteredTodos"
     class="todo"
     :key="todo.id"
     :class="{ completed: todo.completed, editing: todo == editedTodo }"
     >

1.3 代码的命名规范

  • 函数名采用驼峰命名规范
  • 类名采用-来进行拼接
  • 描述某个动作的采用的发生与否采用形容词 例如 complected 标记是否完成

二、代码设计

从功能出发分析代码设计

2.1 todo-list 的增删改查设计

和我设计的函数不同,官方示例给的函数传入的参数都是一个todo,具体todo的处理方式在函数内部进行。

emoveTodo: function (todo) {
  this.todos.splice(this.todos.indexOf(todo), 1);
}
editTodo: function (todo) {
  this.beforeEditCache = todo.title;
  this.editedTodo = todo;
}
doneEdit: function (todo) {
  if (!this.editedTodo) {
    return;
  }
  this.editedTodo = null;
  todo.title = todo.title.trim();
  if (!todo.title) {
    this.removeTodo(todo);
  }
}

2.2 状态模式下的list展示

todolist的展现存在三个状态 all actived complected

这里官方给的和我写的思路基本一致,设置状态变量state,和filterTodo 展示列表

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

2.3 本地存储的函数封装

于直接使用localStorage不同的是,示例中的localStorage进行了一次封装,这样有以下几个好处

  • 不需要关注存储/读取数据过程中的一些类型转化
  • 代码的可读性更高,函数之间耦合度更低
var STORAGE_KEY = "todos-vuejs-2.0";
var todoStorage = {
  fetch: function () {
    var todos = JSON.parse(localStorage.getItem(STORAGE_KEY) || "[]");
    todos.forEach(function (todo, index) {
      todo.id = index;
    });
    todoStorage.uid = todos.length;
    return todos;
  },
  save: function (todos) {
    localStorage.setItem(STORAGE_KEY, JSON.stringify(todos));
  }
};

2.4 复用功能的实现

关于input框聚焦功能的实现 ---自定义指令

这里扩展两个知识

  • 自定义指令的第一个参数,是所绑定的元素
  • 第二个参数binding.value 是所绑定的数据,这里的做法真的很巧妙
v-todo-focus="todo == editedTodo" // 使用指令 
// 指令实现
directives: {
  "todo-focus": function(el, binding) {
    if (binding.value) {
      el.focus();
    }
  }
}

2.5 localstorage 的存储时机

存储

示例中采用的方法是watch监听todos,每次当todos发生变化的时候就直接存储

watch: {
   todos: {
     handler: function(todos) {
       todoStorage.save(todos);
     },
       deep: true
   }
 },

读取

读取的初始化设置封装在todoStorage当中(特殊情况),而data中只含有读取操作

// app initial state
data: {
  todos: todoStorage.fetch(),
    newTodo: "",
      editedTodo: null,
        visibility: "all"
}

2.5 控制全选 / 全不选

全选全不选这里设计的也很巧妙我们先看dom结构的设计

采用v-model进行双向绑定

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

勾选 或者 取消勾选 全选按钮都会触发 allDone的setter

// computed  allDone 
get: function() { 
  return this.remaining === 0;
}
set: function(value) {
  this.todos.forEach(function(todo) {
    todo.completed = value;
  });
}

2.6 数据设计

这一栏的话是看开发经验来说的,我的设计基本上也是保持一直

是否完成状态

  • completed

标记每一个任务

  • id

任务名称

  • title

以前在做todolist的时候设计过另外一个状态,isEdit

这个我将其作为todo的一个属性,用来标记每一个任务是否处于一个修改的状态

这里的做法比我的设计要好

// 只需要一个editedTodo来标记当前处于编辑状态的任务即可
data: {
  editedTodo: null,
},

相对给每一个todo添加isEdit属性来说,这个做法的好处有以下几点

  • 无需维护多个任务处于Edit状态
  • 内存占用(虽然微小,但是细节得注意)

2.7 切换状态的设计

展示列表一共有三个状态, all 、 active、completed

我的做法是设计一个方法去修改状态,而示例中的做法再一次打开的我的眼界

  • 通过a标签的herf属性添加hash值
  • 给window添加上hashchange事件的监听处理函数
  • 每次hash发生改变的时候修改当前的状态
function onHashChange() {
  var visibility = window.location.hash.replace(/#/?/, "");
  if (filters[visibility]) {
    app.visibility = visibility;
  } else {
    window.location.hash = "";
    app.visibility = "all";
  }
}
window.addEventListener("hashchange", onHashChange);
onHashChange();


相关文章
|
12月前
|
存储 JavaScript 前端开发
数据结构之List | 让我们一块来学习数据结构
数据结构之List | 让我们一块来学习数据结构
123 0
|
3月前
|
消息中间件 负载均衡 NoSQL
Redis系列学习文章分享---第七篇(Redis快速入门之消息队列--List实现消息队列 Pubsub实现消息队列 stream的单消费模式 stream的消费者组模式 基于stream消息队列)
Redis系列学习文章分享---第七篇(Redis快速入门之消息队列--List实现消息队列 Pubsub实现消息队列 stream的单消费模式 stream的消费者组模式 基于stream消息队列)
44 0
|
3月前
|
存储 C++
C++初阶学习第十一弹——探索STL奥秘(六)——深度刨析list的用法和核心点
C++初阶学习第十一弹——探索STL奥秘(六)——深度刨析list的用法和核心点
43 7
|
2月前
|
存储 安全 编译器
Python学习日记(一:List、Tuple、dictionary)
1.列表、元组和字典都是序列 2.列表字典可以修改和删除序列中的某个元素,而元组就是一个整体,不能修改和删除,一定要修改或删除的话,只能修改和删除整个元组。 3.既然元组不能删除和修改,有什么作用呢? 1.元组比列表遍历速度快,因为元组是一个整体,运算效率高; 2.正是因为不能修改,元组可以保护不需要修改的数据,可以使代码结构更安全。
|
4月前
|
Java 索引
【JAVA学习之路 | 进阶篇】List接口常用方法
【JAVA学习之路 | 进阶篇】List接口常用方法
|
4月前
|
C++
c++的学习之路:16、list(3)
c++的学习之路:16、list(3)
26 0
|
4月前
|
C++
c++的学习之路:15、list(2)
c++的学习之路:15、list(2)
22 0
|
4月前
|
存储 C++ 容器
c++的学习之路:14、list(1)
c++的学习之路:14、list(1)
32 0
|
4月前
|
存储 C++
C++STL模板之——list(简化源码,模拟源码)
C++STL模板之——list(简化源码,模拟源码)