准备阶段
1.注册小程序开发者账号
要想开发微信小程序首先要到微信开放平台注册一个小程序开发者账号。
和公众号的地址一样,都是https://mp.weixin.qq.com/
需要注意的是,小程序和公众号的账号并不互通,就算你是要绑定在公众号的小程序,也需要单独另外找一个邮箱重新注册小程序账号,而不能直接用之前已经有的公众号账号直接登录。
注册的时候选清楚是个人企业还是团体,个人的账号限制比较多,无法使用支付或者一键获取手机号的功能。(好像这些功能企业用的话是按调用次数收费)
注册完成后就可以登录进入主页按照发布流程填写基本信息、类目等信息了。
2.备案
现在在国内服务的网站(服务器在国内)、APP、小程序等都需要工信部ICP备案了,不备案是无法上线公开使用的。当然如果你只是自己开发玩玩不上线可以不备案,在小程序里面添加测试号(最多15个)也可以让别人使用你的小程序(测试版)。
备案填信息的时候比较关键的是服务内容标识,这一点个人备案限制比较多,可以参考这个页面。个人备案不能备案有关服务经营性质的相关类目。
备注现在变成了必填,可以从上面的类目描述中复制一下,个人备案最后加上『不涉及服务性和经营性』。
提交备案之后腾讯那边会先审核,一般第二天就会给你打电话通知审核结果,哪里不合适电话都会说清楚,通过腾讯的审核之后就可以提交管局了。
管局审核大概一周内就能完成,期间收到短信验证码需要在24小时内登录工信部核验,这点很重要,错过了需要重新提交备案。
备案成功后就获得了备案号,小程序的备案号一般结尾是X,工信部也可以查询到备案信息。
3.微信认证
微信小程序最好还是要微信认证。有了微信认证才能被搜索到还有分享给别人,要是没有微信认证别人只能扫描小程序码进入小程序。
此外被搜索还能主动调起小程序的体验评价打分,不需要开发者在小程序中引入体验评价相关组件。
认证收费情况:个人认证30元每次,企业认证300元每次。
有效期一年,过期需要重新认证。
在小程序管理页面点击微信认证,提交基本信息后就可以认证了。
然后微信会把你的认证信息提交给第三方机构,第三方机构会给你打电话核实信息,核实确认无误后就认证成功了,还是比较方便的。
可以在小程序发布正式版之后再认证,这样连名称也一起认证上了。
4.代码上传 版本管理
第一次上传代码后可以在小程序管理页面的版本管理的开发版本中看到上传的版本信息,可以将开发版本选为体验版本测试使用。
测试无误后就可以提交审核,这时会进入审核版本,审核的时间是工作时间,因为小程序都是人工审核,审核员要亲自动手测试你的小程序的所有功能,然后会审核通过。一般在工作时间段内半小时到一小时就能审核完成通过(我最快的一次居然十分钟就审核过了)。
服务类目一定要与小程序的实际功能一致,比如小程序涉及提供图片/音频/制作、剪辑服务,就要选择:工具-图片处理类目。
5.广告接入
小程序达到500个累计独立访客且没有违规记录后就可以开通流量主接入广告了,广告组件有很多要求,可以开通流量主之后查看,比如圆角不能太大导致广告图标被遮挡等。
第一次使用广告组件给小程序添加广告需要审核广告组件,在提交小程序版本审核的同时会提交广告审核。
两个审核是分开的,小程序审核通过不代表广告组件审核通过。
广告组件审核状态可以在流量主页面-广告管理中查看。
开发阶段
小程序感觉大致还是网页开发那一套,wxml类比html,wxss类比css,view标签类比div标签,熟悉网页开发的应该很容易上手。以下是我学习过程中的一些记录。
注意:写完界面功能什么的一定要到手机上实际测试!!模拟器很多东西都不准的!!!
模拟设备
微信开发者工具安装好后创建的第一个小程序的模拟设备默认是iPhone5,这屏幕太小了,而且机器早就过时了,照着这小屏开发现在的大屏手机适配成一坨,打开之后先把模拟设备调成iPhone 14 Pro Max再说。
创建页面
小程序创建页面的两种方法:
方法①在app.json的pages里面直接写页面的路径,比如"pages/index/index",保存后会自动创建目录结构和对应页面。
可以配置"entryPagePath"字段来指定小程序的默认入口页面,不写默认pages第一个为小程序首页。
方法②在pages文件夹里面先新建一个文件夹,比如about,然后在about文件夹里面选择新建page,输入about,即可创建对应的wxml wxss js json文件
两种渲染模式
新版不太稳定的skyline渲染模式和老的成熟的webview渲染模式,一般用webview即可。
在app.json里面删除renderer rendererOptions 和compoentFramework即可切换到webview渲染模式。
基本页面/基本组件/外观效果
修改小程序标题栏颜色、标题文字、下拉刷新效果等
在全局配置项app.json里配置,window属性,详见官方文档:小程序配置 / 全局配置 (qq.com)
修改小程序顶部、底部tab栏的图标、文字、选项、颜色等
在全局配置项app.json里配置,tabBar属性,详见官方文档:小程序配置 / 全局配置 (qq.com)
tab按数组顺序展示,list最少2个最多5个。
sitemap:允许微信索引小程序页面便于搜索,和robots.txt类似。
使用sass(css拓展)
在project.config.json里的settings里添加
"useCompilerPlugins": [
"sass"
],
然后把.wxss改成.scss就能用了
尺寸单位rpx:微信为了适配不同屏幕尺寸的手机做的统一,无论什么型号手机屏幕宽度均为750rpx
开发微信小程序时设计师要以iPhone6为标准,因为iPhone6的设计稿宽度就是750px,这样写代码时是多少px就写多少rpx。(iPhone6手机设备宽度为375px)
轮播图
有关组件的相关内容官方文档非常详细,随取随用。
比如轮播图要用到的:视图容器 / swiper (qq.com)
小程序中提供swiper和swiper-item非常方便的制作轮播图。
swiper滑块视图容器,里面放swiper-item组件。
自动播放:autoplay=true
间隔时长(毫秒)interval=2000
image组件 媒体组件 / image (qq.com)
src图片地址,mode图片缩放裁切格式,show-menu-by-longpress长按可以发送朋友收藏识别二维码等
text文本组件
user-select是否支持长按选择(微信小程序中只有这个可以长按选择)
space显示连续空格
navigation组件 导航 / navigator (qq.com)
跳转页面,支持不同方式,可以保留上一个页面,可以关闭其他所有非tabBar页面,可以只跳转到非tabBar页面或者tabBar页面,也可以关闭所有页面打开一个tabBar页面
navigateBack返回前某个页面,默认为上一层,可以加detla属性表示层级
scroll-view组件 可滚动视图区域
事件系统
小程序不能用on的方式绑定事件,也没有click,只有bind或者tab事件
<view bind:tap="fnName">
事件处理函数需要写在.js文件的Pages方法里
<input type="text" name="" id="" bind:input="getInputValue"/>
微信小程序中事件分为冒泡事件和非冒泡事件。
冒泡事件的组件被触发时也会向父组件的事件传递信息。
把bind换成catch可以阻止事件冒泡
data方式获取数据
<button type="primary" bind:tap="handler" data-avid="10086" data-bv-id="BV1bx411c7u3">解析视频</button>
// index.js Page({ handler (event) { console.log('事件触发了') console.log(event) // currentTarget 事件绑定者 // target 事件触发者,二者可以不一致(事件冒泡时currentTarget就是target的父组件 // 单个单词直接data-后面的名字获取 console.log(event.currentTarget.dataset.avid) //多个单词在wxml里面用-分隔,在这里用小头驼峰data-bv-id bvId console.log(event.currentTarget.dataset.bvId) }, getInputValue (event) { // 输入字符时控制台输出文本 console.log(event.detail.value) }, data: { } })
mark方式获取数据
<button type="primary" bind:tap="handler" data-avid="10086" data-bv-id="BV1bx411c7u3" mark:cid="11111282">解析视频</button> //mark数据获取方式,mark获取到的是触发事件的节点以及父节点上所有的mark数据 console.log(event.mark.cid)
声明和绑定数据
小程序中所使用的数据均需要在Page()方法的data对象中声明定义
在wxml中使用双大括号Mustache语法将变量包裹进去使用,
其中可以做算术运算、三元运算、逻辑判断等简单运算,只能写表达式不能写语句或者js的方法。
三元运算:{{ id ===1 ? '等于' : '不等于' }}
修改更新数据
小程序中直接赋值的方法修改数据无法修改页面上的数据,可以用this.setData()方法修改。
这样可以在修改数据的同时让页面驱动视图也更新。
swiperTab () { // 直接赋值写法,虽然控制台里输出了1 2 3 4但是页面上还是0 this.data.tabCount += 1; console.log(this.data.tabCount) // setData写法,不仅数据变了,页面上也会更新 this.setData({ tabCount: this.data.tabCount + 1 }) console.log(this.data.tabCount) },
修改对象
如果是修改对象,添加或修改新的属性可以写成数据路径的形式
this.setData({
'userInfo.name': 'tom',
'userInfo.age': 11,
})
多个属性写多个数据路径
数据量大的优化简写方法
// 优化写法 // 方法一 ES6 提供的展开运算符 const userInfo = { // 通过展开运算符可以将一个对象的数据复制给另一个对象 ...this.data.userInfo, // 后面的属性会覆盖前面的属性 name: 'jerry', age: 18 } this.setData({ userInfo // 键值一样,可以省略成一个 }) // 方法二Object.assign() 将多个对象合并为一个对象 const userInfo = Object.assign(this.data.userInfo, {name: 'jerry'}, {age: 18}) this.setData({ userInfo // 键值一样,可以省略成一个 })
删除单个属性,先用delete方法删除,然后再把对象setData一下。
删除多个属性:
// 使用 ES6 提供的 rest 剩余参数删除
const { age, test, ...rest} = this.data.userInfo
this.setData({
userInfo: rest
})
修改数组
this.data.list.push(2333) // 只在数据里新增,不更新到页面
可以先新增数据然后再setData驱动视图更新
this.data.list.concat(2333) 再驱动视图更新
或者ES6的展开运算符
const newList= [ ...this.data.list, 4 ] 再驱动视图更新
修改也可以使用数据路径'list[0]' = 1 'list[0].name' = 'tom'
删除this.data.list.splice(start, count, item1, item2 ...)
start数组下标位置 count删几个 后面item可选参数再插入进去
删完setData驱动视图更新
或者筛选数据filter
this.data.list.filter(item => item !== 2) 然后驱动视图更新
简易双向绑定数据
默认单向绑定数据会影响页面,但是在页面修改不会影响数据。
在对应属性前添加model
<input model:value="{{ value }}" />
只支持单一字段,不能拼接,不支持数组和对象(不能写a.b)
列表渲染
wx:for绑定数组或对象,每一项变量名默认为item,下标名为index
在使用wx:for时建议添加wx:key 绑定index(要求wx:key绑定的对象唯一,比如*this表示item本身)
<swiper-item wx:for="{{img_url_array}}" wx:key="index">
<image src="{{item}}" mode="widthFix" show-menu-by-longpress lazy-load/>
</swiper-item>
wx:for-item 和wx:for-index这两个属性可以指定元素和下标的变量名,要和wx:for写在同一个标签上
wx:for用在<block />标签上可以渲染结构块,仅为包装元素,不会在页面上展示
可以支持列表渲染、条件渲染
条件渲染
使用wx:if wx:elif wx:else属性组(通过新增/移除节点实现)
使用hidden属性(通过display实现)
wx:elif和wx:else不能单独使用,必须结合wx:if
使用这三个属性组的组件必须连续,中间不能被没有使用这三个属性组的其他组件打断。
<view>点击次数:{{tabCount}}</view>
<view wx:if="{{ tabCount < 17 }}">接着看</view>
<view wx:elif="{{ tabCount === 17 }}">当前点了17次,已经全部看完了哦</view>
<view wx:else>还要多看几遍吗</view>
小程序生命周期 更新机制
切后台5秒后挂起,30分钟后销毁。
点击小程序右上角的关闭、回到手机桌面或者锁屏都会使小程序进入后台状态。
当开发者使用了后台播放音乐、后台地理位置等能力时小程序可以持续在后台运行,不会被挂起。
小程序冷重启时都会调用onLaunch()钩子函数。
利用这个写一个启动时检查小程序更新:
// 检查更新 // 使用 wx.getUpdateManager() 方法监听下载状态 const updateManager = wx.getUpdateManager() // 下载完新版本后触发onUpdateReady回调函数 updateManager.onUpdateReady(function() { // 给用户更新提示 wx.showModal({ title: '更新提示', content: '新版本已经准备好,是否重启应用', complete: (res) => { if (res.cancel) { } // 点击确定强制重启更新 if (res.confirm) { updateManager.applyUpdate() } } })可以在微信开发者工具中的编译选项里面勾选下次编译时模拟更新来模拟更新。
只有异步更新机制才会有这种强制更新,现在微信大部分是同步更新机制,微信运行时会定期检查最近使用的小程序是否有更新,长时间没使用强制同步检查更新,异步机制是在使用(旧版本小程序)过程中异步的检查更新,下次冷启动时应用更新。
应用生命周期
onLaunch 冷启动时触发,一个应用生命周期只触发一次
onShow 启动时或者切前台时触发
onHide 切后台时触发
页面生命周期
onLoad 页面加载(刚打开页面)
onShow 页面展示(可以看到页面,切前台也会触发)
onReady 初次渲染完成页面(视图层第一次渲染完毕可以交互了)
onUnload redirect方式跳转或者关闭小程序时触发(页面销毁时)
onHide navigate方式跳转或者切后台时触发(页面被隐藏时)
切换tabBar不会销毁其他tabBar页面,点击左上角返回上一个页面会销毁当前页面
小程序API
异步API:接收一个object类型参数,wx.requests({})
支持callback 和 Promise两种调用方式
同步API:约定以Sync结尾,wx.setStorageSync()
事件监听API:约定以on开头,wx.onAppHide
发起网络请求
需要用到wx.request()接口API,请求的域名需要在微信公众平台配置好。
// 获取数据 getData(avid) { wx.request({ // 请求地址 url: 'https://api.bilibili.com/x/web-interface/view?aid=' + avid, // 请求方法 method: 'GET', // 请求数据 data: {}, // 请求头 header: {}, // 成功回调函数 success: (res) => { console.log(res) }, // 失败回调函数 fail: (err) => { console.log(err) }, // 无论成功失败只要请求就执行 complete: (res) => { console.log(res) } }
加载中
wx.showLoading({
title: '正在查询清晰度...',
// mask透明遮罩,启用后加载过程中不允许用户触摸
mask: true,
})
wx.hideLoading()
必须调用hideLoading方法才会关闭加载中的提示。
模态对话框
wx.showModal({ title: '前往B站', content: '是否前往b站', complete: (res) => { if (res.cancel) { } if (res.confirm) { } }) wx.showToast({ title: '长按上方图片即可保存', // 文本过长会显示不出来 icon: "none", // success error loading none duration: 2000 // 持续时间两秒 })
好好好
上拉加载
app.json或者page.json里配置距离页面底部距离,默认50px
onReachBottomDistance;
在页面.js中定义onReachBottom事件监听用户上拉加载
(小程序创建页面时会给你写好一个空方法,注意不要多写一遍会没有反应)
上拉加载实现案例:
/** * 页面上拉触底事件的处理函数 */ onReachBottom() { console.log('上拉加载') if(this.data.has_next){ wx.showToast({ title: '正在加载...', icon: 'loading' }) var lastAvid = this.data.videoList[this.data.videoList.length - 1].param var reqUrl = "https://请求地址/get_space_video_list?mid=" + this.data.userUid + "&lastavid=" + lastAvid wx.request({ url: reqUrl, success: (res) => { console.log(res) for (let eachVideo of res.data.data.item) { eachVideo.duration = this.convertSeconds(eachVideo.duration) } // 此案例页面wx:for数据为videoList,这一个语句用于合并列表,这样就能展示新加载的数据了,同时老数据也在上面保留 this.data.videoList = [...this.data.videoList, ...res.data.data.item] this.data.has_next = res.data.data.has_next this.setData({ videoList: this.data.videoList }) }, fail: (err) => { console.log(err) wx.showToast({ title: '加载失败', icon: "error" }) } }) }else{ wx.showToast({ title: '没有更多了', icon: "error" }) } },
开放能力
获取微信头像昵称
头像:按钮设置open-type为chooseAvarar,然后绑定bind:chooseavatar事件获取头像的临时路径。
昵称:input框设置type为nickname,这样用户输入的时候就会提示使用微信昵称。
可以放在form表单里搭配按钮提交数据。
【WXML】 <!-- 测试获取微信头像昵称 --> <view> <button class="btn" open-type="chooseAvatar" bind:chooseavatar="chooseAvatar"> <image class="avatar" src="{{ avatarUrl }}" mode=""/> </button> <form bindsubmit="onSubmit"> <input type="nickname" name="nickname" id="" placeholder="请输入昵称"/> <button type="primary" plain form-type="submit">点击获取昵称</button> </form> </view> 【WXSS】 .btn { background-color: transparent; } /* 尾类 尾元素 */ .btn::after{ border: none; } input { border: 1px solid #17916c; margin: 20rpx; height: 60rpx; border-radius: 20rpx; padding-left: 20rpx; } 【JS】 // 获取微信头像 chooseAvatar(event) { console.log(event) // 解构数据(获取到的头像路径是临时路径,需要上传到服务器保存) const { avatarUrl } = event.detail this.setData({ avatarUrl }) }, // 获取用户昵称 onSubmit(event) { console.log(event) const { nickname } = event.detail.value },
转发
分享给朋友
页面js中声明了onShareAppMessage才会有右上角的三个点转发选项(不然是灰的)
也可以设置一个按钮open-type="share"触发
/** * 用户点击右上角分享 */ onShareAppMessage() { // 自定义分享内容 return { title: '快来使用唧唧!', path: '/pages/about/about', imageUrl: '../../img/logo_blue.png' } }
分享给朋友圈
要在上面分享给朋友的基础上再加一个onShareTimeline事件监听函数。
/** * 用户点击右上角分享到朋友圈 */ onShareTimeline() { return { title: '快来使用唧唧!', query: 'from=timeline', imageUrl: '../../img/logo.png' } }
手机号快速验证和实时验证
个人账号认证无法使用,必须是组织团体企业类型的认证。
而且需要付费才能使用(免费额度1000条)
wxml中按钮绑定open-type
<!-- 测试手机号验证组件 --> <view> <!-- 快速验证组件 --> <button open-type="getPhoneNumber" bindgetphonenumber="getphonenumber">快速验证手机号</button> <!-- 实时验证组件 --> <button open-type="getRealtimePhoneNumber" bindgetrealtimephonenumber="getrealtimephonenumber">实时验证手机号</button> </view>
js里面写对应的处理事件
getphonenumber(event) { console.log(event) }, getrealtimephonenumber(event) { console.log(event) },
调试需要在真机调试,模拟器调试不了这个。
通过event.detail可以获取到code动态令牌,可以通过code获取用户手机号。
前端把code发给后端,后端调用微信api获取手机号再发给前端。(也可以不发给前端,在后端做数据处理。)
客服能力
button open-type设置为contact就可以打开客服界面
记得提前在微信公众后台提前设置好客服账号。
getApp()
写在Page外面
const appInstance = getApp()
获取全局唯一的App实例。
比如可以把登录的token放在里面,或者全局共享的变量。
在app方法中可以直接用this获取,不能在app中使用getApp
不要私自调用生命周期函数
记录bug
// 记录比较离谱的bug // 播放音频这里,b站返回的有的链接可能是403 // 403的音频在开发者工具的模拟器会直接触发onError,很正常 // 但是在手机上会在30秒超时之后才会触发onError,不正常 // 而且这个超时时间不能自己设置,尝试像wxwx.request一样设置了timeout但是没用 // 于是尝试采用缓冲处理,手机端点击播放后如果有以上问题会触发onWaiting // 在缓冲触发事件时尝试读取已缓冲的秒数innerAudioContext.buffered // 但是这个东西也可能有bug,有可能音频正在播放但是这个已缓冲秒数还是0 // 于是判断换源时加了一个检测是否在播放的判断innerAudioContext.paused // 只有在死链(403)无法播放时innerAudioContext.paused才是True // 这样正常播放时就不会有换源导致的断开重新播放的问题
本文地址:https://blog.jixiaob.cn/?post=112
版权声明:若无注明,本文皆为“赵苦瓜のBlog~”原创,转载请保留文章出处。