十点云音乐
基础知识
什么是小程序
- 2017 年度百度百科十大热词之一
- 微信小程序,简称小程序,英文名 Mini Program,是一种不需要下载安装即可使用的应用(张小龙对其的定义是无需安装,用完即走,实际上是需要安装的,只不过小程序的体积特别小,下载速度很快,用户感觉不到下载的过程)
- 小程序刚发布的时候要求压缩包的体积不能大于1M,,否则无法通过,在2017年4月做了改进,由原来的1M提升到 2M
- 2017年1月9日0点,万众瞩目的微信第一批小程序正式低调上线。
小程序的优点
- 同 App 进行互补,提供同 app 类型的功能,比 app 使用方便简洁
- 通过扫一扫或者在微信搜索即可下载
- 用户使用频率不高,但又不得不用的功能软件,目前看来小程序是首选
- 连接线上线下
- 开发门槛低, 成本低
小程序开发
相关资料
- 官网:https://mp.weixin.qq.com/
- 微信开发工具
- 下载地址:https://mp.weixin.qq.com/debug/wxadoc/dev/devtools/download.html?t=2018315
注册小程序账号
开发小程序储备知识
Flex布局
简介
- Flex 是 Flexible Box 的缩写,意为“弹性布局”,用来为盒状模型提供最大的灵活性
- 任何一个容器都可以指定为 Flex 布局
- display: ‘flex’
flex属性
- flex-direction:
- row(默认值):主轴为水平方向,起点在左端
- row-reverse:主轴为水平方向,起点在右端
- column:主轴为垂直方向,起点在上沿
- column-reverse:主轴为垂直方向,起点在下沿
学习地址
http://www.runoob.com/w3cnote/flex-grammar.html
移动端相关知识
物理像素
- 屏幕的分辨率
- 设备能控制显示的最小单元,可以把物理像素看成是对应的像素点
设备独立像素 & css像素
设备独立像素(也叫密度无关像素),可以认为是计算机坐标系统中的一个点,这个点代表一个可以由程序使用并控制的虚拟像素(比如:CSS 像素,只是在 android 机中 CSS 像素就不叫“CSS像素”了,而是叫“设备独立像素”),然后由相关系统转换为物理像素。
dpr比 & DPI & PPI
- dpr:设备像素比,物理像素/设备独立像素 = dpr, 一般以 iphon6 的 dpr 为准 dpr = 2
- PPI:一英寸显示屏上的像素点个数
- DPI:最早指的是打印机在单位面积上打印的墨点数,墨点越多越清晰
移动端适配方案
viewport适配
为什么做 viewport 适配
a) 手机厂商在生产手机的时候大部分手机默认页面宽度为 980px
b) 手机实际视口宽度都要小于 980px,如: iphone6 为 375px
c) 开发需求: 需要将 980 的页面完全显示在手机屏幕上且没有滚动条
实现:
1 | <meta name="viewport" content="width=device-width,initial-scale=1.0"> |
rem适配
为什么做 rem 适配
a) 机型太多,不同的机型屏幕大小不一样
b) 需求: 一套设计稿的内容在不同的机型上呈现的效果一致,根据屏幕大小不同的变化,页面中的内容也相应变化
实现:
1 | function remRefresh() { |
- 第三方库实现:lib-flexible + px2rem-loader
小程序特点
概述
没有 DOM
组件化开发:具备特定功能效果的代码集合
体积小,单个压缩包体积不能大于 2M,否则无法上线
小程序的四个重要的文件
a) *.js
b) *.wxml —> view 结构 —-> html
c) *.wxss —> view 样式 —–> css
d) *. json —-> view 数据 —–> json 文件
小程序适配方案:rpx(responsive pixel 响应式像素单位)
a) 小程序适配单位: rpx
b) 规定任何屏幕下宽度为 750rpx
c) 小程序会根据屏幕的宽度不同自动计算 rpx 值的大小
d) Iphone6 下:1rpx = 1 物理像素 = 0.5px
小程序配置
全局配置: app.json
作用:用于为整个应用进行选项设置
链接:https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html
页面配置:页面名称.json
作用:用于为指定的页面进行配置
链接:https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html
注意!页面配置的优先级高于全局配置
sitemap配置: sitemap.json
作用:用于被微信搜索爬取页面
链接:https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html
小程序框架接口
App
- 全局 app.js 中执行
App()
- 生成当前应用的实例对象
getApp()
获取全局应用实例
Page
- 页面.js 中执行
Page()
- 生成当前页面的实例
- 通过
getCurrentPages
获取页面实例
wxml语法
数据绑定
初始化数据
页面.js 的 data 选项中
1 | Page({ |
使用数据
- 模板结构中使用双大括号
{{msg}}
- 注意事项: 小程序中为单项数据流 model —> view
1 | <text class="userName"> {{msg}} </text> |
修改数据
this.setData({message: ‘修改之后的数据’}, callback)
特点:
a) 同步修改: this.data 值被同步修改
b) 异步更新: 异步将 setData 函数用于将数据从逻辑层发送到视图层(异步)
1 | onLoad() { |
总结
小程序
- data中初始化数据
- 修改数据:
this.setData()
- 修改数据的行为始终是同步的
- 数据流:
- 单向: Model —> View
Vue
data中初始化数据
修改数据:
this.key = value
数据流:
Vue是单向数据流: Model —> View
Vue中实现了双向数据绑定: v-model
React
state中初始化状态数据
修改数据:
this.setState()
自身钩子函数中(componentDidMount)异步的
非自身的钩子函数中(定时器的回调)同步的
数据流:
- 单向: Model —> View
事件绑定
事件分类
冒泡事件
- 定义:当一个组件上的事件被触发后,该事件会向父节点传递。
- 冒泡事件列表: https://mp.weixin.qq.com/debug/wxadoc/dev/framework/view/wxml/event.html
非冒泡事件
- 定义:当一个组件上的事件被触发后,该事件不会向父节点传递。
- 非冒泡事件:表单事件和自定义事件通常是非冒泡事件 https://mp.weixin.qq.com/debug/wxadoc/dev/framework/view/wxml/event.html
绑定事件
- bind绑定:事件绑定不会阻止冒泡事件向上冒泡(绑定冒泡事件)
- catch绑定:事件绑定可以阻止冒泡事件向上冒泡(绑定非冒泡事件)
1 | <view class="goStudy" bindtap="handleParent"> |
事件流的三个阶段
- 捕获: 从外向内
- 执行目标阶段
- 冒泡: 从内向外
向事件对象传参
- 语法:
data-key = value
- 获取:
event.target.dataset.key || event.currentTarget.dataset.key
event.target
和event.currentTarget
的区别event.target
是触发事件的对象,但不一样是绑定事件的对象,如: 事件委托,冒泡currentTarget
触发时间的对象一定是绑定事件的对象, 没有事件委托
生命周期
对应阶段说明
- onLoad(Object query)
- 页面加载时触发。一个页面只会调用一次,可以在 onLoad 的参数中获取打开当前页面路径中的参数。
- 参数:
名称 | 类型 | 说明 |
---|---|---|
query | Object | 打开当前页面路径中的参数 |
- onShow()
- 页面显示/切入前台时触发
- 会执行多次
- onReady()
- 页面初次渲染完成时触发。一个页面只会调用一次,代表页面已经准备妥当, 可以和视图层进行交互。
- onHide()
- 页面隐藏/切入后台时触发。 如 wx.navigateTo 或底部 tab 切换到其他页面,小程序切入后台等。
- onUnload()
- 页面卸载时触发。如 wx.redirectTo 或 wx.navigateBack 到其他页面时。
官网图示说明
官网对应地址
https://developers.weixin.qq.com/miniprogram/dev/framework/app-service/page-life-cycle.html
列表渲染
语法说明
wx:for='{{arr}}'
wx:key='{{唯一值}}'
注意事项
- 默认的个体:item
- 默认的下标:index
- 自定义个体变量名称:
wx:for-item='myItem'
- 自定义下标变量名称:
wx:for-index='myIndex'
条件渲染
语法说明
wx:if = '条件'
wx:elif = '条件'
wx:else
wx:if VS hidden
- hidden 用法:
<view hidden='{{true}}'></view>
- wx:if 等同于 v-if,条件为 false 的时候不加载,条件切换的时候决定元素销毁或者重新加载渲染
- hidden 等同于 v-show,始终加载元素,条件切换的时候决定元素的显示和隐藏
模版使用
定义模板
引入模版
- 引入模板结构:
<import src='模板结构相对路径'/>
- 引入模板样式:
@Import '模板样式路径'
使用模板
小程序API
API使用说明
- 小程序提供了很多实用的方法供开发者使用
- 小程序全局对象是: wx
- 所有的 API 都保存在 wx 对象中
常用API
界面交互
- 显示消息提示框:
wx.showToast()
- 显示消息加载框:
wx.showLoading()
- 关闭消息提示框:
wx.hideToast()
- 关闭消息加载框:
wx.hideLoading()
- 显示消息提示框:
路由跳转
wx.navigateTo()
wx.redirectTo()
wx.switchTab()
网络请求
wx.request()
本地存储
wx.setStorage()
wx.setStorageSync()
wx.getStorage()
wx.getStorageSync()
媒体
wx.getBackgroundAudioManager()
wx.playVoice()
前后端交互
语法:
wx.request()
注意点:
协议必须是https协议
一个接口最多配置20个域名
并发限制上限是10个
开发过程中设置不校验合法域名: 开发工具 —> 右上角详情 —-> 本地设置 —> 不校验
事件委托
- 什么是事件委托
- 将子元素的事件委托(绑定)给父元素
- 事件委托的好处
- 减少绑定的次数
- 后期新添加的元素也可以享用之前委托的事件
- 事件委托的原理
- 冒泡
- 触发事件的是谁
- 子元素
- 如何找到触发事件的对象
- event.target
- currentTarget VS target
- currentTarget要求绑定事件的元素一定是触发事件的元素
- target绑定事件的元素不一定是触发事件的元素
本地存储
存入数据
语法:
wx.setStorage() || wx.setStorageSync() || .....
注意点:
建议存储的数据为json数据
单个 key 允许存储的最大数据长度为 1MB,所有数据存储上限为 10MB
属于永久存储,同H5的localStorage一样
读取数据
wx.getStorage()
异步wx.getStorageSync()
同步
删除数据
wx.removeStorage()
异步wx.removeStroageSync()
同步
清空数据
wx.clearStorage()
异步wx.clearStorageSync()
同步
定义事件相关
分类
- 标准DOM事件
- 自定义事件
标准DOM事件
- 举例: click,input。。。
- 事件名固定的,事件由浏览器触发
自定义事件
绑定事件
- 事件名
- 事件的回调
- 订阅方: PubSub.subscribe(事件名,事件的回调)
- 订阅方是接受数据的一方
触发事件
- 事件名
- 提供事件参数对象, 等同于原生事件的event对象
- 发布方: PubSub.publish(事件名,提供的数据)
- 发布方是提供数据的一方
页面通信
路由传参
- 传参方式
- 路由地址中 + query 传参数
- 示例: url?a=123
- 获取参数:跳转目标页面的 onLoad 函数中的 options 实参中获取
消息订阅发布
- 使用第三方库:
pubsub-js
- 安装:
npm install pubsub-js
- 使用:
import PubSub from ‘pubsub-js’
- 订阅消息:
PubSub.subscribe('eventName', callback)
- 发布消息:
PubSub.publish('eventName', data)
- 取消订阅:
PubSub.unsubscribe('eventName')
eventChannel事件通道
- 订阅事件:
wx.navigateTo()
跳转的时候在 events 选项中定义事件名及事件对应的回调
- 获取事件总线对象
- 目标页面中通过:
实例.getOpenerEventChannel()
- 示例:
const eventChannel = this.getOpenerEventChannel()
- 目标页面中通过:
- 触发事件:
eventChannel.emit('事件名', data)
自定义组件
创建组件
- 开发工具中右键新建组件
- 组件对应的 json 文件中设置:
component: true
使用组件
使用组件的页面的 json 文件中注册使用组件
使用npm包
- 初始化 package.json:
npm init
- 勾选允许使用npm
- 下载npm包:
npm install packageName
- 构建npm
- 开发工具 —> 工具 —> 构建 npm
- 会将 node_modules 中的包打包到 miniprogram_npm 中
获取用户唯一标识(openId)
官网图解
获取流程
wx.login()
,拿到code- 发送 code 给服务器端
- 服务器端发送请求携带参数(code, appSecret, appId)给微信服务器获取 openId
- appSecret,appId 在小程序首页获取
- 服务器获取 openId 后进行加密返回给前端
小程序分包
为什么要分包
- 小程序要求压缩包体积不能大于 2M,否则无法发布
- 实际开发中小程序体积如果大于 2M 就需要使用分包机制进行发布上传
- 分包后可解决 2M 限制,并且能分包加载内容,提高性能
- 分包后单个包的体积不能大于 2M
- 分包后所有包的体积不能大于 16M
分包形式
- 常规分包
- 独立分包
- 分包预下载
常规分包
- 开发者通过在 app.json 中,用 subpackages 字段声明项目分包结构
- 特点:
- 加载小程序的时候先加载主包,当需要访问分包的页面时候才加载分包内容
- 分包的页面可以访问主包的文件,数据,图片等资源
- 主包:
- 主包来源: 除了分包以外的内容都会被打包到主包中
- 通常放置启动页 /tabBar 页面
独立分包
- 设置 independent 为 true
- 特点:
- 独立分包可单独访问分包的内容,不需要下载主包
- 独立分包不能依赖主包或者其他包的内容
- 使用场景
- 通常某些页面和当前小程序的其他页面关联不大的时候可进行独立分包
- 如:临时加的广告页 || 活动页
分包预下载
配置
- app.json 中设置 preloadRule 选项
- key(页面路径): {packages: [预下载的包名 || 预下载的包的根路径])}
特点
- 在加载当前包的时候可以设置预下载其他的包
- 缩短用户等待时间,提高用户体验
官网对应地址
https://developers.weixin.qq.com/miniprogram/dev/framework/subpackages.html
小程序转发分享
分享实现
- Button 组件设置 open-type 为 share
<button open-type='share'></button>
自定义分享内容
生命周期回调中 onShareAppMessage 回调中 return 对象设置自定义内容
小程序支付流程
支付流程官网图解
详细说明
用户在小程序客服端下单(包含用户及商品信息)
小程序客户端发送下单支付请求给商家服务器
商家服务器同微信服务器对接获取唯一标识 openID
商家服务器根据 openId 生成商户订单(包含商户信息)
商家服务器发送请求调用统一下单 API 获取预支付订单信息
商家对预支付信息签名加密后返回给小程序客户端
- 签名方式:MD5
- 签名字段:小程序 ID,时间戳,随机串,数据包,签名方式
- 参考地址:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=3
用户确认支付(鉴权调起支付)
- API:
wx.requestPayment()
- API:
微信服务器返回支付结果给小程序客户端
微信服务器推送支付结果给商家服务器端
官网对应地址
https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_3&index=1
实战:TenCloudMusic
主页
1 | <view class="indexContainer"> |
1 | .banners { |
1 | import request from "../../utils/request" |
1 | { |
组件
1 | <view class="header"> |
1 | .header { |
1 | Component({ |
1 | { |
登陆
1 | <view class="container"> |
1 | .wrapper{ |
1 | import request from "../../utils/request"; |
1 | { |
个人中心
1 | <view class="personalContainer"> |
1 | .personalContainer { |
1 | import request from "../../utils/request"; |
搜索
1 | <view class="searchContainer"> |
1 | .searchContainer { |
1 | import request from '../../utils/request' |
1 | { |
视频
1 | <view class="videoContainer"> |
1 | .videoContainer .header { |
1 | import request from "../../utils/request" |
1 | { |
每日推荐
1 | <view class="recommendSongContainer"> |
1 | /* 头部 */ |
1 | import PubSub from 'pubsub-js' |
1 | { |
歌曲页
1 | <view class="songDetailContainer"> |
1 | .songDetailContainer { |
1 | import PubSub from 'pubsub-js' |
config.js
1 | // 配置服务器相关信息 |
request.js
1 | //发送ajax请求 |
app.js
1 | App({ |
app.json
1 | { |
app.wxss
1 | @import "/static/iconfont/iconfont.wxss"; |