Мини-программа TodoList Практика

внешний интерфейс WeChat GitHub Апплет WeChat Less Gulp Backbone.js
Мини-программа TodoList Практика

Практика TodoList

Прочитав официальное введение в документ, я хочу найти простой пример для проверки реализации.TodoList MVC очень хорош, прост и удобен.

Раньше я использовал JQ, Backbone и vue, чтобы просто играть.Примерные функции следующие:

  • добавить дело
  • Хранить в кеше приложения
  • Отображение списка
  • Дифференциальное отображение состояния: все, незавершенное, завершенное
  • изменить состояние дел
  • удалить задачу

В соответствии с вышеперечисленными функциями апплет комплектуется следующим образом:

GitHub: GitHub.com/CH563/в ДОЛ…

Вот запись моего процесса завершения:

Скачать средства разработки утверждения:Скачать инструменты разработчика

После завершения установки используйте WeChat для сканирования и входа в систему, выберите папку и создайте ее.Инструмент разработки автоматически создаст следующий каталог:

pages/

app.js

app.json

app.wxss

Описание структуры и конкретной конфигурации смотрите в официальной документации:Билеты.WeChat.QQ.com/debug/WX ADO…

базовая конфигурация

Из-за обычных привычек разработки Less, если вы напрямую используете wxss апплета для записи, будет восстановлен исходный метод записи, что очень неудобно, поэтому вы напрямую используете gulp для компиляции Less в реальном времени и изменения файла имя wxss. Инструмент разработки апплета не поддерживает Less и разработан непосредственно с помощью vscode. Инструмент разработки апплета можно просматривать и отлаживать в режиме реального времени. vscode также имеет множество подключаемых модулей для поддержки подсказок синтаксиса апплета.

// gulpfile.js
var gulp = require('gulp')
var less = require('gulp-less')
var plumber = require('gulp-plumber')
var rename = require('gulp-rename')

gulp.task('less', function () {
  return gulp.src('./app.less')
    .pipe(plumber())  // 错误处理
    .pipe(less()) // 编译less
    .pipe(rename((path) => path.extname = '.wxss')) // 编译后生成文件修改后缀为.wxss
    .pipe(gulp.dest('./'));
});
gulp.watch('./app.less', ['less']); // 实时监控app.less文件变化,运行任务

Компоненты пользовательского интерфейса также напрямую относятся к компонентам, поддерживаемым апплетом.weui-wxss

@import "./weui.wxss";

Определите маршрутизацию страницы апплета и сопоставление цветов в app.json:

{
  "pages":[
    "pages/index/index"
  ],
  "window":{
    "backgroundTextStyle":"light",
    "navigationBarBackgroundColor": "#ca2100",
    "navigationBarTitleText": "TodoList",
    "navigationBarTextStyle":"white"
  }
}

разработка страницы

Файлы страниц хранятся в каталоге pages/. Каждая функциональная страница будет создавать папку. TodoList теперь нужна только одна страница для ее завершения.

Привязка данных использует синтаксис Mustache (двойные фигурные скобки) для переноса переменных.

<text class="userinfo-nickname">{{userInfo.nickName}}</text>
<!-- 三元运算 -->
<text class="{{status === '1'?'active':''}}" data-status="1" bindtap="showStatus">全部</text>

добавить дело

использовать поляaddShowЧтобы судить о добавлении входного слоя для отображения и скрытия

Поле ввода-вывода не является двусторонним, поэтому добавьте сюда событие.bindinput="setInput"для назначения изменений в реальном времени

<view class="addForm {{addShow?'':'hide'}}">
    <view class="addForm-div">
      <input class="weui-input" placeholder="请输入todo" value="{{addText}}" bindinput="setInput" focus="{{focus}}" />
      <view class="addForm-btn">
        <button class="weui-btn mini-btn" type="warn" bindtap="addTodo" size="mini">确定添加</button>
        <button class="weui-btn mini-btn" type="default" bindtap="addTodoHide" size="mini">取消</button>
      </view>
    </view>
  </view>

Обработка событий назначения в реальном времени

setInput: function (e) {
    this.setData({
      addText: e.detail.value
    })
}

При отмене значение ввода необходимо очистить, а ввод необходимо привязатьvalue="{{addText}}"

Page({
 data:{
     //...
 }, 
 //...
 addTodoHide: function () {
    this.setData({
      addShow: false, // 控制添加输入面板隐藏
      focus: false, // 失去焦点
      addText: '' // 清空值
    })
 }
 //...
})

добавить дело

Page({
 data:{
     //...
 }, 
 //...
 addTodo: function () {
    // 检查有没有输入
    if (!this.data.addText.trim()) {
      return
    }
    var temp = this.data.lists // 取出lists
    var addT = {
      id: new Date().getTime(), // 取当前时间
      title: this.data.addText,
      status: '0'
    }
    temp.push(addT) // 添加新的todo
    this.showCur(temp) // 处理当前状态的方法
    this.addTodoHide() // 添加成功后,隐藏添加面板方法
    wx.setStorage({ // 小程序异步缓存
      key:"lists",
      data: temp
    })
    wx.showToast({ // weui toast组件
      title: '添加成功!',
      icon: 'success',
      duration: 1000
    });
 }
 //...
})

Раздел списка

прокрутить внутри прокрутки

Отображение списка, запуск событий, использование данных для передачи параметров, привязка событий привязки

<scroll-view class="lists" scroll-y>
    <!-- 判断列表是否为空 -->
    <block wx:if="{{curLists.length < 1}}">
      <view class="nodata">暂无数据</view>
    </block>
    <!-- 列表渲染 -->
    <view class="item" wx:for="{{curLists}}" wx:key="index">
      <!-- 内容view,绑定touch三个件事,来实现滑动册除 -->
      <view class="content" style="{{item.txtStyle}}" data-index="{{index}}" bindtouchstart="touchS" bindtouchmove="touchM" bindtouchend="touchE">
        <!-- checkbox图标,changeTodo事件来控制状态切换 -->
        <icon class="icon-small" type="{{item.status === '0'?'circle':'success'}}" size="23" data-item="{{item.id}}" bindtap="changeTodo"></icon>
        <text class="title {{item.status === '1'?'over':''}}">{{item.title}}</text>
        <!-- api.formatTime是使用了wxs模块化编写的模块 -->
        <text class="time">{{api.formatTime(item.id)}}</text>
      </view>
      <!-- 删除按钮,绑定删除事件 -->
      <view class="del" data-item="{{item.id}}" bindtap="delTodo"><text>删除</text></view>
    </view>
  </scroll-view>

Проведите, чтобы удалить

Эффект: При скольжении влево содержимое перемещается пальцем влево, а кнопка del появляется справа; когда расстояние скольжения больше половины ширины кнопки, при отпускании пальца оно автоматически скользит влево, чтобы отобразить кнопку, а когда она меньше половины, она автоматически возвращается в исходное положение, скрывает кнопку.

Идеи реализации:Кнопки содержимого и удаления имеют абсолютное позиционирование соответственно. Слой z-index используется для управления содержимым, закрывающим удаление. Когда содержимое перемещается влево, кнопка удаления становится видимой.

Сенсорный объект, предоставляемый API-интерфейсом апплета WeChat, и 3 функции, связанные с касанием пальца (touchstart, touchmove, touchend), для реализации перемещения содержимого пальцем.

Для получения подробных инструкций API, пожалуйста, проверьте:Билеты.WeChat.QQ.com/debug/WX ADO…

Содержимое списка было привязано к этим трем событиям:bindtouchstart="touchS" bindtouchmove="touchM" bindtouchend="touchE"

Реализация:

УведомлениеtxtStyle, который привязан к этому свойству в содержании, чтобы следовать за движением пальцаstyle="{{item.txtStyle}}"

delBtnWidthДля ширины кнопки del здесь в rpx

Page({
 data:{
     //...
 }, 
 //...
  touchS: function (e) {
    // console.log('开始:' + JSON.stringify(e))
    // 是否只有一个触摸点
    if(e.touches.length === 1){
      this.setData({
        // 触摸起始的X坐标
        startX: e.touches[0].clientX
      })
    }
  },
  touchM: function (e) {
    // console.log('移动:' + JSON.stringify(e))
    var _this = this
    if(e.touches.length === 1){
     // 触摸点的X坐标
      var moveX = e.touches[0].clientX
      // 计算手指起始点的X坐标与当前触摸点的X坐标的差值
      var disX = _this.data.startX - moveX
     // delBtnWidth 为右侧按钮区域的宽度
      var delBtnWidth = _this.data.delBtnWidth
      var txtStyle = ''
      if (disX == 0 || disX < 0){ // 如果移动距离小于等于0,文本层位置不变
        txtStyle = 'left:0'
      } else if (disX > 0 ){ // 移动距离大于0,文本层left值等于手指移动距离
        txtStyle = 'left:-' + disX + 'rpx'
        if(disX >= delBtnWidth){
          // 控制手指移动距离最大值为删除按钮的宽度
          txtStyle = 'left:-' + delBtnWidth + 'rpx'
        }
      }
      // 获取手指触摸的是哪一个item
      var index = e.currentTarget.dataset.index;
      var list = _this.data.curLists
      // 将拼接好的样式设置到当前item中
      list[index].txtStyle = txtStyle
      // 更新列表的状态
      this.setData({
        curLists: list
      });
    }
  },
  touchE: function (e) {
    // console.log('停止:' + JSON.stringify(e))
    var _this = this
    if(e.changedTouches.length === 1){
      // 手指移动结束后触摸点位置的X坐标
      var endX = e.changedTouches[0].clientX
      // 触摸开始与结束,手指移动的距离
      var disX = _this.data.startX - endX
      var delBtnWidth = _this.data.delBtnWidth
      // 如果距离小于删除按钮的1/2,不显示删除按钮
      var txtStyle = disX > delBtnWidth/2 ? 'left:-' + delBtnWidth + 'rpx' : 'left:0'
      // 获取手指触摸的是哪一项
      var index = e.currentTarget.dataset.index
      var list = _this.data.curLists
      list[index].txtStyle = txtStyle
      // 更新列表的状态
      _this.setData({
        curLists: list
      });
    }
  }
  //...
})

WXS реализует формат времени

Эффект следующий:

Здесь я использую WXS апплета

WXS (WeiXin Script) представляет собой набор языков сценариев для небольших программ.В сочетании с WXML можно построить структуру страницы.Узнать больше

Создайте новый файл api.wxs, а затем укажите его в index.wxml, определите имя модуля для ссылки:

<!-- index.wxml -->
<wxs src="./api.wxs" module="api" />
...
<text class="time">{{api.formatTime(item.id)}}</text>

Каждый модуль wxs имеет встроенный объект модуля.

Файл api.wxs и метод реализации формата времени:

var formatTime = function(time){
  // 获取当前时间
  var getUnix = function () {
    var date = getDate()
    return date.getTime()
  }
  // 获取今天零点时间
  var getTodayUnix = function () {
    var date = getDate()
    date.setHours(0)
    date.setMinutes(0)
    date.setSeconds(0)
    date.setMilliseconds(0)
    return date.getTime()
  }
  // 获取今年的1月1日零点时间
  var getYearUnix = function () {
    var date = getDate()
    date.setMonth(0)
    date.setDate(1)
    date.setHours(0)
    date.setMinutes(0)
    date.setSeconds(0)
    date.setMilliseconds(0)
    return date.getTime()
  }
  // 获取标准时间
  var getLastDate = function (time) {
    var date = getDate(time)
    var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1
    var day = date.getDay() < 10 ? '0' + (date.getDay()) : date.getDay()
    return date.getFullYear() + '-' + month + '-' + day
  }
  // 转换时间
  var getFormatTime = function (timestamp) {
    var now = getUnix()
    var today = getTodayUnix()
    var year = getYearUnix()
    var timer = (now - timestamp) / 1000
    var tip = ''
    if (timer <= 0) {
      tip = '刚刚'
    } else if (Math.floor(timer / 60) <= 0) {
      tip = '刚刚'
    } else if (timer < 3600) {
      tip = Math.floor(timer / 60) + '分钟前'
    } else if (timer >= 3600 && (timestamp - today >= 0)) {
      tip = Math.floor(timer / 3600) + '小时前'
    } else if (timer / 86400 <= 31) {
      tip = Math.ceil(timer / 86400) + '天前'
    } else {
      tip = getLastDate(timestamp)
    }
    return tip
  }
  return getFormatTime(+time)
}

// es6方法一样,导出formatTime方法
module.exports.formatTime = formatTime;

Здесь следует отметить, что получение текущего времени WXS не поддерживаетnew Date(), который имеет свой собственный методgetDate(). как использоватьnew Date()Такой же.

На данный момент это завершено, практический пример TodoList, простая функция, хороший пример для начала.

Я надеюсь, что это будет полезно для вас.Пожалуйста, подскажите мне некоторые недостатки.Я только что закончил читать примеры официальной документации.

Загрузка исходного кода:GitHub.com/CH563/в ДОЛ…

Пусть все получат повышение!