注册微信小程序获取APPID 创建项目时选用APPID

image

目录认识

image

小程序文件结构与传统web对比

传统web微信小程序
HTMLWXML
CSSWXSS
JavascriptJavascript
配置:无JSON

新建文件夹

app.json下 pages输入文件名会自动创建

image

app.json认识

image-20220831210037876

TabBar底部导航

字段解释

pagePath:跳转的路径
text:名字 描述
iconpath:未选中时的图标路径
selectedIconPath:选中时的图标路径

app.json list最少2个

"tabBar": {
"list": [{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "icon/_home.webp",
"selectedIconPath": "icon/home.webp"
},{
"pagePath": "pages/demo1/demo1",
"text": "图片",
"iconPath": "icon/_img.webp",
"selectedIconPath": "icon/img.webp"
},{
"pagePath": "pages/video/video",
"text": "视频",
"iconPath": "icon/_videocamera.webp",
"selectedIconPath": "icon/videocamera.webp"
},{
"pagePath": "pages/logs/logs",
"text": "日志",
"iconPath": "icon/_search.webp",
"selectedIconPath": "icon/search.webp"
}
]
},

image

view组件

容器 div = view 具有块级元素特点

<view style="width: 100%;height: 200px;background-color: antiquewhite;">
<text class="d1">数据包</text>
<image style="width: 750rpx;" src="/images/11.webp" />
</view>

text组件

文本 span = text 具有行级元素特点

<text class="d1">数据包</text>

图片引入

图片 img = image 具有行内块级元素特点

image不设置宽高时,有默认宽高 image可以只写组件头,不写组件尾(单标签形式)。应在组件头用"/"关闭。

背景图片在行内样式时可以加载本地图片,写到wxss中只能加载网络图片

<image style="width: 750rpx;" src="/images/11.webp" />

rpx自适应

750rpx就是全屏

可以在组件头中写行内样式,也可在wxss中写样式(自动引入)

rpx: 自适应屏幕宽度尺寸。规定屏幕宽为750份,每份为1rpx。

在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,1rpx = 0.5px = 1物理像素

flex布局

  1. 任何容器都可以指定为Flex布局,任何子组件都可以设置宽高
  2. 父组件
设置成弹性盒子:display: flex;
指定主轴方向:flex-direction: column;
指定是否换行:flex-wrap:wrap;
指定在主轴对齐方式:justify-content:space-between|space-around;
指定在交叉轴对齐方式:align-items:center;
  1. 子组件

    flex:定义了项目的缩放比例

修改每个界面的顶部名字

//在对应界面的....json中

"navigationBarTitleText": "列表"

image

自定义头部

//在对应的界面的json配置文件中

"navigationStyle": "custom"

image

数据绑定

<!-- 绑定普通参数 字符串-->
<view>{{message}}</view>
<!-- 数值型 -->
<text>{{age}}</text>
<!-- 对象型 -->
<text>{{student.stname}}</text>
<!-- boolean型 -->
<text>{{isture}}</text>

数据

data: {
message:'你好',
age:10,
student:{
id:10,
stname:'李四',
address:'湖南湘潭',
height:'180cm'
},
isture:true,
}

运算

<!-- 运算符 -->
<view hidden="{{age==11 ? true:false}}">你可以看见嘛</view>
<view>{{a+b+c}}</view>
<view>{{'helo'+5}}</view>
<view>{{8%5==0 ? '偶数':'奇数'}}</view>

for循环

<!-- 使用默认输出item  默认下标index-->
<view>
<!-- 也可以使用wx:key="index" -->
<text wx:for="{{number}}" wx:key="*this">{{index}}:{{item}}</text>
</view>

<!-- 改变默认输出变量wx:for-item="变量名" 改变下标:wx:for-index="下标名"-->
<view>
<text wx:for="{{number}}" wx:key="*this" wx:for-item="obj" wx:for-index="i">{{i}}:{{obj}}</text>
</view>

<!-- 嵌套循环 -->
<view>
<view wx:for="{{grop}}" wx:key="*this" wx:for-item="obj" wx:for-index="i">
<view wx:for="{{obj}}" wx:key="*this" wx:for-item="enum">{{enum}}</view>
</view>
</view>

<!-- 循环对象 -->
<view wx:for="{{student}}" wx:key="id">
{{item}}--{{index}}
</view>

<!-- 循环数组对象 -->
<view wx:for="{{cf}}" wx:key="*this">
{{item.id}}--{{item.name}}
</view>

数据

data: {
message:'你好',
age:10,
student:{
id:10,
stname:'李四',
address:'湖南湘潭',
height:'180cm'
},
isture:true,
a:1,
b:2,
c:3,
number:[1,2,34,34,45,55,76,6887],
grop:[
[1,24,5,6,78,98],
[1,2,3,4,5,6,7]
],
cf:[
{id:10,name:'李四'},
{id:11,name:'李四2'},
{id:12,name:'李四3'}
]
}

多选框是否勾选

<!-- 多选框ture false -->
<checkbox checked="{{ture}}"></checkbox>

隐藏显示

//hidden true/false
<view hidden="{{age==11 ? true:false}}">你可以看见嘛</view>

block

<!-- block不会生成dom元素 是个占位符 -->
<block wx:for="{{number}}" wx:key="*this">
{{item}}
</block>

条件判断

<!-- 条件渲染 if 很少次使用IF 频繁使用就hidden-->
<text wx:if="{{week==1}}">星期一学Java</text>
<text wx:elif="{{week==2}}">星期二学MK</text>
<text wx:elif="{{week==3}}">星期三学前端</text>
<text wx:elif="{{week==4}}">星期四学MK</text>
//else
<text wx:else>看剧</text>

事件绑定

点击事件

<!-- 绑定事件 带参数-->
<button bindtap="dj">点击事件</button>

文本框输入事件

 <!-- 输入了内容就会调bindinput 输入后触发 -->
<input bindinput="sr" placeholder="测试输入"/>

文本框改变事件

bindchange事件

取值传值

点击按钮时取值

<!-- 绑定事件 带参数 传值data-自定义名字 -->
<button bindtap="dj" data-number="5">点击事件</button>

//js
dj:function(e){
console.log(e);
console.log('点击成功');
//获取参数 e.currentTarget.dataset.传值的自定义名字
console.log(e.currentTarget.dataset.number);
}

//上面写成这样也可以
dj(){

}

取出文本框输入的值

 <!-- 输入了内容就会调bindinput 输入后触发 -->
<input bindinput="sr" placeholder="测试输入"/>


//输入框
sr(e){
console.log('输入框');
console.log(e);
//获取文本框的值 j
console.log(e.detail.value);
//给Data的属性赋值
this.setData({info:e.detail.value})
//取data中的值
console.log(this.data.info);
},

给data定义的属性赋值

//this.setData({属性名:值}) 属性名是上面定义的data的属性值
jsjg(e){
console.log(this.data.js);
console.log(this.data.js2);
let res=parseInt(this.data.js)+parseInt(this.data.js2);
console.log(res);
this.setData({he:res});
}

获取data中的属性值

this.data.info
//属性名是data中定义的名字
this.data.属性名

获取全局APP实例

app.js下定义的全局数据

image

获取全局值 任意界面

const app=getApp();
console.log(app.globalData.url);

下拉刷新

app.json

"enablePullDownRefresh": true  开启
"backgroundTextStyle":"dark",//闪动
"backgroundColor": "#efefef" 背景颜色

image

设置头部的颜色

"navigationBarBackgroundColor": "#f2a0a1",

image

授权获取用户信息

点击事件获取

//getUserProfile是方法名
<button bindtap="getUserProfile">授权用户</button>

js

wx.getUserProfile({
desc: '展示用户信息', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
success: (res) => {
console.log(res)
this.setData({
userInfo: res.userInfo
})
}
})

image

缓存的使用

设置缓存

//设置缓存 wx.setStorageSync(key,value)
wx.setStorageSync('test', app.globalData.url);

得到缓存

//得到缓存wx.getStorageSync(key)
let hu=wx.getStorageSync('test');
console.log(hu);

删除一个缓存

//删除一个缓存
wx.removeStorage({
key: 'test',
});

删除全部缓存

//删除多个缓存
wx.clearStorage();

JS中跳转到某个界面

普通界面

url里面写路径
wx.navigateTo({
url: '/pages/detail/detail',
})

tabbar界面

wx.switchTab({
url:'/pages/user/index',
})

hover-class轻触

轻触样式
<view class="d1" hover-class="vietap">
hello view
</view>

text 复制

<!--user-select:可以复制(true/false)   
decode:可以是用转义(true/false)-->
<view>
无法复制
<text user-select="{{true}}" decode="{{true}}">可以复制</text>
</view>

image

常用 mode=“widthFix”

<!--默认大小 320*240  
mode:默认是缩放
aspectFit:显示长边
widthFix:高度自适应+width:100%=缩放比合适-->

<image style="display: block;"
mode="top left" src="https://sls-study-cloud-1301165591.cos.ap-guangzhou.myqcloud.com/Blog/article/njde.webp" ></image>

swiper轮播图

<swiper indicator-color="#7700FF" indicator-active-color="#1AFF00FF" autoplay="{{true}}" indicator-dots="{{true}}" interval="1000" circular="{{true}}">
<swiper-item>
<image mode="widthFix" src="https://sls-study-cloud-1301165591.cos.ap-guangzhou.myqcloud.com/music/img/1.webp"></image>
</swiper-item>
<swiper-item>
<image mode="widthFix" src="https://sls-study-cloud-1301165591.cos.ap-guangzhou.myqcloud.com/music/img/10.webp"></image>
</swiper-item>
<swiper-item>
<image mode="widthFix" src="https://sls-study-cloud-1301165591.cos.ap-guangzhou.myqcloud.com/music/img/11.webp"></image>
</swiper-item>
</swiper>

导航标签使用a标签

跳转后从储存取数据需要在onshow生命周期中使用

传值

<navigator url="/pages/goods_detail/index?goodsid={{item.goods_id}}">
</navigator>

跳到的页面JS接收

/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
//获取传过来的值商品ID
console.log(options.goodsid);
this.getgoodsinfo(options.goodsid);
},

默认使用

<!--导航 a标签 默认不能跳到tabBar页面-->
<navigator url="/pages/day4/day4">视频navgator</navigator>

重定向模式

<!--重定向模式 不能跳tabbar页面 不能回到原来页面-->
<navigator url="/pages/day4/day4" open-type="redirect">redirect</navigator>

跳到TabBar页面

<!--跳掉tabBar页面 回不去-->
<navigator url="/pages/video/video" open-type="switchTab">switchTab</navigator>

TabBar和普通都可以跳

<!--随便跳 (跳tabbar)不能回去 reLaunch  (不跳tabbar)可以回去-->
<navigator url="/pages/day4/day4" open-type="reLaunch">reLaunch</navigator>

rich-text富文本标签

<rich-text nodes="<h1>你好</h1>"></rich-text>

icon标签

<icon type="success"></icon>
<icon type="success_no_circle"></icon>
<icon type="info"></icon>
<icon type="warn"></icon>
<icon type="waiting"></icon>
<icon type="cancel"></icon>
<icon type="download"></icon>
<icon type="search"></icon>
<icon type="clear"></icon>

image

button

size可以跳转大小
<button type="warn" bindtap="grcli">绿色</button>
<button type="default" bindtap="recli">红色</button>
<button type="primary" bindtap="whcli">白色</button>

加载框

 //打开
wx.showLoading({
title: 'title',
})

//关闭
wx.hideLoading();

image

消息提示框

//打开 不用手动关闭
wx.showToast({
title: 'title',
})

image

模态窗口

wx.showModal({
title: '提示',
content: '这是一个模态弹窗',
success (res) {
if (res.confirm) {
console.log('用户点击确定')
} else if (res.cancel) {
console.log('用户点击取消')
}
}
})

image

导入样式

@import '../../style/common.wxss';

使用less

vscode安装插件

image

编辑配置

image

"less.compile": {    
"outExt": ".wxss"
},

写less保存后直接变成wxss

分享

<!-- 分享 -->
<button open-type="share">分享</button>

打开客服

<!-- 打开客服 -->
<button open-type="contact">打开客服</button>

单选框

单选框
<radio-group bindchange="rachange">
<radio value="回家" checked="{{true}}">回家</radio><radio value="上学">上学</radio>
<text>你选择的是:{{beh}}</text>
</radio-group>

js

rachange(e){
this.setData({
beh:e.detail.value
})
console.log(this.data.beh);
},

多选框

<checkbox-group bindchange="getsg">
<checkbox wx:for="{{fruit}}" wx:key="*this" value="{{item}}">{{item}}</checkbox>
<view>选中的水果:{{sg}}</view>
</checkbox-group>

js
getsg(e){
console.log(e);
this.setData({
sg:e.detail.value
})
}

组件

创建组件

创建components–>News–>新建Component

image

js文件夹分析

/**
* 组件的属性列表
*/
properties: {

},
/**
* 组件的初始数据
*/
data:{

},
/**
* 组件的方法列表
*/
methods: {

}

注册组件

在需要使用这个组件的页面的json文件中配置组件

如我在day5中使用

{
"usingComponents": {
"Tabs": "/components/Tabs/Tabs"
}
}

image

使用组件

在改界面的wxml中使用 tabs是注册组件中的名字

<Tabs></Tabs>

组件父传子传值

界面 navlist是父组件的data里面的参数

day5.wxml

<Tabs nalis="{{navlist}}"></Tabs>

页面的js中data属性值

day5.js

navlist:[
{
id:1,
name:'首页',
isselect:true
},{
id:2,
name:'列表',
isselect:false
},{
id:3,
name:'我的',
isselect:false
}
]

组件中获取父组件传的值

Tabs.js

组件js中

//nalis是在界面中定义的传值属性 array是属性值的类型
properties: {
//简写
nalis:Array,
//详写
nalis:{
type:Array,
value:''
}
},

获取properties的值

this.properties.属性名

组件子传父

子组件

//触发事件传值 idchange自定义的名字 但是在父组件值使用需要加一个bind
this.triggerEvent('idchange',{id});

父组件

//bindidchange是子组件的触发事件
<Tabs nalis="{{navlist}}" bindidchange="idchange"></Tabs>

组件插槽

子组件

<view class="tabs_context">
<!--插槽 父向子传-->
<slot></slot>
</view>

父组件 组件标签中间放内容 插槽就会有内容

<Tabs nalis="{{navlist}}" bindidchange="idchange">
<!--这里面放了内容 子组件的插槽就可以获取到内容-->
<block wx:if="{{navlist[0].isselect}}">首页</block>
<block wx:if="{{navlist[1].isselect}}">列表</block>
<block wx:if="{{navlist[2].isselect}}">我的</block>
</Tabs>

生命周期

应用生命周期

app.js

onLaunch(初始化)
onShow(刚加载)
onHide(放到后台或者离开该界面)
onError(出现错误的时候执行 错误级)
onPageNotFound(页面没有找到)

页面的生命周期

xxx.js

onLoad(监听页面加载)
onReady(监听页面初次渲染完成)
onShow(监听页面显示)
onHide(监听页面隐藏)
onUnload(监听页面卸载)
onPullDownRefresh(监听用户下拉动作)
onReachBottom(页面上拉触底事件的处理函数)
onShareAppMessage(用户点击右上角分享)
onPageScroll(页面滚动触发)
onResize(尺寸变换时触发) 注:屏幕旋转是

屏幕旋转

单个界面旋转 界面.json

"pageOrientation": "auto"

整个程序旋转 app.json

"pageOrientation": "auto"

发送请求

微信提供的

wx.request({
url:'https://service-qze5ckvg-1301165591.gz.apigw.tencentcs.com
/release/test',
//成功
success(res){
console.log(res.data);
},
//错误
fail(err){
console.log(err);
}
})

promise封装请求

util.js

//promise请求

const request=(params)=>{
return new Promise((resolve,reject)=>{
wx.request({
...params,
success(res){
resolve(res.data);
},
fail(err){
reject(err);
}
})
});
}

module.exports = {
request
}

使用中导入

import {request} from '../../utils/util'

使用

request({url:'https://autumnfish.cn/api/joke/list',data:{
num:10
}}).then((res)=>{
console.log(res);
})

await使用

async asyqq() {//点击的方法 方法需要加async
let res = await request({
url: 'https://autumnfish.cn/api/joke/list', data: {
num: 10
}
});
console.log(res);
}

请求时显示加载图标封装请求

//请求时加上加载框
let ajatime=0;
//请求
const request=(params)=>{
ajatime++;
wx.showLoading({
title:'加载中...',
mask:true
});
return new Promise((resolve, reject)=>{
wx.request({
...params,
success(res){
resolve(res.data);
},
fail(err){
reject(err);
},
complete:()=>{
ajatime--;
if(ajatime===0){
wx.hideLoading();
}
}
})
})
};

微信登入

微信登入官方提供 可以通过获取用户权限 和 登入的code去后台获取token

wx.login({
success(res){
console.log(res);//返回code
}
})

图片预览

//获取所有轮播图
console.log(this.stgoods.pics);
let imgarr=this.stgoods.pics.map((v)=>v.pics_big_url);
wx.previewImage({
//当前预览的图
current:e.currentTarget.dataset.pic,
urls:imgarr
})

返回上一个界面

// 返回上一个页面
wx.navigateBack({
delta: 1,
})

上传图片到云存储

下载文件

https://github.com/tencentyun/cos-wx-sdk-v5/blob/master/demo/lib/cos-wx-sdk-v5.js

引入文件(下载的文件放在util文件夹下面 在util.js下引入文件)

var COS = require('cos-wx-sdk-v5.js');

封装方法

保存秘钥

// SECRETID 和 SECRETKEY请登录
var cos = new COS({
SecretId: 'xxxxxxxxxxxxxxxx',
SecretKey: 'xxxxxxxxxx',
});

上传方法

//储存库名字
let Bucket='sls-study-cloud-1301165591'
//地域
let Region='ap-guangzhou'
//文件上传到云存储
const cosupimg=(filename,filePath)=>{
return new Promise((resolve,reject)=>{
cos.postObject({
Bucket: Bucket,
Region: Region,
Key: 'applet of WeChat/shop/' + filename,
FilePath: filePath,
}, function (err, data) {
//判断返回的结果
if(data!=null){
resolve(data);
}else{
reject(err);
}
});
})
}

删除文件

//删除云存储图片
const decosimg=(filename)=>{
return new Promise((resolve, reject)=>{
cos.deleteObject({
Bucket: Bucket,
Region: Region,
Key: 'applet of WeChat/shop/' + filename,
}, function(err, data) {
if(data!=null){
resolve(data);
}else{
reject(err);
}
});
});
}

使用

图片示例

image

//选择图片+
upimg(){
//保存this
let that =this
wx.chooseImage({
success(res){
that.setData({
//放入临时的地址
imgarr:[...that.data.imgarr,...res.tempFilePaths]
})
}
})
},
//点击图片预览
prvimg(e){
/*console.log(e.detail.index);*/
wx.previewImage({
//当前预览的图
current:this.data.imgarr[e.detail.index],
urls:this.data.imgarr
})
},
//多行文本输入
handtext(e){
//设置输入的内容
this.setData({
feebtext:e.detail.value
});
/*console.log(this.data.feebtext);*/
},
//点击提交按钮
async feebsubmit() {
//获取原来的图片数组
let chooseImage = this.data.imgarr;
//文本内容
let feebtext = this.data.feebtext;
//判断文本域是不是为空
if (!feebtext.trim()) {
wx.showToast({
title: '反馈的内容不能为空!',
icon: 'none',
mask: true
});
return;
};
wx.showLoading({
title: '正在上传...',
mask: true
});
//有图片
if (chooseImage.length != 0) {
//循环遍历
for (const item of chooseImage) {
//下标
const i = chooseImage.indexOf(item);
//截取到文件的名字
let filename = item.substr(item.lastIndexOf('/') + 1);
//上传到云存储
let res = await cosupimg(filename, item);
console.log(res);
//判断状态
if(i===chooseImage.length-1 && res.statusCode===200){
wx.hideLoading();
wx.showToast({
title:'提交成功',
icon:'success',
mask:true
})
//重新赋值
this.setData({
imgarr:[],
feebtext:''
});
//返回上一个界面
setTimeout(()=>{
wx.navigateBack({
delta:1
});
},2000);
//返回上一个界面
setTimeout(()=>{
wx.navigateBack({
delta:1,
mask:true
});
},1100);
}
}
}else{
//只提交文字
wx.showToast({
title:'提交成功!',
icon:'success',
mask:true
});
//返回上一个界面
wx.navigateBack({
delta:1
})
}
},

轮播图的高度计算

高度:750rpx * 图片高度/图片宽度

图片宽度为100% mode:widthfix

image

iphone底部安全区适配

调用wx.getSystemInfo,获得手机型号(res.model),并存储为全局变量

// app.js
App({
// 调用wx.getSystemInfo,获得手机型号(res.model),并存储为全局变量
onLaunch: function () {
let _self = this;
wx.getSystemInfo({
success: (res) => {
let modelmes = res.model;
if (modelmes.search("iPhone X") != -1) {
_self.globalData.isIphoneX = true;
}
// wx.setStorageSync("modelmes", modelmes);
},
});
},
globalData: {
userInfo: {},
},
});

在所需页面的js文件的onLoad函数内从全局变量里面拿出来第一步存储的手机型号值,这里设置为
isIphoneX:

const app = getApp();

Page({
onLoad: function(options){
// let modelmes = wx.getStorageSync('modelmes');
let isIphoneX = app.globalData.isIphoneX;
this.setData({
isIphoneX: isIphoneX
})
}
})

给页面添加一个最底部的盒子,或者给整个页面套一个最外层的盒子(底部间距为68rpx)

<view class="detail" style="height: {{isIphoneX ? 'calc(100% - 68rpx)' : '100%'}}">
...内容
</view>

此处需要注意
App.wxss 的Page高度需要设置,同时detail页面的也需要设置溢出滚动,这样才能保证页面正常滚动

/* App.wxss */
Page{
height: 100%;
}

/* detail.wxss */
.detail{
overflow: scroll;
}

小程序刷新当前页

网上很多刷新当前页的做法是

this.onLoad();
// 或是
this.onShow();

如果只是为了清除数据刷新页面,恢复初始值的话,可以将data中的数据抽离,然后重新setData即可

let obj = {username: "xxx"}

Page({
data: JSON.parse(JSON.stringify(obj)), // 做一次深拷贝,让data与obj脱钩
fn(){
this.setData(obj); // 重新赋值data,相当于刷新了页面,因为数据还原了
}
})