写在最前面
边看视频 * 边撸代码 * 边记笔记,学习效率蹭蹭蹭~~~
学习视频
快速访问
视图层
750rpx
- 设计稿推荐
750px
宽度 - 换算公式:750 * 被测量元素宽度 / 设计稿总宽度
- 字体尺寸规范
设计稿 rpx 转换
已知设计稿总宽度 375px
某元素宽度 150px
width:calc(750rpx * 150 / 375);
设计稿 vw 转换
vw
适用于 web
端,此写法 Sass/Less
通用
已知设计稿总宽度 375px
某元素宽度 150px
$ui-width: 375px;
@function px2vw($px) {
@return $px / $ui-width * 100vw;
}
width:px2vw(150px);
框架
app.js
生命周期
和全局数据
- 设置全局数据
App({ onLaunch: function () { // }, globalData: { old:18 } });
- 页面
.js
读取全局数据const app = getApp(); console.log(app.globalData.old);
wxml
无法直接读取全局数据,只能先保存到页面.js
的data
const app = getApp(); Page({ data: { old:app.globalData.old, } });
- developers.weixin.qq.com/miniprogram…
app.json
- 全屏显示
{ "window": { "navigationStyle": "custom" } }
- developers.weixin.qq.com/miniprogram…
加载 WeUI 组件库
- app.json
{
"useExtendedLib": {
"weui": true
}
}
- 页面
.json
配置需要的组件
{
"usingComponents": {
"mp-icon": "weui-miniprogram/icon/icon"
}
}
- 页面
.wxml
使用组件
<mp-icon icon="add"></mp-icon>
自定义 tabBar
- app.json
{
"pages": [
"pages/index/index",
"pages/analysis/index",
"pages/settings/index"
],
"tabBar": {
"color": "#515151",
"selectedColor": "#1296db",
"backgroundColor": "#FFFFFF",
"list": [
{
"text": "首页",
"pagePath": "pages/index/index",
"iconPath": "images/calculator.png",
"selectedIconPath": "images/calculator-active.png"
},
{
"text": "统计",
"pagePath": "pages/analysis/index",
"iconPath": "images/data.png",
"selectedIconPath": "images/data-active.png"
},
{
"text": "设置",
"pagePath": "pages/settings/index",
"iconPath": "images/set.png",
"selectedIconPath": "images/set-active.png"
}
]
}
}
页面.js
-
数据
和生命周期
和事件
-
onLoad
适合数据操作 -
onReady
适合组件操作
页面.json
- 可以覆盖
app.js
的配置 - developers.weixin.qq.com/miniprogram…
下拉刷新
- index.json
{
"enablePullDownRefresh": true
}
- index.js
Page({
onPullDownRefresh() {
console.log('下拉刷新了');
}
});
获取到数据后关闭下拉
wx.stopPullDownRefresh()
页面背景色设置
index.json
设置的是手势下拉后面的背景色
{
"backgroundColor": "#ededed"
}
如果要设置页面背景颜色,得在 wxss
中自定义
page {
background-color: #ededed;
}
路由页面跳转
页面间通信
链接参数
- 简单且使用率高
- 单向
A向B传递数据
使用场景:打开详细页
A.js
Page({
fn(){
wx.navigateTo({
url: '/pages/page2/index?id=1&old=18'
})
}
})
B.js
Page({
onLoad(option){
console.log(option);
}
})
全局数据参数
app.js
的globalData
- 可以在任意两个页面间通信
- 但是不会实时更新
EventChannel
B向A传递数据
使用场景:B新规文章后 A刷新文章列表
A.js
在 events
里添加 a
事件
Page({
fn(){
wx.navigateTo({
url: '/pages/page2/index',
events:{
a(data){
console.log(data);
}
}
})
}
})
B.js
通过 eventChannel.emit
触发 A.js
的 a
事件并带参数
Page({
fn(){
this.getOpenerEventChannel().emit('a',{
id: 1,
old: 18
});
}
})
A向B传递数据
使用场景:打开详细页
A.js
通过在 success
里添加 eventChannel.emit
触发 B.js
的 a
事件并带参数
Page({
fn(){
wx.navigateTo({
url: '/pages/page2/index',
success({eventChannel}){
eventChannel.emit('a',{
id: 1,
old: 18
})
}
})
}
})
B.js
监听 a
事件
Page({
onLoad(option){
this.getOpenerEventChannel().on('a',function(option){
console.log(option);
})
}
})
容器类
view
- 类似
html
里的div
标签 - 官网推荐:不使用
:active
伪类,并使用hover-class
替换:active
- developers.weixin.qq.com/miniprogram…
使用 hover-stop-propagation
可以防止 hover
事件冒泡
//
<view>
父
<view
hover-class="hover"
hover-stop-propagation
>
子
</view>
</view>
// 或者
<view>
父
<view
hover-class="hover"
hover-stop-propagation="{{true}}"
>
子
</view>
</view>
web-view
- 自动全屏
- 个人小程序不可用
- developers.weixin.qq.com/miniprogram…
必须是业务域名才可用
<web-view src="https://juejin.cn/"></web-view>
swiper & swiper-item
swiper
内部只能放swiper-item
- developers.weixin.qq.com/miniprogram…
基本结构
<swiper
indicator-dots
autoplay
>
<swiper-item>
<image src="/images/1.jpg"/>
</swiper-item>
<swiper-item>
<image src="/images/2.jpg"/>
</swiper-item>
</swiper>
open-data
- 可以拿到微信的开放数据
open-gid
不可获取- developers.weixin.qq.com/miniprogram…
获取用户开放数据
<open-data type="userNickName"/>
<open-data type="userAvatarUrl"/>
<open-data type="userGender" lang="zh_CN"/>
内容类
icon
progress
text
- 不等于
span
- 默认用户不可选中文字
- developers.weixin.qq.com/miniprogram…
用户可选中文字
<text
selectable
>222</text>
rich-text
- 为了安全和性能
rich-text
只能通过nodes
属性读取json
格式的富文本数据- developers.weixin.qq.com/miniprogram…
navigator
- 路由页面跳转
- 类似
html
里的a
标签 - developers.weixin.qq.com/miniprogram…
自定义页面内返回链接
<navigator
open-type="navigateBack"
>
返回
</navigator>
表单类
button
快速实现分享功能
<button
type="primary"
open-type="share"
>分享</button>
checkbox-group
- 可选标签,但是用
checkbox-group
提交数据更方便 - developers.weixin.qq.com/miniprogram…
picker
- 功能强大,已封装时间、日期、地区选择器
- 类似
html
里的select + option
标签 json
数据可以通过range-key
来指定显示内容- developers.weixin.qq.com/miniprogram…
自定义选择器内容
index.wxml
<picker
range="{{array}}"
bindchange="bindChange"
>
当前选择:{{array[index]}}
</picker>
index.js
Page({
data:{
index:0,
array:[
'张三', '李四', '王五'
]
},
bindChange(e){
console.log(e.detail.value);
this.setData({
index: e.detail.value
})
}
});
form
使用表单校验 WxValidate 扩展插件
-
WxValidate.js 放入
/utils/WxValidate.js
-
index.wxml
<form bindsubmit="bindSubmit"> <label> NAME: <input name="your-name" type="text" placeholder="输入NAME"/> </label> <label> EMAIL: <input name="your-email" type="text" placeholder="输入EMAIL"/> </label> <label> MESSAGE: <textarea name="your-message" rows="10" placeholder="输入MESSAGE"></textarea> </label> <button formType="submit" type="primary">提交</button> </form>
-
index.js
import WxValidate from '../../utils/WxValidate.js' Page({ data: {}, onLoad: function (options) {}, bindSubmit(e){ // 验证字段的规则 const rules = { 'your-name': { required: true, }, 'your-email': { required: true, email: true, }, 'your-message': {} }; // 验证字段的提示信息,若不传则调用默认的信息 const messages = { 'your-name': { required: '请输入姓名', }, 'your-email': { required: '请输入邮箱', email: '请输入正确的邮箱', }, 'your-message': {}, } // 创建实例对象 this.WxValidate = new WxValidate(rules,messages); // 传入表单数据,调用验证方法 if (!this.WxValidate.checkForm(e.detail.value)) { console.log(this.WxValidate.errorList); const error = this.WxValidate.errorList[0]; wx.showToast({ icon: 'none', title: error.msg, }) return false; } // 验证成功后表单数据发送给后端 wx.request({ url: 'https://juejin.cn/form', method: 'POST', data: e.detail.value, success: res=> { console.log(res); } }); } })
媒体类
image
video
<video
id="v1"
src="https://juejin.cn/media/video.mp4" />
<button
type="primary"
bindtap="play"
>播放</button>
<button
type="primary"
bindtap="pause"
>暂停</button>
Page({
play(){
let v1 = wx.createVideoContext('v1')
v1.play()
v1.requestFullScreen()// 真机才能全屏
},
pause(){
let v1 = wx.createVideoContext('v1')
v1.pause()
}
})
radio
- 组件 radio
- 结合 wx.createInnerAudioContext() 使用
背景音频
- 关闭小程序继续播放音乐
- wx.getBackgroundAudioManager()
地图
map
- 只能用腾讯地图(不然呢
- developers.weixin.qq.com/miniprogram…
画布
canvas
- 强大到我学不动。。。
- developers.weixin.qq.com/miniprogram…
页面配置
page-meta
方便动态设置页面配置
<page-meta
background-color="{{bgColor}}"
background-color-top="{{bgColorTop}}"
>
<navigation-bar
title="{{title}}"
loading="{{loading}}"
/>
</page-meta>
语法类
数据
{{}}
内不可以放入函数表达式,不会运行- developers.weixin.qq.com/miniprogram…
- 数据只能放在页面
.js
的data
里Page({ data: { oy:'技术黄' } });
.wxml
页面获取数据<view>{{oy}}</view> <view id="{{oy}}" ></view>
.js
获取数据this.data.oy
事件
- 事件函数写在页面
.js
里 - developers.weixin.qq.com/miniprogram…
通过事件实现数据递增
- index.wxml
<view>{{old}}</view>
<button
type="primary"
bindtap="bindTap"
>Add</button>
- index.js
Page({
data: {
old:18
},
bindTap(){
this.setData({
old : this.data.old + 1
});
}
});
循环
wx:for
- 默认提供
index
和item
二个值,可自定义修改 - 可循环:数组、字符串、数字、json
- 为了性能需要设置
wx:key
,最好使用后台提供的id
字段
只渲染循环内部分
- 通过 block 标签实现
<block wx:for="{{['张三', '李四', '王五']}}" wx:key="index" > <text>{{index}}:{{item}}</text> </block>
- 染循输出结果
<text>0:张三</text> <text>1:李四</text> <text>2:王五</text>
结合 swiper 循环
- index.wxml 这里的
wx:key
直接输入键名即可
<swiper
indicator-dots
autoplay
>
<swiper-item
wx:for="{{swiper_imgs}}"
wx:key="id"
>
<image src="/images/{{item.src}}" />
</swiper-item>
</swiper>
- index.js
Page({
data: {
swiper_imgs:[
{id:1,src:'1.jpg'},
{id:2,src:'2.jpg'}
]
}
});
条件
wx:if
wx:elif
wx:else
- 多个组件判断
block wx:if
- developers.weixin.qq.com/miniprogram…
结合 switch 开关效果
- index.wxml
<switch
checked="{{show}}"
bindchange="bindChange"
/>
<view
wx:if="{{show}}"
>Hello World</view>
- index.js
Page({
data: {
show:false
},
bindChange(e){
this.setData({
show:!e.detail.value
});
}
});
模块化
- 重复使用内容模块化优化
- 放置在
/miniprogram/utils
文件夹内 - developers.weixin.qq.com/miniprogram…
- utils/location.js
module.exports = (age) => {
console.log(age)
}
- pages/index/index
let location = require('../../utils/location')
location(18)
自定义组件
developers.weixin.qq.com/miniprogram…
创建自定义组件
components
文件夹右键- 新建文件夹命名组件名
header
header
文件夹右键新建 component
pages/index/index.json
{ "usingComponents": { "header": "../../components/header" } }
- 页面使用
header
组件<header />
组件属性
页面设置组件的属性值,可以在组件内显示,通过 properties
来设置
页面
pages/index/index.wxml
<header title="hello world" />
组件
components/header/index.js
Component({
properties: {
title:{
type: String,
value: '默认值'// 没有默认值可以删除这行
}
}
})
组件
components/header/index.wxml
<view>{{title}}</view>
组件内方法
组件内方法必须放在 methods
内
组件
components/header/index.js
Component({
methods: {
fn(){
console.log('hello world');
}
}
})
组件
components/header/index.wxml
<button
bindtap="fn"
>组件方法调用</button>
组件自定义数据
获取在标签上自定义的 data-xx
数据,通过 dataset
属性获取
页面
pages/index/index.wxml
<header data-age="18" />
组件
components/header/index.js
Component({
methods: {
fn(){
console.log('data-age: '+this.dataset.age);
}
}
})
监听组件属性变化
监听 properties
内数据的变化,通过 observer
实现,适用于 父向子 场景
组件
components/header/index.js
Component({
properties: {
title:{
type: String,
value: '默认值',
observer: function(){
console.log('title值每次变化都会触发');
}
}
}
})
生命周期
developers.weixin.qq.com/miniprogram…
组件的的生命周期必须放在 lifetimes
内
组件的 ready
类似页面的 onload
Component({
lifetimes: {
ready: function() {
console.log('onload');
}
}
})
组件的 pageLifetimes
可以监听组件所在页面的生命周期
Component({
pageLifetimes: {
show: function() {
// 页面被展示
},
hide: function() {
// 页面被隐藏
},
resize: function(size) {
// 页面尺寸变化
}
}
})
组件间通信
developers.weixin.qq.com/miniprogram…
父向子
使用场景:打开详细页
- 动态修改组件的
properties
属性 - 通过子组件属性的
observer
监听实现父向子传递
页面
pages/index/index.wxml
<page title="{{page.title}}" content="{{page.content}}"></page>
<button
bindtap="fn"
>父向子</button>
页面
pages/index/index.js
Page({
data: {
page:{
title: 'title',
content: 'content'
}
},
onLoad: function (options) {
},
fn(){
this.setData({
page:{
title: this.data.page.title + '+',
content: this.data.page.content + '+'
}
})
}
})
组件
components/page/index.wxml
<view>{{title}}</view>
<view>{{content}}</view>
组件
components/page/index.js
// components/view/index.js
Component({
properties: {
title:{
type: String,
observer: function(){
console.log('page.title属性监听');
}
},
content:{
type: String,
observer: function(){
console.log('page.content属性监听');
}
},
}
})
子向父
使用场景:子页面数据库添加数据后,通知父页面刷新
- 子组件通过
triggerEvent
通知父 - 页面引用的组件设置
bind:xxx
绑定通知 - 页面
e.detail
可以获取参数
页面
pages/index/index.wxml
<add
bind:add="fn"
></add>
页面
pages/index/index.js
Page({
data: {},
onLoad: function (options) {
},
fn(e){
console.log(e.detail);// 可获取子组件的参数
console.log('子组件触发父方法');
}
})
组件
components/add/index.wxml
<button
bindtap="fn"
>子向父</button>
组件
components/add/index.js
Component({
methods: {
fn(){
this.triggerEvent('add', {name:'oy',age:18})
}
}
})
behaviors
developers.weixin.qq.com/miniprogram…
- 可以向组件内部注入“组件”内容,如果内容相同组件优先
- 适合复用相同内容
- 只能用在组件里
- 不建议使用,维护难度大哈哈哈
云开发
- 安全性高、可扩容、自带鉴定权限。
- 配置云开发目录
project.config.json
{ "miniprogramRoot": "miniprogram/", "cloudfunctionRoot": "cloudfunctions/" }
云函数
cloudfunctions
右键 [新建 Node.js 云函数]add
cloudfunctions/add/index.js
// 云函数入口文件 const cloud = require('wx-server-sdk') cloud.init() // 云函数入口函数 exports.main = async (event, context) => { return 'Hello World ' + event:name; }
add
右键 [上传并部署:云端安装依赖]- 前端使用
miniprogram/pages/index/index.js
Page({ data: { name:'张三' }, onLoad: function (options) {}, fn(){ wx.cloud.callFunction({ name:'add', data:{}, success(res){ console.log(res); }, fail(res){ console.log(res); } }); } })
网络
请求
wx.request({
url: 'https://api.juejin.cn/',
method: 'POST',
data: {
x: '',
y: ''
},
header: {
'content-type': 'application/json'
},
success (res) {
console.log(res.data)
},
fail (err) {
console.error(err)
}
})
封装成 Promise 风格
wx.request
默认不支持 Promise
风格,我们可以自己封装。
miniprogram/utils/request.js
module.exports = (name,age,url) => {
return new Promise((resolve, reject) => {
wx.request({
url,
data: {
name,
age
},
success (res) {
resolve(res.data)
},
fail (err) {
reject(err)
}
})
})
}
使用
let utilsRequest = require('../../utils/request')
Page({
onLoad: async function (options) {
let res = await utilsRequest('Hello World', '18', 'https://juejin.cn/')
}
})
上传
wx.chooseImage({
success (res) {
const tempFilePaths = res.tempFilePaths
wx.uploadFile({
url: 'https://juejin.cn/upload',
filePath: tempFilePaths[0],
success ({data}){
console.log(data)
}
})
}
})
WebSocket
- 可持续连接
- 数据双向通信
wx.connectSocket({
url: 'wss://juejin.cn'
})
wx.sendSocketMessage({
data: 'hello world'
})
数据缓存
读取
wx.getStorageSync('title')
写入
wx.setStorageSync('title', 'hello world')
清空
wx.clearStorageSync()
获取用户信息
不包含 OPENID
wx.getUserProfile
必须点击,弹出窗口用户确认后才能获取
<button type="primary" bindtap="getUserProfile">授权登录</button>
Page({
getUserProfile() {
wx.getUserProfile({
desc: '用于完善会员资料',
success: (res) => {
console.log(res.userInfo);
}
})
}
})
wx.getUserInfo
必须点击,弹出窗口可获取
官方自 2021年4月13日
起只能获取匿名的用户个人信息
,所以可以弃用了。
<button type="primary" open-type="getUserInfo" bindgetuserinfo="bindGetUserInfo">授权登录</button>
// pages/login/index.js
Page({
bindGetUserInfo (e) {
console.log(e.detail.userInfo)
}
})
用户设置
wx.getSetting
查询 userInfo
userLocation
用户授权结果
wx.openSetting
打开小程序授权设置界面
授权定位
判断如果没有授权,就通过 openSetting
打开小程序授权设置界面
Page({
onLoad: async function (options) {
// 授权定位
try{
let res = await wx.getLocation({type: 'wgs84'})
}catch(e){
// 未授权或者拒绝定位 就止步到这里了
this.checkAuthSetting()
return
}
},
async checkAuthSetting(){
let {authSetting} = await wx.getSetting()
if (!authSetting['scope.userLocation']) {
// console.log('未授权定位');
wx.showModal({
title: '请授权定位',
success: ({confirm}) => {
if(confirm){
// 打开小程序授权设置界面
wx.openSetting({
success: () => {
// 再核实下是否授权定位
wx.redirectTo({
url: '/pages/index/index',
})
}
})
}
}
})
return {
code: 400,
msg: '未授权定位'
};
}else{
return {
code: 200,
msg: '已经授权定位'
}
}
}
})
技巧篇
支持 sass
- 修改
project.config.json
里setting
的useCompilerPlugins
值,如果没有这个值就添加"useCompilerPlugins": ["sass"],
- 修改
index.wxss
的后缀为index.scss
- 清缓存刷新
- 如果还是不行控制台报错就
详情
里找到将JS编译成ES5
取消选中然后再选中(不知道算不算编辑器bug)
获取 openid
- 小程序:云函数,最方便但是。。。
- web:url -> code -> access_token -> openid
- 小程序 + web:wx.login(code) -> access_token -> openid 最优方案
检测小程序新版本
- developers.weixin.qq.com/miniprogram…
- 自动监测下载最新版小程序
- app.js
// app.js App({ onLaunch: function () { this.globalData = {}; // 自动监听是否有新版本 const updateManager = wx.getUpdateManager() updateManager.onUpdateReady(function () { wx.showModal({ title: '更新提示', content: '新版本已经准备好,是否重启应用?', success: function (res) { if (res.confirm) { // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启 updateManager.applyUpdate() } } }) }) } });
小程序生成URL
这里使用的是 URL Link
生成的,因为时效只有 30
天,所以放在 html
里跳转方便替换。
- 获取
access_token
developers.weixin.qq.com/miniprogram… - 通过获取的
access_token
来获取url_link
developers.weixin.qq.com/miniprogram… - 把获取到的
url_link
贴入html
中// 生成日期20221010 有效期 30天 location.href = 'https://wxaurl.cn/abcdefg';
HTML5 中使用 WeUI 样式库
- github.com/Tencent/weu…
- 文档:github.com/Tencent/weu…
- alert
<link rel="stylesheet" href="https://res.wx.qq.com/open/libs/weui/2.0.1/weui.min.css"> <script src="https://res.wx.qq.com/t/wx_fed/cdn_libs/res/weui/1.2.3/weui.min.js"></script> <script> weui.alert('alert'); </script>
- loading
let loadingWeUI = weui.loading('加载中'); setTimeout(function () { loadingWeUI.hide(function() { console.log('加载完成'); }); }, 3000);
持续更新