美文网首页前端大叔精选微信小程序
现学现卖微信小程序开发(二)

现学现卖微信小程序开发(二)

作者: 接灰的电子产品 | 来源:发表于2017-01-03 08:42 被阅读1329次

    现学现卖微信小程序开发(一)
    现学现卖微信小程序开发(二)
    现学现卖微信小程序开发(三):引入Rx,为小程序插上翅膀

    一个Todo应用的小程序版

    好的,那么下一步我们就先照猫画虎,新建一个todos文件夹,然后一套四样同名文件准备齐全

    新建todos目录和相关文件新建todos目录和相关文件

    先在app.json中报个到,在pages中加入 "pages/todos/todos"。接下来把首页 index.js 中的导航改为 ../todos/todos

    //事件处理函数
      bindViewTap: function() {
        wx.navigateTo({
          url: '../todos/todos'
        })
      },
    

    然后呢,我们简单的先写一个界面,其实什么都没有,就是一个view。把 todos.wxml 改成下面的模样:

    <!--todos.wxml-->
    <view class="container todo-list">
      
    </view>
    

    然后把导航栏标题设置一下,叫 Awesome Todos吧,把 todos.json 改成下面的样子:

    {
        "navigationBarTitleText": "Awesome Todos"
    }
    

    样式呢,也非常简单粗暴的来一个吧:

    .todo-list {
      display: block;
      padding: 40rpx;
      width: 100vw;
      margin: 0 auto;
    }
    

    快速搭建一个Web API

    好的,下面我们要写关键的 todos.js 了。在写之前,我们需要一个服务器提供数据,这里介绍一个可以非常快速便捷的搭建一个仿真Web API的利器:json-server。 使用 npm i -g json-server 安装,然后随便挑一个目录建一个todos-data.json 文件:

    {
      "todos": [
        {
          "id": 1,
          "desc": "have breakfast",
          "completed": false
        },
        {
          "id": 2,
          "desc": "have lunch",
          "completed": false
        },
        {
          "id": 3,
          "desc": "take a break",
          "completed": false
        },
        {
          "id": 4,
          "desc": "having fun",
          "completed": false
        },
        {
          "id": 5,
          "desc": "新的服务器版本不错",
          "completed": true
        }
      ]
    }
    

    这个时候,你的Web API就差一步之遥了,现在在命令行窗口敲入 json-server ./todos-data.json就大功告成了。

    json-server服务启动了json-server服务启动了

    你可以打开浏览器输入 http://localhost:3000/todos 看看是否返回的是我们的数据。这个Web API是完全RESTful的,也就是说

    • 查询所有待办事项:以GET方法访问http://localhost:3000/todos
    • 查询单个待办事项:以GET方法访问http://localhost:3000/todos/id,比如id是1,那么访问http://localhost:3000/todos/1
    • 更新某个待办事项:以PUT方法访问http://localhost:3000/todos/id
    • 删除某个待办事项:以DELETE方法访问http://localhost:3000/todos/id
    • 增加一个待办事项:以POST方法访问http://localhost:3000/todos

    回到正题,开始Todo的开发

    我们一开始的 todos.js 是这个样子的:

    const URL = 'http://localhost:3000/todos'
    
    let pageParams = {
      data: { todos: [], desc: '' }
    }
    
    pageParams.onLoad = function () {
      const that = this
      wx.request({
        url: URL,
        data: JSON.stringify({}),
        header: { 'content-type': 'application/json' },
        method: 'GET',
        success: res => {
          console.log(res.data)
          that.setData({
            todos: res.data
          })
        },
        fail: () => console.error('something is wrong'),
        complete: () => console.log('todos loaded')
      })
    }
    
    Page(pageParams)
    

    这段代码非常简单,创建一个pageParams对象并给本地数据初始化。然后定义onLoad生命周期函数,利用 wx.request 创建一个 HTTP GET 请求取得返回的数据,然后用setData去更新本地数据。注意一点 const that = this 是一个常用的避免 this 的context出现切换时出现问题的小技巧。再有就是我们无法直接写入data,只能使用setData方法来进行更新。

    那么我们看看是否成功吧,点击左侧的调试,然后点首页的头像进入我们的todo页面,当然现在界面上啥也没有,但Console中还是有料滴。

    Console中可以看到我们的Web API返回的结果Console中可以看到我们的Web API返回的结果

    既然API调通了,我们就来让结果显示到页面上吧,首先改造页面如下。

    <!--todos.wxml-->
    <view class="container todo-list">
      <block wx:for="{{todos}}" wx:for-item="todo" wx:key="todo.id">
        <view class="todo-item">
          <text class="desc">{{todo.desc}}</text>
        </view>
      </block>
    </view>
    

    这段代码中,view 是个视图容器,感觉可以把它想象成HTML中的div。微信小程序中除了 view 之外,目前还提供了 scroll-viewswiper 两种容器,顾名思义 scroll-view 是用于可滚动的场景,而 swiper 是用于可以手指滑动切换内容的场景。

    在组件上使用 wx:for 绑定一个数组,即可使用数组中各项的数据重复渲染该组件。wx:for-item 意思是设定数组当前元素的变量名。wx:key 设置列表中项目的唯一的标识符。注意提供wx:key可以提升重新渲染时的性能,所以尽量提供。

    block 是一个挺怪的设计,它不是一个可视化的元素,感觉纯粹为提供数据绑定而准备,在数据绑定时,以 block 来组织比较复杂的组件组合。所以block这一段的意思就是对于数组todos中的每一个todo,重复渲染下面这段

    <view class="todo-item">
      <text class="desc">{{todo.desc}}</text>
    </view>
    

    当然我们也需要拓展一下css,哦,不对,是wxss。

    .todo-list {
      display: block;
      padding: 40rpx;
      width: 100vw;
      margin: 0 auto;
    }
    .todo-item {
      display: flex;
      flex-direction: row;
      flex-basis: 1;
      justify-content: space-around;
      align-items: stretch;
      width: 80 vw;
      padding: 20rpx;
      border-bottom: 1rpx solid #ededed;
    }
    .desc {
      vertical-align: middle;
      flex-grow: 1;
    }
    

    现在看一下效果,列表成功显示了。

    todos列表todos列表

    事件的处理

    现在我们给Todos添加两个功能吧:Toggle(切换完成状态)和Remove(删除该事项)。这样的话,需要给todo的描述之前加一个完成状态的复选框以及一个在todo的描述之后的删除按钮。我们没有使用微信提供的 checkbox ,而是用 icon 组件和 wx:if 来做处理,目的也是多展示一些特性。

    <!--todos.wxml-->
    <view class="container todo-list">
      <block wx:for="{{todos}}" wx:for-item="todo" wx:key="todo.id">
        <view class="todo-item">
          <icon bindtap="toggleTodo" data-todo="{{todo}}" class="icon" type="success" wx:if="{{todo.completed}}"></icon>
          <icon bindtap="toggleTodo" data-todo="{{todo}}" class="icon" type="success_circle" wx:if="{{!todo.completed}}"></icon>
          <text bindtap="toggleTodo" data-todo="{{todo}}" class="desc">{{todo.desc}}</text>
          <icon bindtap="removeTodo" data-todo="{{todo}}" class="remove" type="clear"></icon>
        </view>
      </block>
    </view>
    

    上面的模版中,我们看到多了一些新面孔:

    • wx:if:这个比较好理解,就是条件渲染,在todo已完成的状态下显示一个icon,未完成状态下显示另一个icon。
    • bindtap:这个是什么呢?它是微信小程序提供的绑定事件的机制,其绑定表达式为:bind+事件="事件处理函数"。我们上面的例子中的 bindtap="toggleTodo" 就是对于tap(触碰后马上离开)事件处理是一个在Page中定义的叫 toggleTodo 的函数。
    • data-todo:很多时候我们需要在事件传递时携带一些数据过去,比如Toggle这个功能,我们需要在事件处理函数中知道是哪个todo要切换完成状态。data-todo就是定义要传输的数据用的,data表明是要在 事件中传输的数据,而后面的todo表明这个数据在dataset中的key,通过这个key我们可以在Page中使用 event.target.dataset.todo得到这个数据。这也意味着我们可以通过多个key传递多个数据。

    值的注意的一点是除了 bindXXX 这种绑定事件的形式外,还有一种形式是 catchXXX,它们的区别是 bind 事件绑定不会阻止冒泡事件向上冒泡,catch 事件绑定可以阻止冒泡事件向上冒泡。什么是冒泡呢?事件会继续向上(父组件或父节点)传递就是冒泡,反之就是非冒泡。

    在微信小程序中,冒泡的事件如下表列出的,其他如没有特殊的声明都是非冒泡事件

    事件 触发条件
    touchstart 手指触摸动作开始
    touchmove 手指触摸后移动
    touchcancel 手指触摸动作被打断,如来电提醒,弹窗
    touchend 手指触摸动作结束
    tap 手指触摸后马上离开
    longtap 手指触摸后,超过350ms再离开

    对于这些冒泡事件来说,如果我们要阻止其冒泡的行为,可以使用 catchXXX 来绑定事件。

    const URL = 'http://localhost:3000/todos'
    
    let pageParams = {
      data: { todos: [], desc: '' }
    }
    
    pageParams.onLoad = function () {
      const that = this
      wx.request({
        url: URL,
        data: JSON.stringify({}),
        header: { 'content-type': 'application/json' },
        method: 'GET',
        success: res => {
          console.log(res.data)
          that.setData({
            todos: res.data
          })
        },
        fail: () => console.error('something is wrong'),
        complete: () => console.log('get req completed')
      })
    }
    
    pageParams.toggleTodo = function (event) {
      const that = this
      const selectedTodo = event.target.dataset.todo
      const url = `${URL}/${selectedTodo.id}`
      const updatedTodo = Object.assign({}, selectedTodo, {completed: !selectedTodo.completed})
    
      wx.request({
        url: url,
        data: JSON.stringify(updatedTodo),
        header: { 'content-type': 'application/json' },
        method: 'PUT',
        success: res => {
          console.log(res.data)
          that.setData({
            todos: that.data.todos.map(todo => {
              if(todo.id === updatedTodo.id){
                return updatedTodo
              }
              return todo
            })
          })
        },
        fail: () => console.error('something is wrong'),
        complete: () => console.log('toggle req completed')
      })
    }
    
    pageParams.removeTodo = function (event) {
      const that = this
      const selectedTodo = event.target.dataset.todo
      const url = `${URL}/${selectedTodo.id}`;
      
      wx.request({
        url: url,
        data: JSON.stringify(selectedTodo),
        header: { 'content-type': 'application/json' },
        method: 'DELETE',
        success: res => {
          console.log(res.data)
          that.setData({
            todos: that.data.todos.filter(todo => todo.id !== selectedTodo.id)
          })
        },
        fail: () => console.error('something is wrong'),
        complete: () => console.log('delete req completed')
      })
    }
    
    Page(pageParams)
    

    接下来的事情就变的很简单,我们在 todos.js 中增加两个处理函数用于处理toggle和remove,事件处理函数有一个参数就是event。处理逻辑还是先提交HTTP请求处理服务器端数据,处理成功后再处理本地内存数据。

    当然 wxss 再更新一下:

    .todo-list {
      display: block;
      padding: 40rpx;
      width: 100vw;
      margin: 0 auto;
    }
    .todo-item {
      display: flex;
      flex-direction: row;
      flex-basis: 1;
      justify-content: space-around;
      align-items: stretch;
      width: 80 vw;
      padding: 20rpx;
        border-bottom: 1rpx solid #ededed;
    }
    .icon {
      vertical-align: middle;
    }
    .remove {
      float: right;
      align-self: flex-end;
    }
    .desc {
      vertical-align: middle;
      flex-grow: 1;
    }
    

    现在的效果是这样滴

    可以工作的todo,当然还没有新增todo的功能可以工作的todo,当然还没有新增todo的功能

    新增Todo、过滤器、优化代码结构、引入Rx等话题我们后面继续,这次就先到这里。

    相关文章

      网友评论

      • f51d69bacc72:您好,请问一下请求http://localhost:3000/todos时报错域名无效怎么办?
        f51d69bacc72:@接灰的电子产品 嗯,好了,谢谢:)
        接灰的电子产品:@车前晓 在项目设置中开启“开发环境不校验请求域名及TLS版本“,或者可以选择无AppId开发
      • 向阳雨下:写的很详细,比自己看文档好多了,mark
      • wow胖子:为什么todo列表点一下就回到初始页面?
        接灰的电子产品:清空了?这不是程序可以造成的了,看看你的开发工具环境是不是没配好或者有问题了
        wow胖子:console刷的一下就清空了,回到了初始页面,看不到是不是出错了
        接灰的电子产品:@wow胖子 你看看console中有提示错误吗
      • 二搬:我是个忧郁的人,让无聊的风吹进我的信仰
      • d5a1d0843c21:有用
        d5a1d0843c21: @接灰的电子产品 已关注,来年我们项目组估计也要小程序开发,增加入口渠道🤗👍👍👍
        接灰的电子产品:@Scott166 谢谢支持,持续关注哦
      • HenrryZ:老哥 windows下怎么用这个json-server
        接灰的电子产品:安装node 然后一样的npm i -g json-server

      本文标题:现学现卖微信小程序开发(二)

      本文链接:https://www.haomeiwen.com/subject/pmpgvttx.html