微信开发运营小程序微信小程序

微信小程序实例-历史上的今天

2018-01-19  本文已影响345人  胡萝卜须摇头玩

目录:

一、 小程序相关知识
(1) 文件类型
(2) 目录结构
(3) 组件的使用
(4) 基本语法
(5) 相关API(Application Programming Interface)
二、 开发前准备
三、 开发实战
(1)界面设计
(2)界面实现
(3)数据处理

自从微信小程序正式发布以来,涌现出了大量优秀的作品,如“智行火车票”、“摩拜单车”、“知乎热榜”、“识图取字”等等。对于勇于走在技术前沿和热爱尝试新鲜事物的开发者们来说,当然也会开发一款属于自己的小程序。本篇教程就用一个简单的小例子来教大家如何开发一款小程序。
 
适合读者:对网页前端开发有基本了解的小程序开发小白
小程序名称:历史上的今天
模仿效果(其他小程序):

8.gif

所需资料:

具体步骤:

一、 小程序相关知识
(1) 文件类型

小程序中的文件可分为4种类型,后缀名分别为“.wxml ”、“.wxss ”、“.js ”、“.json”。其中,后缀名为 “wxml” 的文件为各个页面的布局文件,描述页面所包含的具体内容,类似 Web 编程中的 html 文件。如以下新建项目的首页默认代码:

<!--index.wxml-->
<view class="container">
  <view class="userinfo">
    <button wx:if="{{!hasUserInfo && canIUse}}" open-type="getUserInfo" bindgetuserinfo="getUserInfo"> 获取头像昵称 </button>
    <block wx:else>
      <image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" background-size="cover"></image>
      <text class="userinfo-nickname">{{userInfo.nickName}}</text>
    </block>
  </view>
  <view class="usermotto">
    <text class="user-motto">{{motto}}</text>
  </view>
</view>
效果预览图: image.png

 
.wxss后缀的则类似css文件,语法上虽和css基本相同,但也做了一些扩充和修改:

/**index.wxss**/
.userinfo {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.userinfo-avatar {
  width: 128rpx;
  height: 128rpx;
  margin: 20rpx;
  border-radius: 50%;
}
image.png

 
js 文件用来处理程序的交互和逻辑,如响应用户的点击、获取用户的位置、进行网络请求等等。其中的 Page()函数,用来注册一个页面,指定页面的初始数据(data),另外还包括生命周期函数(onLoad、onReady、onShow、onHide、onUnload),事件处理函数(bindViewTap)等等。

//index.js
//获取应用实例
const app = getApp()

Page({
  data: {
    motto: 'Hello World',
    userInfo: {},
    hasUserInfo: false,
    canIUse: wx.canIUse('button.open-type.getUserInfo')
  },
  //事件处理函数
  bindViewTap: function() {
    wx.navigateTo({
      url: '../logs/logs'
    })
  },
  onLoad: function () {
    if (app.globalData.userInfo) {
      this.setData({
        userInfo: app.globalData.userInfo,
        hasUserInfo: true
      })
    } else if (this.data.canIUse){
      // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
      // 所以此处加入 callback 以防止这种情况
      app.userInfoReadyCallback = res => {
        this.setData({
          userInfo: res.userInfo,
          hasUserInfo: true
        })
      }
    } else {
      // 在没有 open-type=getUserInfo 版本的兼容处理
      wx.getUserInfo({
        success: res => {
          app.globalData.userInfo = res.userInfo
          this.setData({
            userInfo: res.userInfo,
            hasUserInfo: true
          })
        }
      })
    }
  },
  getUserInfo: function(e) {
    console.log(e)
    app.globalData.userInfo = e.detail.userInfo
    this.setData({
      userInfo: e.detail.userInfo,
      hasUserInfo: true
    })
  }
})

 
json文件为小程序的配置文件,分为page.json、app.json 和 project.config.json三种。

//app.json
{
  "pages": [
    "pages/index/index",
    "pages/logs/index"
  ],
  "window": {
    "navigationBarTitleText": "Demo"
  },
  "tabBar": {
    "list": [{
      "pagePath": "pages/index/index",
      "text": "首页"
    }, {
      "pagePath": "pages/logs/logs",
      "text": "日志"
    }]
  },
  "networkTimeout": {
    "request": 10000,
    "downloadFile": 10000
  },
  "debug": true
}

  

(2) 目录结构

新建项目后的默认文件目录如下图所示。最外层的“pages”为小程序中各个页面的所在文件夹,其中的每个子文件夹都对应着不同的页面,如图中的“index”和“log”文件夹分别对应着小程序的“首页”和“日志”两个页面。
顾名思义,“utils”为工具类文件夹,开发者可以将与字符串处理、日期处理或网络请求有关的代码文件放在该文件夹中。
最外层剩余的四个文件则依次为“app.js”、“app.json”、“app.wxss”、“project.config.json”,均是对小程序进行全局属性设置的文件。


q.png
(3)组件的使用

组件是视图层的基本组成单元。如手机应用中常见的文本、按钮、输入框、图片、滑动选择器等。小程序为开发者提供了一系列基础组件,自带一些与微信风格类似的样式,开发者可以通过组合这些基础组件进行快速开发。
一个组件通常包括开始标签和结束标签,属性用来修饰这个组件,内容在两个标签之内。如按钮组件“button”:

<button>点击设置以上按钮disabled属性</button>

官方为开发者提供了详细的小程序组件说明及使用帮助文档,本例中我们只需其中的 3 个组件即可实现相关功能。

<view style="height: 300px;line-height:300px;background-color:#F76160;color:white;text-align:center;">
  历史上的今天
</view>

效果图:

image.png
<!--pages/scrollview/scrollview.wxml-->
<view >
<!--垂直滚动-->
  <view >垂直滚动</view>
  <scroll-view scroll-y style="height: 200px;" >
    <view id="green" style="width:100%;height:100px;background-color:green;">green</view>
    <view id="red" style="width:100%;height:50px;background-color:red;">red</view>
    <view id="yellow" style="width:100%;height:100px;background-color:yellow;">yellow</view>
    <view id="blue" style="width:100%;height:50px;background-color:blue;">blue</view>
  </scroll-view>

<!--水平滚动-->
  <view style="margin-top:50px;">水平滚动</view>
<scroll-view scroll-x="true" style=" white-space: nowrap; display: flex" >
<!--  display: inline-block-->
  <view style="background: green; width: 150px; height: 100px; display: inline-block">green</view>
  <view style="background: red; width: 80px; height: 100px; display: inline-block" >red</view>
  <view style="background: yellow; width: 150px; height: 100px; display: inline-block">yellow</view>
  <view style="background: blue; width: 80px; height: 100px; display: inline-block">blue</view>
</scroll-view>
</view>
1.gif
<text style="color:red;font-size:56rpx;">
  微信小程序是一种全新的连接用户与服务的方式,它可以在微信内被便捷地获取和传播,同时具有出色的使用体验。
</text>

效果图:

image.png
(4)基本语法

   ① 变量定义及使用
小程序中的变量定义在对应页面 js 文件里的 Page - data 中,在wxml页面使用的时候需用双大括号包裹起来。如下所示:

<!--pages/variable/variable.wxml-->
<view style='width:100%;margin-top:100px;text-align:center;'>
  <text>当前时间:{{curTime}}</text> 
  <button type="primary" style='margin:50rpx;' bindtap='refreshTime'>点击更新时间</button>
</view>
// pages/variable/variable.js
Page({
  data: {
    curTime:""
  },
  refreshTime: function () {
    var now = new Date();
    var h = now.getHours();
    var m = now.getMinutes();
    var s = now.getSeconds();
    var time = h + ':' + m + ':' + s;
    //改变变量的值
    this.setData({
      curTime:time
    });
  },
})

效果预览图如下:


2.gif

   ② for循坏
当需要实现类似列表的效果时,可在组件上使用 “wx:for” 语句来重复渲染。默认数组的当前项的下标变量名默认为index,数组当前项的变量名默认为item,当然也可以改成自己想要使用的变量名,如:wx:for-item="phone" wx:for-index="idx" 。

<!--pages/for/for.wxml-->
<view wx:for="{{['苹果','华为','小米','魅族']}}" wx:for-item="phone" wx:for-index="idx" style="text-align:center;margin-top:50px;font-size:30px;">
  {{phone}}
</view>
image.png

   ③ 点击事件
在组件开始标签中添加“ bindtap="click" ”,并在js函数中实现该方法,可为其添加点击事件。

<button type="primary" style='margin:50rpx;' bindtap='click' >点击事件</button>

传参:
当需要获取点击对象的某些属性数据时,可在其开始标签中添加“data-参数名="参数值"”(去掉最外层引号),然后在点击事件中使用“e.currentTarget.dataset.参数名”获取相应的值。
示例代码:

<!--pages/click/click.wxml-->
<view style='width:100%;margin-top:100px;text-align:center;'>
  <text>这是:{{name}}</text> 
  <button type="primary" style='margin:50rpx;' bindtap='click' data-phone="iPhone">苹果</button>
  <button type="primary" style='margin:50rpx;' bindtap='click' data-phone="Huawei">华为</button>
  <button type="primary" style='margin:50rpx;' bindtap='click' data-phone="Xiaomi">小米</button>
</view>
// pages/click/click.js
Page({
  data: {
    name:""
  },

  click:function(e){
    var phone = e.currentTarget.dataset.phone;
    this.setData({
      name:phone
    });
  }
})

 

效果预览图: 6.gif
(5)相关API(Application Programming Interface)

   ① wx.request(OBJECT)
发起网络请求。需要注意的是,在使用该 API 前需在微信公众平台小程序的后台中对服务器域名进行配置,具体操作步骤前面已说明,此处不再赘述。

OBJECT参数说明: 2018-01-20_100655.png success返回参数说明: image.png

示例代码:

<!--pages/network/network.wxml-->
<view style='padding:20rpx;'>
  <text>{{str}}</text>
  <button type="primary" style='margin:50rpx;' bindtap='getRequestStr'>点击进行网络请求</button>
</view>
// pages/network/network.js
Page({
  data: {
    str:"测试文本"
  },

  getRequestStr:function(){
    var that=this;
    wx.request({
      url: 'http://www.ipip5.com/today/api.php?type=txt', //仅为示例,并非真实的接口地址
      header: {
        'content-type': 'application/json' // 默认值
      },
      success: function (res) {
        console.log(res.data);
        that.setData({
          str: res.data
        });
      }
    })
  }
})

效果预览图:


3.gif

   ② wx.navigateTo(OBJECT)
跳转到应用内的某个页面。
OBJECT 参数说明:

image.png
使用方法(navigate2为要跳转的页面):
wx.navigateTo({
  url: 'navigate2'
})

很多时候,跳转的页面之间需要进行参数的传递。比如“淘宝”APP中,当搜索关键词“手机”的时候,如果用户对某款手机感兴趣,会点击查看它的具体参数配置,那么在跳转后的页面中就需要知道用户到底点击了哪一项,也就是选择了哪款手机。
 
小程序页面之间的参数传递方法与Web开发类似,在要跳转的 url 后加上“?”,后跟参数名和参数值,多个参数之间用“&”号连接。

wx.navigateTo({
  url: 'navigate2?phone=xiaomi'
})

 
然后在跳转后的页面中使用“options.参数名”获取传过来的参数值:

onLoad: function (options) {
    var phone = options.phone;
    console.log(phone);   //xiaomi
}

示例代码:
navigate 页面:

<!--pages/navigate/navigate.wxml-->
<button type="primary" style='margin:50rpx;' bindtap='toNext'>点击跳转页面</button>
// pages/navigate/navigate.js
Page({
  toNext: function (e) {
    var toUrl = 'navigate2?phone=小米';
    wx.navigateTo({
      url: toUrl
    })
  }
})

 
navigate2 页面:

<!--pages/navigate/navigate2.wxml-->
<view style='width:100%;margin-top:100px;text-align:center;'>
  这是:{{mPhone}}
</view>
// pages/navigate/navigate2.js
Page({
  data: {
    mPhone:""
  },

  onLoad: function (options) {
    var phone = options.phone;
    this.setData({
      mPhone:phone
    });   
  }
})
效果预览图: 7.gif

   ③ wx.getSystemInfo(OBJECT)
获取设备信息。
OBJECT参数说明:

image.png
示例代码:
wx.getSystemInfo({
  success: function(res) {
    console.log(res.model)  //手机型号
    console.log(res.pixelRatio)  //设备像素比
    console.log(res.windowWidth)  //可使用窗口宽度
    console.log(res.windowHeight)  //可使用窗口高度
    console.log(res.language)  //微信设置的语言
    console.log(res.version)  //微信版本号
    console.log(res.platform)  //客户端平台
  }
})

更多使用方法可查看这里

二、 开发前准备

工欲善其事,必先利其器。为能顺利完成这个实例,首先需要准备一个小程序的开发者账号,详细步骤可查看这里;小程序所需的数据可从以下
API 接口获得(本实例使用的数据为 json 格式)。
txt格式:http://www.ipip5.com/today/api.php?type=txt
json格式:http://www.ipip5.com/today/api.php?type=json

返回数据示例:

{
    "today": "0167081765e5",
    "result": [
        {
            "year": "395\n",
            "title": "7f579a6c5e1d56fd520688c24e3a897f7f579a6c5e1d56fd548c4e1c7f579a6c5e1d56fd"
        },
        {
            "year": "1600\n",
            "title": "52674f5c5bb653615c145fb7968600b75df45c14536151fa751f"
        },
        {
            "year": "1676\n",
            "title": "6b4c52674f5c66f25bb65f176717520765af79d100b7536174e65229901d4e16"
        },
        {
            "year": "1706\n",
            "title": "7f8e56fd653f6cbb5bb6672c6770660e00b75bcc5170514b679751fa751f4e8e7f8e56fd9ebb77016ce258eb987f"
        }
    ]
}

在小程序中使用网络相关的 API 时,需要事先在微信公众平台中对服务器域名进行配置。


2018-01-19_172737.png

使用管理员手机微信扫描二维码验证后,在“requests合法域名”中填写 API 的一级域名并保存。


image.png

※注:设置完后需重新启动微信开发者工具。

三、 开发实战
(1)界面设计

在动手之前,先对小程序的界面进行简单的设计。


home.png

点击首页中的每一项,可跳转到当年这一天的事件详情页面。


page_1.png
(2)界面实现

  目录结构:新建项目后,首先要将本实例需要的所有页面创建出来。项目目录结构如下:

image.png

  导航栏标题:导航栏的标题可在“app.json”文件中进行设置,将 “window”-“navigationBarTitleText” 更改为“历史上的今天”。代码如下:

//app.json
{
  "pages": [
    "pages/index/index",
    "pages/logs/logs"
  ],
  "window": {
    "backgroundTextStyle": "light",
    "navigationBarBackgroundColor": "#fff",
    "navigationBarTitleText": "历史上的今天",
    "navigationBarTextStyle": "black"
  }
}

  首页:整个页面分为上、下两大部分,分别为上方的“日期”及下方的“事件列表”,中间使用分隔线隔开。由于下面的事件列表是可以滚动的(当当天事件足够多的时候),因此需要用到scroll-view。

此时index.wxml的代码如下:

<view style="width: 100%;height:100px;background-color: red;">
</view>
<scroll-view style='width: 100%;height:300px;background-color:blue;' scroll-y>
</scroll-view>

效果预览图如下:


image.png

这里有一个问题就是,底部的滚动视图需要占据所有的剩余高度,但是由于用户的不同,各个机型的屏幕宽高是不一样的,因此需要动态计算小程序的可使用窗口高度,再减去顶部的红色视图高度,即可得到滚动视图的高度。

<!-- index.wxml -->
<view style="width: 100%;height:100px;background-color: red;">
</view>
<scroll-view style='width: 100%;height:{{scrollViewHeight}}px;background-color:blue;' scroll-y>
</scroll-view>
//index.js
Page({
  data: {
    scrollViewHeight:200
  },  
  onLoad: function () {
    var that=this;
    //获取屏幕高度
    wx.getSystemInfo({
      success: function (res) {
        that.setData({
          scrollViewHeight: res.windowHeight - 100
        });
      }
    });
  }
})

效果预览图:


image.png

onLoad函数中之所以要用 “var that=this”,是因为在 javascript 语言中,this代表着当前的对象,它在程序中随着执行的上下文随时会变化。在本例中回调函数对象相对于getSystemInfo点击事件函数对象已经发生了变化。所以已经不是原来的页面对象了。解决的办法就是复制一份当前的对象。所以我们有了这个重要的语句:

var that=this;//把this对象复制到临时变量that.

 

然后添加下方“事件列表”部分的代码:
index.wxml 页面代码如下:

<!-- index.wxml -->

<!-- 顶部日期 start -->
<view style="width: 100%;height:100px;color:#67CDCD;font-size:44rpx;font-weight:bold;line-height:100px;text-align:center;">
  13月32日
</view>
<!-- 顶部日期 end -->
<!-- 中间分隔线 start -->
<view style="width:100%;height:1rpx;background-color:gray;"></view>
<!-- 中间分隔线 end -->
<!-- 底部滚动视图 start -->
<scroll-view style="width: 100%;height:{{scrollViewHeight}}px;" scroll-y>
  <view wx:for="{{[1,2,3,4,5,6,7,8,9,10]}}" wx:for-item="item" wx:for-index="idx">
    <view style="height:1rpx;background-color:gray;margin:0 20rpx;"></view>
    <view style="height:100rpx;line-height:100rpx;padding-left:20rpx;text-overflow: ellipsis;white-space: nowrap; overflow: hidden;" 
bindtap='viewDetail' data-year="{{item.year}}" data-title="{{item.title}}">
      2030年, iPhone 30 正式发布
    </view>
  </view>
</scroll-view>
<!-- 底部滚动视图 end -->
微信图片_20180119213450.jpg

点击各个事件,可跳转到显示事件详情的detail页面。
detail.wxml 页面代码如下:

<!--pages/detail/detail.wxml-->

<!-- 顶部日期 start -->
<view style="width: 100%;height:100px;color:#67CDCD;font-size:44rpx;font-weight:bold;line-height:100px;text-align:center;">
  2030年13月32日
</view>
<!-- 顶部日期 end -->
<!-- 中间分隔线 start -->
<view style="width:100%;height:1rpx;background-color:gray;"></view>
<!-- 中间分隔线 end -->
<!-- 底部视图 start -->
<view style="padding:20rpx;height:{{viewHeight}}px;" >
  iPhone 30 正式发布
</view>
<!-- 底部视图 end -->
微信图片_20180119225935.jpg
(3)数据处理

最后只要获取 API 接口中的数据,并将其显示到界面上就可以了。

//发送请求
wx.request({
    url: "https://www.ipip5.com/today/api.php?type=json",
    header: {
        "content-type": "application/x-www-form-urlencoded"
    },
    method: 'POST',
    success: function (res) {
        try {
            that.setData({
            items:res.data.result,
            dateOfToday: res.data.today
            });
        } catch (e) {

        }
        wx.hideLoading();
   },
   fail: function (err) {
       console.log("error:" + err);
       wx.hideLoading();
   }
});

最终源码如下:
index页面

<!-- index.wxml -->

<!-- 顶部日期 start -->
<view style="width: 100%;height:100px;color:#67CDCD;font-size:44rpx;font-weight:bold;line-height:100px;text-align:center;">
  {{dateOfToday}}
</view>
<!-- 顶部日期 end -->
<!-- 中间分隔线 start -->
<view style="width:100%;height:1rpx;background-color:gray;"></view>
<!-- 中间分隔线 end -->
<!-- 底部滚动视图 start -->
<scroll-view style="width: 100%;height:{{scrollViewHeight}}px;" scroll-y>
  <view wx:for="{{items}}" wx:for-item="item" wx:for-index="idx">
    <view style="height:1rpx;background-color:gray;margin:0 20rpx;"></view>
    <view style="height:100rpx;line-height:100rpx;padding-left:20rpx;text-overflow: ellipsis;white-space: nowrap; overflow: hidden;" bindtap='viewDetail' data-year="{{item.year}}" data-title="{{item.title}}">
      {{item.year}} {{item.title}}
    </view>
  </view>
</scroll-view>
<!-- 底部滚动视图 end -->
//index.js
Page({
  data: {
    scrollViewHeight:200,
    dateOfToday:'',
    items:[]
  },  
  onLoad: function () {
    var that = this;

    //显示加载动画
    wx.showLoading({
      title: '正在加载',
    });

    //获取屏幕高度
    wx.getSystemInfo({
      success: function (res) {
        console.log(res.windowHeight);
        that.setData({
          scrollViewHeight: res.windowHeight - 100
        });
      }
    });

    //获取当前日期
    var myDate = new Date();
    var dateStr = myDate.getFullYear() + '年' + (myDate.getMonth()+1) + '月' + myDate.getDate() + '日';
    this.setData({
      dateOfToday: dateStr
    });

    //发送请求
    wx.request({
      url: "https://www.ipip5.com/today/api.php?type=json",
      header: {
        "content-type": "application/x-www-form-urlencoded"
      },
      method: 'POST',
      success: function (res) {
        console.log("success:" + res);
        try {
          that.setData({
            items:res.data.result,
            dateOfToday: res.data.today
          });
        } catch (e) {

        }
        wx.hideLoading();
      },
      fail: function (err) {
        console.log("error:" + err);
        wx.hideLoading();
      }
    });
  },
  viewDetail: function (e) {
    var title = e.currentTarget.dataset.title;
    var year = e.currentTarget.dataset.year;
    var url = '../detail/detail?title=' + title + '&year=' + year + '&date=' + this.data.dateOfToday;
    wx.navigateTo({
      url: url
    })
  },
})

 

detail页面

<!--pages/detail/detail.wxml-->

<!-- 顶部日期 start -->
<view style="width: 100%;height:100px;color:#67CDCD;font-size:44rpx;font-weight:bold;line-height:100px;text-align:center;">
  {{dateOfToday}}
</view>
<!-- 顶部日期 end -->
<!-- 中间分隔线 start -->
<view style="width:100%;height:1rpx;background-color:gray;"></view>
<!-- 中间分隔线 end -->
<!-- 底部视图 start -->
<view style="width: 100%;height:{{viewHeight}}px;" >
  {{detail}}
</view>
<!-- 底部视图 end -->
// pages/detail/detail.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    dateOfToday:"",
    detail:""
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    console.log("options:" + options);
    var year = options.year;
    var date = options.date;
    var title = options.title;
    this.setData({
      dateOfToday: year + "年" + date,
      detail: title
    });
  }
})

 

附:源码下载
更多有关小程序的学习视频,可参考这里
如有错误,敬请批评指正!

上一篇下一篇

猜你喜欢

热点阅读