微信小程序开发流程

3,601 阅读1分钟

一.小程序开发账号申请(AppID)

  1. 登陆微信公众平台 mp.weixin.qq.com
  2. 点击立即注册:填写账号信息->激活账号(邮箱激活)->信息登记(选择主体类型)
  3. 安装开发者工具:mp.weixin.qq.com/debug/wxado…

二.小程序开发起步:

  1. 阅读小程序开发指南: developers.weixin.qq.com/miniprogram…
  2. 小程序框架模版部署: ( mpVue框架文档【官方已经停止维护】:mpvue.com )
// 全局安装 vue-cli
$ npm install --global vue-cli

// 创建一个基于 mpvue-quickstart 模板的新项目
$ vue init mpvue/mpvue-quickstart my-project  
 
// 安装依赖 
$ cd my-project
$ npm install

// 启动构建
$ npm run dev
  1. 启动微信开发者工具,引入项目目录dist中的wx文件夹即可预览到简单的 mpvue 小程序。

三.小程序的版本区分:

  1. 开发版本:使用开发者工具,运行代码后点击上传可以将代码上传到开发者版本中。
  2. 体验版本:
    • 可以选择某个开发版本作为体验版本,一个AppID同一时刻有且只有一个体验版二维码。
    • 体验者微信号需使用小程序开发账号登陆微信公众平台中,添加到体验成员。
  3. 审核中版本:
    • 只有在完成小程序基本资料填写后,方可选择一个开发版本提交审核。
    • 只能有一份代码处于审核中,有审核结果以后可以发布到线上。
    • 请开发者严格测试了版本之后,再提交审核, 过多的审核不通过,可能会影响后续的时间。
  4. 线上版本:线上所有用户使用的代码版本,该版本代码在新版本代码发布后被覆盖更新。

四. 小程序发布上线准备工作(审核版本-上线版本)

  1. 检查微信开发账号:
    • 确保需要上线的AppID正确(在project.config.json文件中修改)
    • 确保上线的AppID通过微信认证完成了主体真实性确认
  2. 检查项目环境配置:确保项目环境切换为'production'  (在src/biz/apiConfig.js文件中修改)
  3. 检查生产环境域名配置:(开发-集成-验收  同下一致)
    • 确保在小程序公众平台上配置服务器选项中成功添加生产环境的服务器域名和业务域名
    • 业务域名需经过ICP备案,新备案域名需24小时后才可配置。域名格式只支持英文大小写字母、数字及“- ”,不支持IP地址。配置业务域名后,可打开任意合法的子域名。
    • 下载校验文件并将文件放置在域名根目录下,例如wx.qq.com,并确保可以访问该文件。
  4. 填写小程序信息:微信公众平台上未填写小程序信息内容是无法发布审核版本:
    • 小程序名称:(长度为4-30个字符,一个中文字等于2个字符)
    • 小程序简称 :(选填:长度为4-10个字符,一个中文字等于2个字符)
    • 涉及特定行业领域小程序名称需提供:(各项图片大小小于5M)《营业执照》或《组织代码证》,请务必加盖公司公章《商标注册证》等相关行业法定许可或备案证明文件、相关职业或执业证件
    • 小程序头像:(格式:png,bmp,jpeg,jpg,gif;不可大于2M,建议图片尺寸为144px*144px)
    • 小程序介绍: 介绍字数为4~120个字
    • 小程序的服务类目:选择对应的服务类目。例如:金融业下的信托服务。需提供:《金融许可证》或 《金融机构许可证》(上传原件或复印件,复印件务必加盖公司公章)

五. 小程序开发的核心概念

  1. 小程序的生命周期过程总结

    • 应用的生命周期:
      • onLaunch : 当小程序初始化完成时,会触发(全局只触发一次)
      • onShow : 当小程序启动,或从后台进入前台显示时触发
      • onHide : 当小程序从前台进入后台时触发(右上角的关闭、按手机设备的Home键)
      • onError : 当小程序发生脚本错误,或者 API 调用失败时触发
    • 页面的生命周期:
      • onLoad : 监听页面加载,触发时机早于onShow和onReady(在页面没被销毁之前只会触发1次)
      • onShow : 监听页面显示,触发事件早于onReady
      • onReady : 监听页面初次渲染完成(触发时表示页面可交互,在页面没被销毁之前只会触发1次)
      • onHide : 监听页面隐藏(wx.navigateTo切换到其他页面、底部tab切换时触发)
      • onUnload : 监听页面卸载(wx.redirectTo或wx.navigateBack返回到其他页时触发)
  2. 页面跳转和路由

微信小程序采用页面栈的形式来管理页面,小程序宿主环境限制了这个页面栈的最大层级为10层。现在页面栈数据为 [pageA,pageB,pageC],pageC在最顶上,也就是用户看到的界面。 * wx.navigateTo({url:'pageD'}) 推出一个pageD,此时页面栈[pageA, pageB, pageC, pageD] * wx.navigateBack() 退出当前页面栈的最顶上页面,此时页面栈变成 [ pageA, pageB, pageC ] * wx.redirectTo({ url:'pageE'}) 替换当前页变成pageE,此时页面栈变成 [ pageA, pageB, pageE ] * wx.switchTab({ url:'pageF'}) 切换到tab页面pageF,此时原来页面栈被清空 [ pageF ] * wx.reLaunch({ url:'pageH'}) 重启小程序并打开pageH,此时页面栈为 [ pageH ]。

  1. 页面路由触发方式及页面生命周期函数的对应关系:
路由方式触发时机路由前页面生命周期路由后页面生命周期
初始化小程序打开的第一个页面onLoad, onShow
打开新页面 调用API wx.navigateToonHideonLoad, onShow
页面重定向 调用API wx.redirectToonUnloadonLoad, onShow
页面返回 调用API wx.navigateBackonUnloadonShow
Tab切换 调用 API wx.switchTab具体情况具体分析具体情况具体分析
重启动调用 API wx.reLaunchonUnloadonLoad, onShow

六. 小程序开发的踩坑收录

  1. iOS 屏幕宽度适配问题 块级元素的标签,用100%来代替需要完全宽度750rpx的页面效果(使用 absolute 和 fixed 的标签除外),如果同时设置了标签的 padding 或 border,需更改 box-sizing 属性值为border-box;

  2. iOS 中Date 不支持构造 YYYY-MM-dd 的数据格式 可替换成 YYYY/MM/dd

  3. 小程序页面未触发onUnload之前页面状态不会销毁 由于页面的生命周期onLoad在被销毁之前只会触发1次,因此页面中data()返回的数据在 onShow()、onHide()生命周期触发时,不会主动去做数据初始化。需要手动重制数据状态,或者在离开页面时使用wx.redirectTo来跳转页面达到触发onUnload()行为。

  4. 小程序 textarea、input 层级过高,导致填写内容穿透 原生组件的层级是最高的,所以页面中的其他组件无论设置 z-index 为多少,都无法覆盖在原生组件上。解决的办法就是当textarea输入完成时,将textarea隐藏,将输入内容显示在一个text文本框。当点击text输入框时,又将text隐藏,显示textarea,并将textarea的焦点选中继续输入内容。

  5. 小程序原声组件button无法去除默认的border样式 使用 button::after{ border:none } 就可以去除默认border。

  6. 小程序中不支持 ::placeholder 选择器 在input标签中加入 placeholder-class="place-holder" 然后定义这个类的.place-holder{ color:red; }

  7. 如何获取小程序在页面传递的参数 在所有页面的组件内可以通过 this.root.root.mp.query 进行获取。

  8. 小程序 web-view 组件无法实现在Android上直接预览pdf文件 由于Android 和 ios 在web-view组件上的差异,解决方式是:使用wx.getSystemInfo()获取设备信息,ios系统直接使用web-view进行预览pdf文件;Android系统通过wx.downloadFile()下载文件、wx.openDocument()打开文件的操作模拟文件预览的效果。(以下代码已经对部分小程序API 进行promise化)

//首先在 utils.js 进行小程序API promise化
function wxPromisify(functionName, params) {
  return new Promise((resolve, reject) => {
    wx[functionName]({
      ...params,
      success: res => resolve(res),
      fail: res => reject(res)
    });
  });
}
function getSystemInfo(params={}){  //获取系统信息
  return wxPromisify('getSystemInfo',params);
}
function downloadFile(params={}){   //下载文件
  return wxPromisify('downloadFile',params);
}
function openDocument(params={}){   //打开文件
  return wxPromisify('openDocument',params);
}

//小程序预览文件全兼容方法

showDocHandle(){
  let docId = this.uuid;
  let resultUrl = `${apiConfig.request.getPubFile}/${this.xxxPubUrl}`
  wx.showLoading({title: '正在识别设备!'})
  utils.getSystemInfo()
    .then(res => {
      if(res.system.indexOf('iOS') != -1){
        wx.hideLoading();
        this.show = true;
        this.resultUrl = resultUrl;
      }else{
        this.show = false;
        wx.showLoading({title: '正在缓存文件!'});
        return utils.downloadFile({url: resultUrl});
      }
    })
    .then(res => {
      let tempFilePath = res.tempFilePath;
      wx.hideLoading();
      wx.showLoading({title: '正在打开文件!'})
      return utils.openDocument({filePath: tempFilePath})
    })
    .catch(err => {
      wx.hideLoading();
      utils.showToast("缓存文件失败!")
    })
    .then(res => {
      wx.hideLoading()
      utils.showToast("文件打开成功!")
    })
    .catch(err => {
      wx.hideLoading();
      utils.showToast("打开文件失败!")
      wx.navigateBack({delta:1})
    })
}