首页>案例集>JavaScript案例集

用ES6写了一个todos,本地任务清单!

学完了ES6,就可以拿一个小项目练练手,todoMVC是一个比较出名的用来练习各种编程语言的项目,可以直接去它官网看。

这里写一个ES6版本的。

4.jpg

点击图片看效果,如果想看Vue2版本的,也可以点这里

增删改查功能都有,自己看代码。

核心代码:

// 找对象
  const newTodoInput = $('.new-todo');
  const oTodoList = $('.todo-list');
  const oMain = $('.main');
  const oFooter = $('.footer');
  const oTodoCount = $('.todo-count');
  const oClearCompleted = $('.clear-completed');
  const oToggleAll = $('.toggle-all');
  const oTodoType = $$('.filters a');

  // 数据的本地存储
  const TODOS_KEY = 'dotos_ES6';
  let todosStorage = {
    get() {
      return JSON.parse(localStorage.getItem(TODOS_KEY)) || [];
    },
    set(todos) {
      localStorage.setItem(TODOS_KEY,JSON.stringify(todos));
    }
  }
  // 全局变量
  // 存储数据的todos
  // let todos = [
  //  { id: 1, title: '学习', completed: false },
  //  { id: 2, title: '做饭', completed: true },
  //  { id: 3, title: '接娃放学', completed: true },
  // ]
  let todos = todosStorage.get();

  // 用于区分单击和双击事件
  let timer = null;

  // 初始化渲染
  render(todos);

  // 当enter的时候添加事项
  newTodoInput.addEventListener('keyup', (e) => {
    if (e.key === 'Enter') {
      // 添加事项
      addTodo();
      todosStorage.set(todos);
      // 重新渲染
      render(todos);
    }
  })

  // 因为有很多事项,有很多删除按钮,所以用事件委托性能更高
  // ul同时委托了单击事件和双击事件,通过300ms的延迟来判断是单击还是双击
  // 如果300ms以后没有单击,则是单击事件,执行对应的代码。
  oTodoList.addEventListener('click', function (e) {
    clearTimeout(timer);
    timer = setTimeout(function () {
      const target = e.target;
      console.log(target);
      const tempLi = target.closest('li');
      // 根据li的id属性找到todos里面该id的数据,数字和字符串的相等用==
      const todo = todos.find(item => item.id == tempLi.id);
      // 如果点击的是删除按钮,则删除该事项
      if (target.className === 'destroy') {
        delTodo(todo);
      }
      // 如果点击的是复选框按钮,则切换完成和未完成的状态
      if (target.className === 'toggle') {
        todo.completed = target.checked;
      }
      // 修复双击下出现输入框编辑的时候,单击输入框的文本,输入框又消失的问题
      if (target.className === 'edit') {
        const oEditing = tempLi.querySelector('.edit');
        tempLi.classList.add('editing');
        oEditing.focus();
        return;
      }
      todosStorage.set(todos);
      render(todos);

    }, 300);
  })

  // 编辑事项
  oTodoList.addEventListener('dblclick', function (e) {
    // 如果300ms以内又有点击事件,则是双击事件,清掉前面定时器要执行的代码,执行双击对应的代码。
    clearTimeout(timer);
    const target = e.target;
    console.log(target);
    const tempLi = target.closest('li');
    const todo = todos.find(item => item.id == tempLi.id);
    if (target.tagName === 'LABEL') {
      const oEditing = tempLi.querySelector('.edit');
      tempLi.classList.add('editing');
      oEditing.focus();
      // 把输入框的光标放在最后面。
      // element.setSelectionRange(selectionStart, selectionEnd [, selectionDirection]);
      // 如果希望全选输入元素中的文本,你可以使用 HTMLInputElement.select() 方法。
      oEditing.setSelectionRange(-1, -1);
      // 存储输入框以前的数据
      const titleBeforeEdit = oEditing.value;
      oEditing.addEventListener('keyup', function (e) {
        console.log(e.key)
        const val = this.value.trim();
        // 编辑完成
        if (e.key === 'Enter') {
          if (val === '') {
            delTodo(todo);
          } else {
            todo.title = val;
          }
          todosStorage.set(todos);
          render(todos);
        }
        // 取消编辑
        if (e.key === 'Escape') {
          this.value = titleBeforeEdit;
          render(todos);
        }
      })
      // 失去焦点的时候,编辑完成
      oEditing.addEventListener('blur', function () {
        const val = this.value.trim();
        if (val === '') {
          delTodo(todo);
        } else {
          todo.title = val;
        }
        todosStorage.set(todos);
        render(todos);
      })

    }
  })

  // 删除完成的事项
  oClearCompleted.addEventListener('click', function () {
    todos = todos.filter(todo => !todo.completed);
    todosStorage.set(todos);
    render(todos);
  })

  // 点击全选复选框,对所有事项的状态切换
  oToggleAll.addEventListener('change', function () {
    const val = this.checked;
    for (const todo of todos) {
      todo.completed = val;
    }
    todosStorage.set(todos);
    render(todos);
  })

  // 根据hash切换a的状态
  // 不能点击a的时候获取hash,否则获取的是上一个hash值。
  window.onhashchange = function () {
    // console.log(location.hash);
    // a被选中的状态
    selectedType();
    render(todos);
  }

  // 找对象的函数
  function $(selector) {
    return document.querySelector(selector);
  }

  function $$(selector) {
    return document.querySelectorAll(selector);
  }

  // 渲染事项
  function render(todos) {
    // 对面板的切换
    if (todos.length) {
      oMain.style.display = 'block';
      oFooter.style.display = 'block';
    } else {
      oMain.style.display = 'none';
      oFooter.style.display = 'none';
    }
    if (!todos.length) {
      return;
    };
    let renderTodos = [];
    // 筛选数据
    // console.log(location.hash);
    switch (location.hash) {
      case '#/active':
        renderTodos = todos.filter(todo => !todo.completed);
        break;
      case '#/completed':
        renderTodos = todos.filter(todo => todo.completed);
        break;
      default:
        renderTodos = todos;
        break;
    }
    // a的被选中状态
    selectedType();

    let str = '';
    for (const obj of renderTodos) {
      str += `<li id='${obj.id}' class=${obj.completed ? 'completed' : ''}>
      <div class="view">
        <input class="toggle" type="checkbox" ${obj.completed ? 'checked' : ''}>
        <label>${obj.title}</label>
        <button class="destroy"></button>
      </div>
      <input class="edit" value="${obj.title}">
    </li>`
    }
    oTodoList.innerHTML = str;

    // 得到未完成的事项的个数。
    const remainingCount = getRemainingCount(todos);

    // 状态栏 未完成数量的显示
    oTodoCount.innerHTML = `<strong>${remainingCount}</strong> ${remainingCount === 1 ? 'item' : 'items'} left`

    // 删除完成事项的按钮
    // 如果事项的总个数大于未完成事项的个数,则按钮显示
    oClearCompleted.style.display = todos.length > remainingCount ? 'block' : 'none';

    //对全选复选框的状态设置
    if (remainingCount === 0 && todos.length !== 0) {
      oToggleAll.checked = true;
    } else {
      oToggleAll.checked = false;
    }
  }

  // 未完成的事项的个数
  function getRemainingCount(todos) {
    return todos.filter(item => !item.completed).length;
  }


  // 添加事项
  function addTodo() {
    let value = newTodoInput.value.trim();
    if (!value) return;
    todos.push({ id: Date.now(), title: value, completed: false });
    newTodoInput.value = '';
  }
  // 删除单个事项
  function delTodo(todo) {
    const index = todos.indexOf(todo);
    if (index !== -1) {
      todos.splice(index, 1);
    }
  }

  // 事项类别状态设置
  function selectedType() {
    oTodoType.forEach((item, index) => {
      if (item.hash === location.hash) {
        oTodoType.forEach(item => item.classList.remove('selected'));
        item.classList.add('selected');
        // console.log(item.hash);
      }
    })
  }


点赞


0
保存到:

相关文章

发表评论:

◎请发表你卖萌撒娇或一针见血的评论,严禁小广告。

Top