小程序开发实战学习笔记

标签: 小程序

序言 原本题目写的时候实战经验,但是觉着算不上什么经验,就改成学习笔记了��

注册小程序账号

开发和发布流程

小范围讨论公公抽离之类

不写公共样式因为不知道别人会不会用你的

目录结构

小程序包含一个描述整体程序的 app 和多个描述各自页面的 page。

具体参见官方文档


生命周期

onLoad(Object query)
页面加载时触发。一个页面只会调用一次,可以在 onLoad 的参数中获取打开当前页面路径中的参数。
onShow()
页面显示/切入前台时触发。
onReady()
页面初次渲染完成时触发。一个页面只会调用一次,代表页面已经准备妥当,可以和视图层进行交互。

注意:对界面内容进行设置的 API 如wx.setNavigationBarTitle,请在onReady之后进行。

onHide()
页面隐藏/切入后台时触发。 如 navigateTo 或底部 tab切换到其他页面,小程序切入后台等。(⚠️此处跟后面的定时器有关联)
onUnload()
页面卸载时触发。如redirectTo或navigateBack到其他页面时。(⚠️此处跟后面的定时器有关联)

⚠️注意:上传文件的时候,页面也会先后进入onHide,onShow生命周期

具体参见官方文档

配置文件

app.json和pages文件夹里的json文件的一个区别

app.json

{
  "pages": [
    "pages/index/index"
  ],
  "window": {
    "backgroundTextStyle": "light"
  },
  "networkTimeout": {
    "request": 10000
  }
}

pages文件夹里的json文件只有一层,因为页面的.json只能设置 window 相关的配置项,以决定本页面的窗口表现,所以无需写 window 这个键。

{
  "navigationBarTitleText": "订单详情"
}

project.config.json文件是项目配置(工具配置)文件

通常大家在使用一个工具的时候,都会针对各自喜好做一些个性化配置,例如界面颜色、编译配置等等,在小程序开发者工具上做的任何配置都会写入到这个文件,当你重新安装工具或者换电脑工作时,你只要载入同一个项目的代码包,开发者工具就自动会帮你恢复到当时你开发项目时的个性化配置,其中会包括编辑器的颜色、代码上传时自动压缩等等一系列选项。包括基础库版本,项目的appid项目名字等。

另外,如果修改编译模式,那么增减的编译模式会反映在project.config.json文件的condition-miniprogram-list数组里。可能测试在测的时候或者协同开发的时候别人有修改,影响了这个文件最好不要提交。

具体参见官方文档

快捷键

列举几个提升开发效率的常用快捷键**

  • ⌘ + N ctrl + N 新建文件
  • ⌘ + S ctrl + S 保存文件
  • ⇧ + ⌘ + S shift + ctrl + S 保存所有文件
  • ⌘ + Z ctrl + Z 撤销
  • ⇧ + ⌘ + Z shift + ctrl + Z 重做
  • ⇧ + ⌥ + F shift + alt + F 格式化代码
  • ⌘ + F ctrl + F 文件内搜索
  • ⇧ + ⌘ + F shift + ctrl + F 项目内搜索
  • ⌘ + B ctrl + B 编译项目

更多快捷键移步官方文档

wxss

与 CSS 相比,WXSS 扩展的特性有:尺寸单位 样式导入

尺寸单位

rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
⚠️开发微信小程序时设计师最好用 iPhone6 作为视觉稿的标准。这样好计算,乘以2就可以了。

样式导入

使用@import语句可以导入外联样式表,@import后跟需要导入的外联样式表的相对路径,用;表示语句结束。

目前支持的选择器

目前支持的选择器有:.class,#id,element,element, element,::after,::before。
eg.箭头之类的小图标可以用伪类写。

其他

没有嵌套
background-image设置背景图片:只支持线上图片和base64图片,不支持本地图片

wxml

列表渲染

多层渲染
使用 wx:for-item 可以指定数组当前元素的变量名,使用 wx:for-index 可以指定数组当前下标的变量名。

如不提供 wx:key,会报一个 warning, 如果明确知道该列表是静态,或者不必关注其顺序,可以选择忽略。

⚠️但是仍然建议使用 wx:key 来指定列表中项目的唯一的标识符。

代码中的 ” ” 和 ’ ‘

小程序中wxml中设置wxss变量等情况时,注意 ” ” 和 ’ ’ 之间的嵌套关系。

关于<block/>

小程序中的<block/>并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性。
因为 wx:if 是一个控制属性,需要将它添加到一个标签上。如果要一次性判断多个组件标签,可以使用一个<block/> 标签将多个组件包装起来,并在上边使用 wx:if 控制属性。
类似 block wx:if,也可以将 wx:for 用在标签上,以渲染一个包含多节点的结构块。

关于 wx:if 和 hidden

因为 wx:if 之中的模板也可能包含数据绑定,所以当 wx:if 的条件值切换时,框架有一个局部渲染的过程,因为它会确保条件块在切换时销毁或重新渲染。

同时 wx:if 也是惰性的,如果在初始渲染条件为 false,框架什么也不做,在条件第一次变成真的时候才开始局部渲染。

相比之下,hidden 就简单的多,组件始终会被渲染,只是简单的控制显示与隐藏。

一般来说,wx:if 有更高的切换消耗而 hidden 有更高的初始渲染消耗。因此,如果需要频繁切换的情景下,用 hidden 更好,如果在运行时条件不大可能改变则 wx:if 较好。

组件

icon

size 单位px

text

text中的内容不确定的时候,注意添加样式word-break: break-all;否则,内容全是数字时会溢出text。

image

binderror:当错误发生时,发布到 AppService 的事件名,事件对象event.detail = {errMsg: ‘something wrong’}

坑:当找不到图片时才会执行,如果后台没有返回这个字段,src中为空的时候不会执行。

textarea

开发调试过程中会发现textarea 浮在最上面。关于这个问题:

该组件是原生组件,使用时请注意相关限制。

关于原生组件

由于原生组件脱离在 WebView 渲染流程外,因此在使用时有以下限制:
原生组件的层级是最高的,所以页面中的其他组件无论设置 z-index 为多少,都无法盖在原生组件上。
后插入的原生组件可以覆盖之前的原生组件。
原生组件还无法在 scroll-view、swiper、picker-view、movable-view 中使用。
部分CSS样式无法应用于原生组件,例如:
无法对原生组件设置 CSS 动画
无法定义原生组件为 position: fixed
不能在父级节点使用 overflow: hidden 来裁剪原生组件的显示区域
原生组件的事件监听不能使用 bind:eventname 的写法,只支持 bindeventname。原生组件也不支持 catch 和 capture 的事件绑定方式

在iOS下,原生组件暂时不支持触摸相关事件。

坑:在开发过程中遇到的问题,如果一个输入框中的文字过多,显示不完全,在ios真机上是无法左右滑动文字查看的。在开发工具上可以,原因见下一条。

⚠️注意 真机与开发工具的表现

在工具上,原生组件是用web组件模拟的,因此很多情况并不能很好的还原真机的表现,建议开发者在使用到原生组件时尽量在真机上进行调试。

目前原生组件有:camera canvas input live-player live-pusher map textarea video

数据传递

小程序两个页面如何接传值

正向传值 上一页面->下一页面

  1. url传值
    • 通过url传递参数到下一个页面,下一个页面在onload生命周期中通过option.来获取参数值
  2. 本地储存(后面有单独一节)
  3. 全局的app对象
    • 在一个页面中getApp().mydata = 'lnp',在另一个页面中getApp().mydata即可
    • 在配置文件app.js中有一个叫做globalData的对象。在小程序的所有页面中都可以随时调用和写入存放在GlobalData的数据。无论是调用还是写入,第一步都是要让页面与App.js产生关联。所以在页面的对应的JS中,第一句话就要写上:var app = getApp();

反向传值 下一页面->上一页面

  1. 本地储存(后面有单独一节)
  2. 全局的app对象

跳转

为了不让用户在使用小程序时造成困扰,请尽量避免多层级的交互方式。
⚠️注意:目前页面路径最多只能十层。

导航api

wx.navigateTo(OBJECT)
保留当前页面,跳转到应用内的某个页面,使用wx.navigateBack可以返回到原页面。(非 tabBar 的页面的路径 ;路径后可以带参数)

wx.redirectTo(OBJECT)
关闭当前页面,跳转到应用内的某个页面。(非 tabBar 的页面的路径 ;路径后可以带参数)

wx.reLaunch(OBJECT)
关闭所有页面,打开到应用内的某个页面。(可以打开任意页面,包括tabBar 页面;路径后可以带参数;跳转的页面路径是 tabBar 页面则不能带参数。跳转到的页面不能返回,因此最好用在返回至首页的的时候)

wx.switchTab(OBJECT)
跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面(需要跳转的 tabBar 页面的路径必须是 app.json 的 tabBar 字段定义的页面,否则无效,路径后不能带参数)

wx.navigateBack(OBJECT)
关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages() 获取当前的页面栈,决定需要返回几层。

wx.navigateBack({
  delta: 2
})

⚠️注意:调用 navigateTo 跳转时,调用该方法的页面会被加入堆栈,而 redirectTo 方法则不会

详见文档

navigator组件

navigator组件的open-type属性值规定页面的跳转方式,navigate,redirect,switchTab,reLaunch,navigateBack与api相对应。
详见文档


坑:比如有的小程序底部的tabBar有一个‘我的’功能有未读消息红点的需求,所以无法使用小程序原本的tab。自定义的tabBar中 <navigator class="tab-item" url="/pages/home/index/index" open-type="redirect">需要添加open-type="redirect",否则页面会被加入堆栈,用户切换tab多次会导致页面无法跳转。但是添加该属性存在一个问题,在开发工具上会明显看到页面先跳转到index页面,再跳转到目标页面,在真机上表现为闪一下,该问题目前未解决。

跳转到h5

使用web-view组件,基础库 1.6.4 开始支持,低版本需做兼容处理。
⚠️注意:
* 个人类型与海外类型的小程序暂不支持使用。
* 每个页面只能有一个web-view组件,<web-view/>会自动铺满整个页面,并覆盖其他组件。

当需要跳转到的url过长时,无法通过url参数携带,可以通过本地存储保存。

api相关

wx.nextTick(FUNCTION)

基础库 2.2.3 开始支持,低版本需做兼容处理。

用于延迟一部分操作到下一个时间片再执行(类似于 setTimeout)。

因为自定义组件中的 setData 和 triggerEvent 等接口本身是同步的操作,当这几个接口被连续调用时,都是在一个同步流程中执行完的,因此若逻辑不当可能会导致出错。

Component({
  doSth() {
    this.setData({ number: 1 }) // 直接在当前同步流程中执行

    wx.nextTick(() => {
      this.setData({ number: 3 }) // 在当前同步流程结束后,下一个时间片执行
    })

    this.setData({ number: 2 }) // 直接在当前同步流程中执行
  }
})
//1 2 3

详见文档

本地存储

每个微信小程序都可以有自己的本地缓存,可以通过 wx.setStorage(wx.setStorageSync)、wx.getStorage(wx.getStorageSync)、wx.clearStorage(wx.clearStorageSync)可以对本地缓存进行设置、获取和清理。同一个微信用户,同一个小程序 storage 上限为 10MB。localStorage 以用户维度隔离,同一台设备上,A 用户无法读取到 B 用户的数据。

注意: 如果用户储存空间不足,我们会清空最近最久未使用的小程序的本地缓存。我们不建议将关键信息全部存在 localStorage,以防储存空间不足或用户换设备的情况。
详细请看接口文档,写的很详细。

//设置
wx.setStorage({
    key: 'mykey',
    data: 'lnp'
  })
//获取      
wx.getStorageSync('mykey'),

定时器

清除定时器需要注意在页面卸载和隐藏/进入后台时都要清除。

// redirectTo或navigateBack离开时触发
onUnload: function() {
    clearInterval(countDownTimer)
},
// navigateTo 离开时触发
onHide: function() {
    clearInterval(countDownTimer)
}

支付

付款的时候点击叉,都是支付失败,但是可以通过fail中返回的res.errMsg == 'requestPayment:fail cancel'与否来判断是否是用户主动取消支付。
原本说上线才能测试支付,但是后台配置了之后也可以测试。
详见文档

音频

移步文档
微信小程序获取音频时长

const innerAudioContext = wx.createInnerAudioContext()
innerAudioContext.src = 'http://kano.guahao-test.com/orT27672955?token=V1.0_Vi9tRHZQbE9mZXRzUVd5UDhaazBVQT09X1RJTUVfQUVTCOUSTOM&convert=1'
innerAudioContext.onCanplay(() => {
console.log("语音时长预获取:" + innerAudioContext.duration)
})//这一段必须有 不然没法获取时长 删掉console.log也不行
setTimeout(() => {
console.log("语音时长获取:" + innerAudioContext.duration)//2.795102
}, 1000)

备注:关于这个没有在真机上测试,也没有在项目中使用,因为可能涉及流量消耗的问题在真机上这个方法会被阻止掉,日后知道更多再更新此问题。

内存泄露

跳转页面传值多次来回点击就会报错,但不影响页面。官方回复为基础库的已知问题
eventemitter 的 warning,没影响,也不会实际泄露。
移步开发者社区

注意

设置data数据

setData 函数用于将数据从逻辑层发送到视图层,同时改变对应的 this.data 的值。注意:

(1)直接修改 this.data 无效,不会重新渲染page,还会造成数据不一致。

(2)单次设置的数据不能超过1024kB,请尽量避免一次设置过多的数据。

this赋值

方法中给this赋值,const _this = this, 应对变量提升等问题

表单提交

formId

前台获取 formId 送至后台,由后台实现模板消息的发送。(此处由于 formId 只能由用户触发表单提交操作产生,故前台需要将每次产生的formId发送至后台,由后台保存并在适当时候调用微信接口向用户发送模板消息)

注意:因为我们是在开发者工具中测试,所以得到的formId值为the formId is a mock one。在真机中我们可以得到一个具体的值,利用该值结合其他参数就可以发送模板消息啦,所以测试真实场景务必在真机中测试。

坑:开始的做法是先e.detail.formId获取formId,保存到form的隐藏input里,然后再提交,这样做会导致第一次点击提交的时候获取不到formId的值。后来用这种方法直接传值是可以的。

 data: Object.assign(e.detail.value,{
        formId: e.detail.formId//formId 用于发送模板消息
}),

避免表单重复提交

有时候接口请求慢,需要注意禁止重复提交的问题。

兼容

ios上new Date()时间格式处理

在ios上new Date(expiredTimeNormalIos)中的参数如果直接用后台返回的 “2017-11-11 11:11:11”时间格式,不支持,会直接返回null,需要转化成可以兼容的格式,如下

 let expiredTimeNormalIos = expiredTimeNormal.replace(/\-/g, '/')
 //时间格式兼容ios 2014-09-25T13:24:00

input在华为mate8上显示问题

与布局有关

toast

低版本,如果配置none,最后显示还是勾

iphone x

<!--app.js-->
globalData: {
    isIphoneX: false,//判断是否是iphone x以便兼容
}
onShow: function () {
    const _this = this
    //判断设备类型
    wx.getSystemInfo({
      success: function (res) {
        //console.log(res.model)
        if (res.model.search('iPhone X') != -1) {//判断方法不能写res.model==iPhone X,因为真机上返回的是一个包含iPhone X字段的详细设备类型
          _this.globalData.isIphoneX = true
        }
      }
    })
},
<!--app.wxss-->
/* 适配iphone x 吸底按钮 */
.fix-iphonex-button {
  bottom:68rpx!important;
}
.fix-iphonex-button::after {
    content: ' ';
    position: fixed;
    bottom: 0!important;
    height: 68rpx!important;//关于68rpx是根据iphone x和其他设备宽高对比得出来的,亲测有效
    width: 100%;
    background: #fff;
}
.fix-iphonex-pb{
  padding-bottom:68rpx!important;//修改了底部的bottom可能会影响其他布局,视情况添加其他样式
}

其他

更改appId 需要在项目上改,单在配置文件中改无效,同样别人更新的时候需要拉取代码,然后新建项目。

图片上传服务器的域名需要后台配置

报错:未绑定为第三方平台的开发小程序。是因为解除绑定,需要重新添加项目。

刚开始开发的时候发现在个别安卓机上不能预览(比如锤子手机��)

发布的时候域名要是https

上线前把开发调试时候的无用编译模式删掉,或者保留有效的入口和参数名以便模拟调试

接口域名切换成线上地址

线上图片如果有cdn缓存,前端设置图片的时候需要在图片路径后添加参数,否则更换了图片在移动设备上比较难清缓存

发现一个小bug,不知道是不是小程序自己的问题:图片路径后加参数和不加参数,在mode=”widthFix”模式下如<image style='width:40rpx;' mode="widthFix" src=""></image>时,高度计算的结果是不一样的。

待完善…

当网络条件差或卡顿的情况下,用户多次点击,出现多次跳转页面等情况,可以通过JS中的函数节流和函数防抖解决。

原文链接:加载失败,请重新获取