这篇文章是最近看知晓课堂时尝试做小程序而get到的一些不系统的知识,以及遇到的部分问题或者教程中比较奇怪的地方和解决方法的汇总,比较散乱。遇到的问题和解决方案直接戳 问题里面找。demo源码:voezy/zxkt

部分知识要点

第一章

利用前端技术栈,WXML 与 WXSS(与 html 和 css 同源)与 js。
与普通的 App 不同的是,小程序的语言使用网页前端的技术栈,并且使用 JavaScript 运行环境,相当于是一个浏览器。
但是,小程序也并非是单纯的 HTML5。与普通的 HTML5 不同的是,小程序具 有高级的硬件处理接口(例如蓝牙、重力感应等),同时运行环境也更接近原生 应用,效率更高。
已经绑定其他的公众号、小程序、个人号的邮箱,不能重新注册新的小程序。也就是说,在微信里与微信号绑定的邮箱,或是在公众平台注册公众号所用过的邮箱,是不能用于注册小程序的。

第二章

app.json记录小程序的基础配置,如:

  • 小程序的所有页面路径
  • 小程序全局界面表现
  • Tab 标签页配置
  • 网络超时
  • 调试模式开启或关闭

pages 文件夹与 app.json 配置的联系
在 app.json 中,pages 数组是必填的。它规定小程序中所有页面的地址,同时规定了小程序启动时的首页, pages 数组的首位所指的页面就是首页。
app.json 还能配置更多选项。

第三章

  • 长度单位 rpx(responsive pixel)

在RPX中,所有手机的屏幕宽度都会被固定为750rpx,实际像素以宽度750rpx为标准进行调整。
微信官方提供的最佳实践是,在小程序设计过程中,使用 iPhone 6 的屏幕尺寸 作为设计稿标准。这样,开发者在开发过程中,只需直接对尺寸除以 2,就能正确地配置视觉元素的尺寸。

  • view标签与flex布局。
  • 按钮

open-type,当属性是getUserInfo,声明按钮事件是获取用户资料
bindgetuserinfo,绑定回调函数,参数是要处理用户资料的js函数。
上面两个属性放到按钮中,可以使得点击这个按钮时,获取用户资料并进行一定的处理。

  • 返回的用户资料对象中,部分个人信息在 detail.userInfo
  • 数据绑定

bindgetuserinfo绑定的获取用户资料后用于处理的回调函数中,用this.setData可以设定一些能够被页面所利用的数据(作用好像类似于传递数据给模板引擎),比如,page中有这样一个函数是被bindgetuserinfo绑定的(即按钮中有bindgetuserinfo='getProfile'),

  getProfile(res) {
    this.setData({
      "profile": res.detail.userInfo
    })
  },

那么,在 wxml 中,就可以用''来获取用户资料中的头像图片链接了。setData设定的数据可以在开发者工具的控制台中AppData选项卡看到,要点击这个绑定了处理函数的按钮,让getProfile先作处理和调用,才能看到设定的数据。

  • 设定默认数据

用户刚进入页面时,需要显示一些默认数据的话,
Page({})中直接设定。比如

  Page({
    data: {
      ...  
    }
  })
  • 教程中,函数toDetailPage()之后设置数据的原因

这个方法是点击某篇文章之后所调用的,因此,这篇文章的阅读状态有可能发生改变,为了使得首页文章的阅读状态保持最新,需要利用addReadStatus(this.data.articles)处理文章数据,然后再设置一次articles的数据,就能使首页阅读状态保持最新。
所以toDetailPage()的后面需要这句this.setData({articles: this.addReadStatus(this.data.articles)})

  • 分享按钮

查看官方文档可知,”在 Page 中定义 onShareAppMessage 函数,设置该页面的转发信息。”

  • 只有定义了此事件处理函数,右上角菜单才会显示 “转发” 按钮
  • 用户点击转发按钮的时候会调用
  • 此事件需要 return 一个 Object,用于自定义转发内容

第八章

使用page{width: 100%; height:100%}使元素充满整个屏幕

第九章

includes方法。

遇到一些问题

第三章

设置资料缺失时的显示,第五段,“我们在welcome.wxml中,新增data…”应该是在welcome.js中新增data。

第四章

index/index.js中,设置路由跳转,函数toDetailPage要放在pages里面。主要是没有展示清楚。

第五章

1.例子代码中pageLimit似乎没有定义。

2.方法addReadStatus中,每一篇文章加入阅读状态之后push到newArticles那一句,newArticles.push(movie)中的movie应该改为article。

3.还有,所有的setStorageSync或者getStorageSync里面的READED_ARTICLES都应该加上引号,因为这个参数类型是字符串,不然会有对象未定义的错误。

4.在说明重新打开小程序也需要给文章加上阅读状态那一段,对于函数getArticles的修改说明似乎是有误或者说漏了点什么。
只简单地写道:

  // pages/index/index.js
  this.setData({
    articles: oldArticles.concat(this.addReadStatus(data)),
    loading: false
  })

首先,这个oldArticles就和pageLimit一样,缺少了声明(本来以为只是我忘了加,回去翻了下电子书搜索了一下发现代码真的没有定义这两个)。可以与pageLimit、isEnd一起在前面先声明。
然后,给出的这个修改代码应该是只有点击“加载更多”之后设置数据的修改,没有刚刚打开小程序时加载前四条所应做的修改。
我的修改方案是,声明了oldArticles,然后在设置第一页(前4条)时,把处理过(加上阅读状态)的文章对象数组用Object.assign方法赋给oldArticles, 再然后设置的articles数据就是这个oldArticles。在加载后面两条时,把oldArticles与处理过的lastPage(后两条)利用concat合并在一起。
在做出对oldArticles的声明的前提下,我个人对getArticles函数做的完整修改如下:

  // pages/index/index.js
  // ...省略文章数据

  let isEnd = false
  const pageLimit = 4
  let oldArticles = []
  // ...省略一些函数

  getArticles: function (isFirstPage) {
    if (!isEnd && !this.data.loading) {
      this.setData({ loading: true })
      setTimeout( () => {
        if (isFirstPage) {
          oldArticles = Object.assign(this.addReadStatus(firstPage))
          this.setData({
            articles: oldArticles,
            loading: false
          })
        } else {
          this.setData({
            articles: oldArticles.concat(this.addReadStatus(lastPage)),
            loading: false
          })
          if (lastPage.length < pageLimit) {
            isEnd = true
            this.setData({ loadMoreText: '已无更多' })
          }
        }
      }, 1000)
    }
  },

然后,要查看修改是否生效,教程似乎只是给wxml某些元素加类,这没什么用,因为教程还没有提到wxss的修改。所以我在标题后面加了个简单的阅读状态提示。

  // pages/index/index.wxml
  // ...
  <view data-id="{{ article.id }}" bindtap='toDetailPage'>{{ article.title }}|{{ article.isReaded?'cliked':'uncliked' }}</view>
  // ...

不考虑美观的前提下可以确认已读状态是否生效。点击过的会显示cliked,没有的显示uncliked。

5.emmm…然后还没完,就是分享按钮的设置
分享按钮是指文章页的分享按钮,因此是在pages/detail/index.wxml中修改(其实直接在pages目录右键新建page生成的是pages/detail/detail.wxml
这句<button open-type="share">分享<button/>在教程中说改成<button plain="true" open-type="share" />
然后就开始给article-share-btn这个类加样式,然而按钮的类还没有加上去。把class='article-share-btn'给加上去就可以了。
也就是变成<button class='article-share-btn' plain="true" open-type="share" />

第七章

完整的app.json:

{
  "pages": [
    "page/index/index",
    "page/map/map"
  ],
  "tabBar": {
    "color": "#7A7E83",
    "selectedColor": "#3cc51f",
    "borderStyle": "black",
    "backgroundColor": "#ffffff",
    "list": [
      {
        "pagePath": "page/index/index",
        "iconPath": "image/weather_gray.png",
        "selectedIconPath": "image/weather.png",
        "text": "天气"
      },
      {
        "pagePath": "page/map/map",
        "iconPath": "image/map_gray.png",
        "selectedIconPath": "image/map.png",
        "text": "地图"
      }
    ]
  }
}

然后map.xwml里map标签应以'/>'结束。教程少了'/'

第八章

  • 图片问题

自己找图片,根据教程的大概意思,放到相应的目录中。好了,我后来把心知的图片链接直接放页面图片链接里了。。。它的图片链接恰好是天气代码+'.png',所以可以在页面data中加一个weatherCode,把心知天气存图片的服务器链接加上天气代码'.png'就获取了相应的天气图片。。。

  • 通过经纬度,利用腾讯地图api获取城市信息。

就是要利用定位出来的经纬度,确定所在地的城市名,用这个城市名在心知天气获取当地天气。
所以来到腾讯地图的官网,http://lbs.qq.com/ ,注册登录,然后是建立一个开发者秘钥。
并没有像知晓程序的教程说的那样简单直接,我是没有那么简单就获取到城市。他说的好像是腾讯地图的web开发-URI API-逆地址解析?大概弄了一下,发现没能获取到城市信息。然后转移目标。
然后看到顶部导航栏-开发-微信小程序开发-微信小程序JavaScript SDK,试试吧。。

点击这个微信小程序JavaScriptSDK,然后按照它所说,下载微信小程序JavaScriptSDK v1.0,解压后有qqmap-wx-jssdk.min.jsqqmap-wx-jssdk.js,随便选一个,就选压缩过的min版吧,把qqmap-wx-jssdk.min.js放到小程序项目的page/index目录下,然后,在index.js开头加上var QQMapWX = require('./qqmap-wx-jssdk.min')
然后就是大概这样的操作

  let demo = new QQMapWX({
    key: '********************' // 必填
  });

  demo.reverseGeocoder({
    location: that.data.location,
    success: function (res) {
    },
    fail: function (res) {
    },
    complete: function (res) {
    },
  });

location就是之前用wx.getLocation获取到的经纬度数据,这样子成功调用之后的res.result.address_component.city便是城市名称了,可以把它赋给这个页面的data中的city

再然后,因为我比较懒心知天气的api再小程序里操作起来也有一点麻烦,就直接用它的测试api了(毕竟教程基本上也只是在玩具式编程),测试api见https://www.seniverse.com/doc#now-get
只要用wx.request去获取https://api.seniverse.com/v3/weather/now.json?key=你的key&location=beijing&language=zh-Hans&unit=c返回的数据就可以得到参数location市的天气数据了。上面再腾讯地图拿到的城市名就是这么用的,但其实不用城市名,只用经纬度也可以获取天气。。。而且这样的天气可能更细致精确?但是城市名还是要的,因为要在天气详情页显示出来。因为这是个测试api,所以以后某个时间有可能是会失效的,这个要注意。

  • 再然后的话,就是map.js的操作。

主要操作和教程讲的差不多。它有所欠缺的地方就是说好的全国省会城市数据没有给整理出来(难道要结束了才发源码??源码参考也一天一更不好吗),还有就是index.jsonShow里面的reloadData方法没有说清楚。

我有整理出来全国省会城市的经纬度,不过貌似准确度有点不行。

教程的意思应该是在天气详情页每次onShow时,检查全局的城市是否已被指定(默认为null,非null就是在地图页被点击指定了),
如果已被指定,那么就用reloadData方法重新获取城市和天气数据。reloadData方法应该是自己定义的,但是教程没有说明。
我在index.jsonShowreload定义大概如下:

  reloadData: function() {
    let that = this
    let app = getApp()

    that.setData({
      city: app.globalData.currentCity,
    })
    that.getWeather()
  },

  onShow: function () {
    let app = getApp()
    console.log('\n(onShow)\n全局城市: ' + app.globalData.currentCity + ', 上一次获取的城市: ' + this.data.city)
    if(app.globalData.city == null) {
      console.log('第一次加载程序,从定位获取城市和天气\n--------')
    } else {
      console.log('正获取天气数据\n--------')
      this.reloadData()
    }
  },
  • 最后就是页面的展示。

页面的改动就是把原来在index.wxml写死的城市、天气和温度改成page中的变量。所以page的data要加上weathertemperature变量,在wxml里面读取显示。
如下:

  ...
  <view>
    <input type="text" disabled="{{true}}" value="{{city}} " name="city"></input>
  </view>
  ...
  <view>
    <input type="text" disabled="{{true}}" value="{{weather}}" name="latitude"></input>
  </view>
  ...
  <view>
    <input type="text" disabled="{{true}}" value="{{temperature}}" name="name"></input>
  </view>
  ...
  • 移动端调试的问题

首先是心知api中请求地址包含的城市名在手机里好像有问题,要先把中文转码,用encodeURIComponent(that.data.city),然后拼接到请求地址中。否则会返回一个数据说地址有误。还有就是要在项目详情那里开启‘不校验合法域名、web-view……..’那个选项

第九章

医疗急救卡-form表单组件下面那块

  <view wx:else>
  ...
  </view>

正确的位置应该是在pages/index/index.wxml

上面部分描述只是个大概思路,详情可以到源码中查看: demo源码:voezy/zxkt