原生js实现TodoMVC

Posted chenguang123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了原生js实现TodoMVC相关的知识,希望对你有一定的参考价值。

原生js实现TodoMVC

先用html和css写好页面的基本结构样式,代码如下,

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <link rel="stylesheet" href="./index.css">
</head>
<body>
  <section id="app">
    <header>
      <h2>ToDoMVC</h2>
      <input type="text" id="new-todo" class="box" placeholder="What needs to be done?">
    </header>
    <section>
      <div id="todo">
        <ul></ul>
        <div class="box card hideCard">
          <span></span>
          <input type="radio" name="btn" id="all" checked>
          <input type="radio" name="btn" id="active">
          <input type="radio" name="btn" id="completed">
          <label for="all">all</label>
          <label for="active">active</label>
          <label for="completed">completed</label>
        </div>
      </div>
    </section>
    <footer>
      <div>
        by chenguang123
      </div>
    </footer>
  </section>
</body>
</html>

index.css

* {
  margin: 0;
  padding: 0;
}

html, body {
  height: 100%;
}

#app {
  width: 900px;
  min-height: 100%;
  background-color: rgb(237, 237, 237);
  margin: auto;
  overflow: hidden;
}

header h2 {
  margin: 20px auto;
  text-align: center;
  font-size: 32px;
  color: gray;
}

#new-todo {
  border: none;
  outline: none;
}

.box {
  position: relative;
  box-sizing: border-box;
  display: block;
  width: 500px;
  height: 50px;
  padding: 10px 20px;
  box-shadow: .5px .5px 3px rgb(132, 132, 132);
  font-size: 24px;
  margin: auto;
}

.box input {
  width: 15px;
  height: 15px;
  margin: 0 10px;
}

.list button {
  position: absolute;
  right: 20px;
  visibility: hidden;
  border: none;
  outline: none;
  background-color: transparent;
  font-size: 24px;
  cursor: pointer;
  color: rgb(161, 161, 161);
  transition: color .5s linear;
}

.list:hover button {
  visibility: visible;
}

.list button:hover {
  color: gray;
}

.card {
  font-size: 16px;
}

.card span {
  margin-right: 30px;
}

.card input {
  display: none;
}

.card label {
  border: 1px solid transparent;
  margin: 5px;
  cursor: pointer;
  transition: border .3s linear;
}

.card label:hover {
  border: 1px solid black;
}

.card input:nth-of-type(1):checked ~ label:nth-of-type(1) {
  border: 1px solid black;
}
.card input:nth-of-type(2):checked ~ label:nth-of-type(2) {
  border: 1px solid black;
}
.card input:nth-of-type(3):checked ~ label:nth-of-type(3) {
  border: 1px solid black;
}

footer {
  margin: 30px;
  text-align: center;
  color: gray;
}

.check {
  text-decoration: line-through;
  color: gray;
}

.d1 {
  display: none;
}
.d2 { display: none; } .hideCard { visibility: hidden; } .showCard { visibility: visible; }

 

此时页面展示如下,

技术图片

 

接下来编写index.js,实现TodoMVC的功能,把该文件引入到index.html文件中

// 添加任务到ul中
var ul = document.querySelector(‘#todo ul‘)

// 添加任务的输入框
var newTodo = document.querySelector(‘#new-todo‘)

// 底部用来显示状态的元素
var card = document.querySelector(‘.card‘)

// 用来显示任务数的元素
var span = document.querySelector(‘.card span‘)

// 全部的任务
var all = document.querySelector(‘#all‘)

// 正在进行的任务
var active = document.querySelector(‘#active‘)

// 完成的任务
var completed = document.querySelector(‘#completed‘)

var app = {
  arrList: [], // 保存所有任务
  count: 0, // 任务数
  init: function () {
    // 监听输入框,添加要做的任务
    newTodo.onkeyup = function (e) {
      if (e.keyCode == 13) {
        if (newTodo.value !== ‘‘) {
          this.addList(newTodo.value)
          newTodo.value = ‘‘
          card.classList.replace(‘hideCard‘, ‘showCard‘)
          span.innerHTML = this.count + ‘ items left‘
          if (all.checked) {
            this.showAll()
          }
          if (active.checked) {
            this.showActive()
          }
          if (completed.checked) {
            this.showCompleted()
          }
        }
      }
    }.bind(this)

    // 监听任务被删除、完成、未完成
    ul.onclick = function (e) {
      this.change(e)
      if (all.checked) {
        this.showAll()
      }
      if (active.checked) {
        this.showActive()
      }
      if (completed.checked) {
        this.showCompleted()
      }
    }.bind(this)

    all.onclick = function () {
      this.showAll()
    }.bind(this)

    active.onclick = function () {
      this.showActive()
    }.bind(this)

    completed.onclick = function () {
      this.showCompleted()
    }.bind(this)
  },
  change: function (e) {
    if (e.target.localName === ‘button‘) {
      var i = this.arrList.indexOf(e.target.parentNode)
      // 若点击button要删除的任务是未完成的,则count数也要减一
      if (!e.target.parentNode.children[0].checked) {
        this.count--
        span.innerHTML = this.count + ‘ items left‘
      }
      this.arrList.splice(i, 1)
      e.target.parentNode.parentNode.removeChild(e.target.parentNode)
      if (this.arrList.length === 0) {
        card.classList.replace(‘showCard‘, ‘hideCard‘)
      }
    } else if (e.target.localName === ‘input‘) {
      // 若点击的是input,则判断任务是否完成
      if (e.target.checked) {
        e.target.parentNode.classList.add(‘check‘)
        e.target.parentNode.classList.replace(‘a‘, ‘b‘)
        this.count--
        span.innerHTML = this.count + ‘ items left‘
      } else {
        e.target.parentNode.classList.remove(‘check‘)
        e.target.parentNode.classList.replace(‘b‘, ‘a‘)
        this.count++
        span.innerHTML = this.count + ‘ items left‘
      }
    }
  },
  addList: function (val) {
    var li = document.createElement(‘li‘)
    li.classList.add(‘box‘)
    li.classList.add(‘list‘)
    li.classList.add(‘a‘)
    var content = `
        <input type="checkbox"></input>
        ${val}
        <button>x</button>
      `
    li.innerHTML = content
    this.arrList.push(li)
    ul.appendChild(li)
    this.count++
  },
  /* 
    类a代表未完成的任务
    类b代表已完成的任务
    类d2代表隐藏未完成的任务
    类d1代表隐藏已完成的任务
    
    addList函数中,给新的任务添加了一个类a;change函数中,当被选中后把类a换成了类b
    
    showActive函数中,要显示未完成的任务,所以要把已完成的任务隐藏,把带有类b的任务,换成了类d1,该类为display: none
    该函数中除了要隐藏已完成任务,也要将被隐藏的未完成任务显示出来,把类d2换成类a

    showCompleted函数中,要显示已完成的任务,所以要把未完成的任务隐藏,把带有类a的任务,换成了类d2,该类为display: none
    该函数中除了要隐藏未完成任务,也要将被隐藏的未完成任务显示出来,把类d1换成类b

  */
  showAll: function () {
    for (let i = 0; i < this.arrList.length; i++) {
      this.arrList[i].classList.replace(‘d1‘, ‘b‘)
      this.arrList[i].classList.replace(‘d2‘, ‘a‘)
    }
  },
  showActive: function () {
    for (let i = 0; i < this.arrList.length; i++) {
      this.arrList[i].classList.replace(‘d2‘, ‘a‘)
      this.arrList[i].classList.replace(‘b‘, ‘d1‘)
    }
  },
  showCompleted: function () {
    for (let i = 0; i < this.arrList.length; i++) {
      this.arrList[i].classList.replace(‘d1‘, ‘b‘)
      this.arrList[i].classList.replace(‘a‘, ‘d2‘)
    }
  }
}

app.init()

 

最后实现的效果如下,

技术图片

 

技术图片

 技术图片

 


以上是关于原生js实现TodoMVC的主要内容,如果未能解决你的问题,请参考以下文章

原生js禁止页面滚动

原生js如何绑定a连接点击事件?

Atom编辑器折腾记_(15)JS代码片段补全(插件:javascript-snippets)

原生js实现的创建和删除元素实例代码

angularJS使用ocLazyLoad实现js延迟加载

原生js-实现轮播图效果