微信小程序-TODO案例

微信小程序-TODO案例

开始

Todos 案例

分析

页面布局
效果图
功能分析

  1. 点击+号添加一条任务清单
  2. 点击任务清单可以切换状态
  3. 点击x号删除这一条任务清单
  4. 1 item left跟随着变化三种状态
    当任务清单只有一条时,为1 item left
    当任务清单为0时,为空(消失)
    当任务清单为>1时,为 x items left
  5. Toggle all 表示全选和全不选
  6. clear completed 表示清除所有已完成的任务清单

开始制作页面

改变navigationBarTextStyle值
页面布局图
在这里插入图片描述

代码

wxml

<view class="container">
    <view class="search">
        <image src="../../images/plus.png" bindtap="addTodosHandel"></image>
        <input type="text" placeholder="Anything here..." 
        value="{{  search  }}"
         bindinput="inputChangeHandel"
         bindconfirm="addTodosHandel"
         />
    </view>
    <block wx:if="{{todos.length}}">
    <view class="todos">
        <view class="item {{item.completed ? 'completed' : ''}}" wx:for="{{  todos  }}" wx:key="{{index}}" bindtap="toggleTodos" data-index="{{index}}">
            <icon type="{{item.completed ? 'success' : 'circle'}}"></icon>
            <text>{{ item.names }}</text>
            <icon type="clear" size="16" catch:tap="removeTodos" data-index="{{index}}"></icon>
        </view>
    </view>
    <view class="footer">
        <text bindtap="toggleAllHandel">Toggle all</text>
        <!-- {{}} 里面只要有字符就是为true  if判断如果为true时,就显示出来 -->
        <text wx:if="{{leftCount}}">{{ leftCount }} {{leftCount > 1 ? 'items':'item'}} left</text>
        <text bind:tap="clearHandel">Clear completed</text>
    </view>
    </block>
    <view wx:else>
        <text >null</text>
    </view>
</view>

wxss

/* pages/todos/todos.wxss */
.container{
    border-top: 1rpx solid #000;
}

.search{
    /* align-items:center  侧轴对齐*/
    display: flex;
    align-items: center;
    border: 1rpx solid #e0e0e0;
    margin: 20rpx;
    padding: 20rpx;
    border-radius: 5rpx;
    box-shadow: 0 0 5rpx #e0e0e0;  
}

.search image{
    width: 40rpx;
    height: 40rpx;
    margin-right: 20rpx;
}

.todos{
    margin: 20rpx;
    border: 1rpx solid #e0e0e0;
    border-radius: 5rpx;
    box-shadow: 0 0 5rpx #e0e0e0;   
}

.todos .item{
    display: flex;
    align-items: center;
    padding: 20rpx;
    border-bottom: 1rpx solid #e0e0e0;
}

.todos .item:last-child{
    border-bottom: 0;
}

.todos .item text{
   flex: 1;
   font-size: 30rpx;
   color: #888;
   margin-left: 20rpx;
}

.todos .item.completed text{
  color: #888;
  /* 中划线 */
  text-decoration: line-through;
 }

.footer{
    display: flex;
    justify-content: space-between;
    margin: 20rpx;
    font-size: 30rpx;
    color: #333;
}

js

Page({
  data: {
    // 文本框
    search: '',
    // 任务列表
    todos: [
      { names: 'learning WEAPP', completed: false },
      { names: 'learning HTML', completed: true },
      { names: 'learning CSS', completed: false }
    ],
    leftCount: 2,
    allcompleted: false
  },
  inputChangeHandel: function (e) {
    this.setData({ search: e.detail.value });
  },
  // 事件处理函数

  //判断如果input为空不生成
  addTodosHandel: function (e) {
    if (!this.data.search) return
    var todos = this.data.todos
    todos.push({
      names: this.data.search,
      completed: false
    })
    // 必须显示的通过setData()
    this.setData({
      todos: todos,
      input: '',
      leftCount: this.data.leftCount + 1
    })
  },
  // 1.先让按钮点击时执行一段代码
  // 2.拿到文本框里面的值
  // 2.1. 由于小程序的数据绑定是单向的,必须要给文本注册改变事件 
  // 3.将这个值添加到列表中

  //切换任务
  toggleTodos: function (e) {
    // 切换当前点中的完成状态
    // console.log(e.currentTarget)
    var item = this.data.todos[e.currentTarget.dataset.index]
    item.completed = !item.completed
    // 根据当前任务状态的完成状态决定增加一个或者减少一个
    var leftCount = this.data.leftCount + (item.completed ? -1 : 1)
    this.setData({
      todos: this.data.todos,
      leftCount: leftCount
    })
  },
  // 删除任务(需要注意冒泡)  点击删除按钮会执行切换任务事件函数    点击x然后冒泡到item
  removeTodos: function (e) {
    // 找到数组
    var todos = this.data.todos
    // item 就是splice方法中移除掉的元素
    var remove = todos.splice(e.currentTarget.dataset.index, 1)[0]
    var leftCount = this.data.leftCount - (remove.completed  ?  0 : 1)

    // 找到要删除数组的下标
    
    // todos 中会移除掉index所指向的元素
    this.setData({ todos: todos, leftCount: leftCount })
  },
  //处理任务列表全部点击
  toggleAllHandel: function (e) {
    // this 在这里永远指向的是当前页面对象
    this.data.allcompleted = !this.data.allcompleted
    var that = this
    // 找到数组
    var todos = this.data.todos
    todos.forEach(function (item) {
      item.completed = that.data.allcompleted
    })
    var leftCount = this.data.allcompleted ? 0 : this.data.todos.length
    this.setData({ todos: todos, leftCount: leftCount })
  },
  // 清空所有列表
  clearHandel() {
    //  console.log('111')
    // var todos=[]
    // this.data.todos.forEach(function (item){
    //   if(!item.completed){
    //     todos.push(item)
    //   }
    // })
    // 过滤方法就是当(过滤逻辑)为真的时候将他们移到一个数组
    var todos = this.data.todos.filter(function (item) {
      return !item.completed
    })
    this.setData({ todos: todos })
  }
})

业务逻辑

  1. 三元运算符
    item加了一个class属性如果completed为真就添加这个属性否则就不添加
    icon 如果item.completed为真就type改为success否则circle
<view class="item {{item.completed ? 'completed' : ''}}" wx:for="{{  todos  }}" wx:key="{{index}}" bindtap="toggleTodos" data-index="{{index}}">
            <icon type="{{item.completed ? 'success' : 'circle'}}"></icon>
  1. 添加事件
    !this.data.search 如果search为空 return (文本框里面没东西点击加号没反应)
    todos.push一个新数组添加任务清单名字和状态通过,setData({})方法显示并且x item 中x+1
 //判断如果input为空不生成
  addTodosHandel: function (e) {
    if (!this.data.search) return
    var todos = this.data.todos
    todos.push({
      names: this.data.search,
      completed: false
    })
    // 必须显示的通过setData()
    this.setData({
      todos: todos,
      input: '',
      leftCount: this.data.leftCount + 1
    })
  },

bindinput函数事件
数据绑定 e.detail.value

 inputChangeHandel: function (e) {
    this.setData({ search: e.detail.value });
  },

切换任务
item是当前点击数据的index
将状态值改为false
item.completed=!item.completed
三元运算符如果为false就-1否则就+1

  //切换任务
  toggleTodos: function (e) {
    // 切换当前点中的完成状态
    // console.log(e.currentTarget)
    var item = this.data.todos[e.currentTarget.dataset.index]
    item.completed = !item.completed
    // 根据当前任务状态的完成状态决定增加一个或者减少一个
    var leftCount = this.data.leftCount + (item.completed ? -1 : 1)
    this.setData({
      todos: this.data.todos,
      leftCount: leftCount
    })
  },

删除任务
点击删除号,点击删除号触发冒泡item事件 用catchtap事件
用splice移除选中的元素
用e.currentTarget.dataset.index是添加了一个index属性要在wxml写data-index=”{{index}}“ 传参数

// 删除任务(需要注意冒泡)  点击删除按钮会执行切换任务事件函数    点击x然后冒泡到item
  removeTodos: function (e) {
    // 找到数组
    var todos = this.data.todos
    // item 就是splice方法中移除掉的元素
    var remove = todos.splice(e.currentTarget.dataset.index, 1)[0]
    var leftCount = this.data.leftCount - (remove.completed  ?  0 : 1)

    // 找到要删除数组的下标
    
    // todos 中会移除掉index所指向的元素
    this.setData({ todos: todos, leftCount: leftCount })
  },

全选和全不选
小程序的this永远指向当前页面对象
forEach遍历数组

 //处理任务列表全部点击
  toggleAllHandel: function (e) {
    // this 在这里永远指向的是当前页面对象
    this.data.allcompleted = !this.data.allcompleted
    var that = this
    // 找到数组
    var todos = this.data.todos
    todos.forEach(function (item) {
      item.completed = that.data.allcompleted
    })
    var leftCount = this.data.allcompleted ? 0 : this.data.todos.length
    this.setData({ todos: todos, leftCount: leftCount })
  },

清空所有数组
返回为false状态的任务清单

 // 清空所有列表
  clearHandel() {
    //  console.log('111')
    // var todos=[]
    // this.data.todos.forEach(function (item){
    //   if(!item.completed){
    //     todos.push(item)
    //   }
    // })
    // 过滤方法就是当(过滤逻辑)为真的时候将他们移到一个数组
    var todos = this.data.todos.filter(function (item) {
      return !item.completed
    })
    this.setData({ todos: todos })
  }

总结

深刻了解到微信小程序的数据绑定机制、业务逻辑和不用DOM和BOM操作

发表评论