微信小程序纯内存存储实现todo list

本文介绍如何使用微信小程序实现一个Todo List,通过纯内存存储数据,包括点击切换编辑状态、处理事件冲突、注意sort()函数的排序问题等关键点。详细代码和注释已托管在Git。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

效果显示

todo-list.gif

几个技能点

  1. 点击view切换可编辑状态的input,回车后,要回到文本模式
  2. 将bindtap改为catchtap,阻止与checkbox冲突
  3. 注意sort()函数的坑,是按字符ascii排序,而非数值大小,所以要传递sort()排序回调方法

代码

代码里有详情的注释,完整代码托管在git,https://gitee.com/laeser/demo-weapp
)

JS文件

Page({
  data: {
    todos: [
      {
        title: '明天9点打电话给老张'
      },
      {
        title: '打电话给老王'
      },
      {
        title: '打电话'
      }
    ]
  },
  onLoad() {
    // 调用模拟数据代码,需要时打开下面的注释
    // this.mock()
  },
  // 模拟长列表数据源
  mock() {
    // 生成12行数据,看底部删除按钮是否正常
    const todos = []
    for (let index = 0; index < 12; index++) {
      todos.push({
        title: index
      })
    }
    // 保存数据源
    this.setData({
      todos: todos
    })
  },
  add(e) {
    // 获取文本框里的内容
    const title = e.detail.value
    // 如果文本为空,给出toast提示
    if (!title) {
      wx.showToast({
        title: '请输入内容'
      })
      return
    }
    // 获取原来数据源
    let todos = this.data.todos
    // 构建todo对象
    let todo = {
      title: title
    }
    // 向数组最后添加一个元素
    todos.push(todo)
    // 保存数据源
    this.setData({
      todos: todos,
      title: ''
    })
  },
  editing(e) {
    // 获取当时点击的是第n个元素
    const index = e.currentTarget.dataset.index
    // 设定currentIndex值,让当前的文本框高亮
    this.setData({
      currentIndex: index
    })
  },
  edit(e) {
    // 获取input组件上的取值
    const title = e.detail.value
    // 设定currentIndex值,改变它的聚会
    const index = e.currentTarget.dataset.index
    // 获取原来数据源
    let todos = this.data.todos
    // 修改当前元素的title值
    todos[index].title = title
    // 保存数据源
    this.setData({
      todos: todos,
      currentIndex: -1
    })
  },
  // 勾选事件
  checkboxChange(e) {
    // 取出当前复选框的值
    const values = e.detail.value
    // 保存数据源
    this.setData({
      checkIndices: values
    })
  },
  // 批量删除
  deleteAll() {
    const checkIndices = this.data.checkIndices
    // 判断是不是数组,并且元素个数大于1
    if (Array.isArray(checkIndices) && checkIndices.length > 0) {
      // 删除确认
      wx.showModal({
        title: '确定删除吗?',
        success: ({ confirm }) => {
          if (confirm) {
            // 从后往前遍历,不会造成index错乱
            let todos = this.data.todos
            for (let i = checkIndices.length - 1; i >= 0; i--) {}
            // 注意sort原生是按string的ascii排序,会造成1,11,2这样一系列数据排序不合预期
            checkIndices
              .sort((a, b) => {
                return a - b
              })
              .reverse()
            // 逆序后就可以逐一删除元素
            checkIndices.forEach(item => {
              todos.splice(item, 1)
            })
            // 保存数据源,同时checkIndices将它复位
            this.setData({
              todos: todos,
              checkIndices: []
            })
            // 给出提示框
            wx.showToast({
              title: '删除成功'
            })
          }
        }
      })
    } else {
      wx.showToast({
        title: '请先勾选'
      })
    }
  },
  // 失去焦点事件
  bindblur(e) {
    // 列表中的文本框失去焦点时,currentIndex复位,让它们全部回到未高亮的状态
    this.setData({
      currentIndex: -1
    })
  }
})

wxml文件

<!-- 操作区域主体内容 -->
<view class="main">
  <input type="text" name="title" value="{{title}}" class="add" placeholder="请输入记录内容" confirm-type="done" placeholder-class="input-placeholder" auto-focus bindconfirm="add" />
  <!-- 使用checkbox-group作为容器,方便勾选 -->
  <checkbox-group bindchange="checkboxChange">
    <!-- 遍历数据源 -->
    <label wx:for="{{todos}}" class="list" wx:key="">
      <!-- 复选按钮,取值就是index值,回传checkbox改变事件回调 -->
      <checkbox value="{{index}}" checked="{{item.checked}}" />
      <!-- 文本框,由于currentIndex的存在而具有高亮状态 -->
      <input name="editor" catchtap="editing" data-index="{{index}}" value="{{item.title}}" disabled="{{currentIndex !== index}}" focus="{{currentIndex === index}}" class="input-common {{currentIndex !== index ? 'input-disabled' : 'input-enabled'}}" bindconfirm="edit" bindblur="bindblur" />
    </label>
  </checkbox-group>
</view>
<!-- 删除按钮容器 -->
<view class="delete-container">
  <button type="warn" class="delete-all" bindtap="deleteAll">删除</button>
</view>

wxss文件

/* 主体区域的样式,设定内外边距 */
.main {
  padding: 0 10px;
  margin-top: 10px;
  margin-bottom: 60px;
}

/* 文本框通用样式 */
input {
  color: #666;
  border: 1px solid #999;
  border-radius: 4px;
  padding: 6px;
}

/* 文本框placeholder占位字符的样式 */
input.input-placeholder {
  color: #999;
}

/* 页首添加用文本框背景色 */
.add {
  background-color: white;
}

/* 文本内容的flex布局 */
.list {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
  margin: 5px 0;
}

/* 不论高亮与否都需要具备的样式 */
.input-common {
  color: #000;
  flex: 1;
}

/* 非高亮时的样式 */
.input-disabled {
  border: 1px solid #F8F8F8
}

/* 高亮时的样式 */
 .input-enabled {
  background: white;
}

view.delete-container {
  z-index: 99;
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0px;
  width: 100%;
  text-align: center;
  background-color: #F8F8F8;
}

button.delete-all {
  margin: 10px;
}

关注我

欢迎关注订阅号【黄秀杰】

mp

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值