前言:
WXML
和 Wxss
,以及基于javascript的逻辑层框架, 并在视图层与逻辑层间提供了数据传输和事件系统,让开发者能够专注于数据与逻辑。优点:
微信用户量大,开发门槛低,推广成本低,跨平台,无需安装。
微信小程序开发门槛低,可以实现消息通知,线下扫码,公众号关联等七大功能
同类型的小程序: 支付宝小程序,qq小程序。
微信小程序APP(ID): xxxxx
1.项目结构
|----|---index /首页
|---index.js /首页逻辑文件
|---index.json //首页配置文件
|---index.wxml /首页视图文件
|---index.Wxss //首页样式文件
|----|----1ogs“日志页面
|---logs.js
|---1ogs.json
|---logs.wxml
|---logs.wxss
|---utils /1工具文件夹
|--util.js
|---app.js //全局入口文件
|---app.json //全局配置文件
|---app.NXss //全局样式文件
|---project.config.json //项目配置文件
|---sitemap.json //索引配置文件
2.app.json应用配置项
小程序根目录下的 app.json
文件用来对微信小程序进行全局配置,决定页面文件的路径、窗口表现、设置网络超时时间、设置多 tab 等。完整配置项说明请参考小程序全局配置
以下是一个包含了部分常用配置选项的 app.json
:
{
"pages": [
"pages/index/index",
"pages/logs/index"
],
"window": {
"navigationBarTitleText": "Demo"
},
"tabBar": {
"list": [{
"pagePath": "pages/index/index",
"text": "首页"
}, {
"pagePath": "pages/logs/index",
"text": "日志"
}]
},
"networkTimeout": {
"request": 10000,
"downloadFile": 10000
},
"debug": true
}
其中 list 接受一个数组,只能配置最少 2 个、最多 5 个 tab。tab 按数组的顺序排序,每个项都是一个对象,其属性值如下:
属性 | 类型 | 必填 | 说明 |
---|---|---|---|
pagePath | string | 是 | 页面路径,必须在 pages 中先定义 |
text | string | 是 | tab 上按钮文字 |
iconPath | string | 否 | 图片路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px,不支持网络图片。 当 position 为 top 时,不显示 icon。 |
selectedIconPath | string | 否 | 选中时的图片路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px,不支持网络图片。 当 position 为 top 时,不显示 icon。 |
每一个小程序页面也可以使用同名 .json
文件来对本页面的窗口表现进行配置,页面中配置项会覆盖 app.json
的 window
中相同的配置项。完整配置项说明请参考小程序页面配置
{
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"navigationBarTitleText": "微信接口功能演示", // 页面导航标题
"backgroundColor": "#eeeeee",
"backgroundTextStyle": "light"
"enablePullDownRefresh":true, // 上拉刷新,开启后onPullDownRefresh才有效
"backgroundTextStyle": "dark", // 上拉刷新的等待图标
"usingComponents": { // 引入组件
...
}
}
属性 | 类型 | 默认值 | 必填 | 说明 | 最低版本 |
---|---|---|---|---|---|
1.onLaunch | function | 否 | 生命周期回调——监听小程序初始化。 | ||
2.onShow | function | 否 | 生命周期回调——监听小程序启动或切前台。 | ||
3.onHide | function | 否 | 生命周期回调——监听小程序切后台。 | ||
onError | function | 否 | 错误监听函数。 | ||
onPageNotFound | function | 否 | 页面不存在监听函数。 | 1.9.90 | |
onUnhandledRejection | function | 否 | 未处理的 Promise 拒绝事件监听函数。 | 2.10.0 | |
onThemeChange | function | 否 | 监听系统主题变化 | 2.11.0 | |
其他 | any | 否 | 开发者可以添加任意的函数或数据变量到 Object 参数中,用 this 可以访问 |
// app.js
App({
/* 1.监听小程序的初始化 */
// 获取用户信息
onLaunch(){
console.log("onLaunch")
},
/* 2.监听小程序启动或者切换前台 */
// 对页面的数据和效果进行重置
onShow(){
console.log("onShow")
},
/* 3.监听小程序切后台 */
// 清除定时器
onHide(){
console.log("onHide")
},
/* 错误监听函数 */
// 收集错误,通过异步请求发送服务器
onError(e){
console.log(e)
},
/*
* 页面不存在监听函数
* 启动时的入口文件不存在时才触发
* 一般多用于扫码进入页面时的处理
*/
onPageNotFound(){
// 当页面不存在的时候,进行重定向,跳转到存在的页面
console.log("onPageNotFound")
wx.navigateTo({
url: '/pages/page3/page3',
})
}
})
app.js中有一个 globalData, 可以用于放置全局变量或者常量。
在其它js文件中使用以下代码,获取数据。
const app = getApp(); const baseUrl = app.globalData.baseUrl;
注意:前台、后台定义: 当用户点击左上角关闭,或者按了设备 Home 键离开微信,小程序并没有直接销毁,而是进入了后台;当再次进入微信或再次打开小程序,又会从后台进入前台。只有当小程序进入后台一定时间,或者系统资源占用过高,才会被真正的销毁。
属性 | 类型 | 说明 |
---|---|---|
data | Object | 页面的初始数据 |
1.onLoad(mounted) | function | 生命周期回调—监听页面加载 |
2.onReady | function | 生命周期回调—监听页面初次渲染完成 |
3.onShow | function | 生命周期回调—监听页面显示 |
4.onHide | function | 生命周期回调—监听页面隐藏 |
5.onUnload(unmounted) | function | 生命周期回调—监听页面卸载 |
6.onPullDownRefresh | function | 监听用户下拉动作 |
7.onReachBottom | function | 页面上拉触底事件的处理函数 |
8.onTabItemTap | function | 当前是 tab 页时,点击 tab 时触发 |
onShareAppMessage | function | 用户点击右上角转发 |
onShareTimeline | function | 用户点击右上角转发到朋友圈 |
onAddToFavorites | function | 用户点击右上角收藏 |
onPageScroll | function | 页面滚动触发事件的处理函数 |
onResize | function | 页面尺寸改变时触发,详见 响应显示区域变化 |
onSaveExitState | function | 页面销毁前保留状态回调 |
其他 | any | 开发者可以添加任意的函数或数据到 Object 参数中,在页面的函数中用 this 可以访问。这部分属性会在页面实例创建时进行一次深拷贝。 |
Page({
/* 页面的初始数据 */
data: {
},
/* 1.生命周期函数--监听页面加载 */
// 发送异步请求,初始化页面数据
// 一个页面只会调用一次。
// 接收页面参数 可以获取wx.navigateTo和wx.redirectTo及中的 query。
onLoad: function (options) {
console.log("onLoad")
},
/* 2.生命周期函数--监听页面初次渲染完成 */
onReady: function () {
console.log("onReady")
},
/* 3.生命周期函数--监听页面显示 */
// 每次打开页面都会调用一次。**tabBar切换无效
onShow: function () {
console.log("onShow")
},
/* 4.生命周期函数--监听页面隐藏 */
onHide: function () {
console.log("onHide")
},
/* 5.生命周期函数--监听页面卸载 */
// 当redirectTo或navigateBack的时候调用。 (navigateTo无效)
onUnload: function () {
console.log("onUnload")
},
/* 1.页面相关事件处理函数--监听用户下拉动作 */
onPullDownRefresh: function () {
console.log("onPullDownRefresh")
},
/* 2.页面上拉触底事件的处理函数 */
// 上拉加载数据
onReachBottom: function () {
console.log("onReachBottom")
},
/* 3.切换tab页 */
// 当前是 tab 页时,点击 tab 时触发
onTabItemTap: function () {
console.log("onReachBottom")
},
})
组件的生命周期,指的是组件自身的一些函数,这些函数在特殊的时间点或遇到一些特殊的框架事件时被自动触发。其中,最重要的生命周期是 created
attached
detached
,包含一个组件实例生命流程的最主要时间点。
created
生命周期被触发。此时,组件数据 this.data
就是在 Component
构造器中定义的数据 data
。 此时还不能调用 setData
。 通常情况下,这个生命周期只应该用于给组件 this
添加一些自定义属性字段。attached
生命周期被触发。此时, this.data
已被初始化为组件的当前值。这个生命周期很有用,绝大多数初始化工作可以在这个时机进行。detached
生命周期被触发。退出一个页面时,如果组件还在页面节点树中,则 detached
会被触发。1.组件的生命周期
生命周期 | 参数 | 描述 | 最低版本 |
---|---|---|---|
1.created | 无 | 在组件实例刚刚被创建时执行 | 1.6.3 |
2.attached (mounted) | 无 | 在组件实例进入页面节点树时执行 | 1.6.3 |
3.ready | 无 | 在组件在视图层布局完成后执行 | 1.6.3 |
4.moved(update) | 无 | 在组件实例被移动到节点树另一个位置时执行 | 1.6.3 |
5.detached (unmounted) | 无 | 在组件实例被从页面节点树移除时执行 | 1.6.3 |
error | Object Error |
每当组件方法抛出错误时执行 | 2.4.1 |
代码示例:
Component({
// 自小程序基础库版本 [2.2.3](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html) 起,组件的的生命周期也可以在 `lifetimes` 字段内进行声明(这是推荐的方式,其优先级最高)。
lifetimes: {
created: function() {
// 在组件实例进入创建节点树时执行
},
attached: function() {
// 在组件实例进入页面节点树时执行
},
ready: function() {
// 在组件实例进入创建节点树时执行
},
moved: function() {
// 在组件实例进入创建节点树时执行
},
detached: function() {
// 在组件实例被从页面节点树移除时执行
},
},
})
2.组件所在页面的生命周期
还有一些特殊的生命周期,它们并非与组件有很强的关联,但有时组件需要获知,以便组件内部处理。这样的生命周期称为“组件所在页面的生命周期”,在 pageLifetimes
定义段中定义。其中可用的生命周期包括:
生命周期 | 参数 | 描述 | 最低版本 |
---|---|---|---|
1.show | 无 | 组件所在的页面被展示时执行 | 2.2.3 |
2.hide | 无 | 组件所在的页面被隐藏时执行 | 2.2.3 |
resize | Object Size |
组件所在的页面尺寸变化时执行 | 2.4.0 |
代码示例:
Component({
pageLifetimes: {
show: function() {
// 页面被展示
},
hide: function() {
// 页面被隐藏
},
resize: function(size) {
// 页面尺寸变化
}
}
})
注意: 在标签中使用变量,必需使用双括号和引号共同作用,才能进行数据的绑定。
使用方式 和vue类似,都可以在双括号内使用变量,进行数据绑定。
双括号内可以进行三元运算、和算术运算, 组成新的数据, 但唯一不允许构造成对象使用
1.数据绑定
{{obj.age}}
{{ [msg,num] }}
2.表单数据的双向绑定
// vant组件中使用model进行绑定
使用方法也与vue相同, 但是需要添加wx的专属属性绑定和数据绑定
{{item}}
// wx:key 关键区分字段
索引:{{index}}
姓名:{{item.name}}
对象的key:{{key}}
对象的value:{{value}}
小程序是wx:elif,vue是v-else-if
wx:elif
和 wx:else
来添加一个 else 块:
<view wx:if="{{num == 1}}">{{ [msg,num] }}view>
<view wx:if="{{length > 5}}"> 1 view>
<view wx:elif="{{length > 2}}"> 2 view>
<view wx:else> 3 view>
1.创建模板
模板拥有自己的作用域,只能使用 data 传入的数据以及模板定义文件中定义的
模块。
{{index}}: {{msg}}
Time: {{time}}
2.引用模板
单数
复数
{{item}}
body
header
3.使用实例
bindtap, bindchange, bindinput 是原生 小程序的事件绑定
bind:click , bind:change, 是vant组件常用的事件绑定方式
catchtap 禁用事件冒泡,一般设置为中间层
<-- 监听点击事件-->
<-- 阻止冒泡事件-->
通过api获取当前页面对象,再使用select方法查找节点
警告:微信小程序,不是非常支持修改页面。所以,不建议获取页面文档,也无法做到浏览的复杂渲染的页面。因为这种基于数据绑定的应用,本身就脱离了页面的直接控制。
(1.selectorComponent方法
vant组件中的选择节点方法。
const checkbox = this.selectComponent(`.checkboxes-${index}`);
checkbox.toggle(); // 执行实例的方法
(2.SelectorQuery方法
let query = wx.createSelectorQuery()
query.select('#payTicketBtm').boundingClientRect().exec(function(res) {
console.log("rect",res[0].height)
//res就是 所有标签为payTicketBtm的元素的信息 的数组
})
获取input输入的值
使用 bindinput 绑定输入事件, 可以通过 事件中的事件参数 e.detail.value获取输入的值
使用bindtap绑定点击事件,
点击按钮执行求和
改变data中的属性,相当于改变组件中的状态。需要使用this.setData({count:11})
处理事件的函数不能传参
要通过组件属性的形式 data- 和 e.currentTarget.dataset.name
// react中是setState, 小程序是setData, 类似react中的组件状态, this.setState
// vue,react中是target.value, 小程序是detail.value
// vue是this.xx 小程序是this.data.xx
--page4.js文件
...
/**
* 页面的初始数据
*/
data: {
count:0,
inputValue:''
},
// 处理事件函数
handleInput(e){
console.log(e, e.detail.value)
this.setData({
inputValue:e.detail.value
})
},
// 处理点击进行求和
handleClick(e){
this.setData({
count: this.data.inputValue + 1
})
},
// 处理事件传参
handleParams(e){
console.log("传入的参数是", e)
},
...
----page4.wxml文件
求和的结果是:{{count}}
微信小程序的冒泡事件
1.基本方法catchtap
// 添加一个中间层,捕获冒泡事件
xxxx
// 捕获事件冒泡,防止向父层扩散
handleStopPropagation(){
// 不执行任何数据
},
2.vant组件的 catch修饰
// vant checkbox组件的默认切换事件, 使用catch修饰tap方法
scroll-view组件,常用于组件中内容的滚动监听。
我们只需要将滑动报错的标签上加上一个样式即可 touch-action: none;
touch-action :当你触摸并按住触摸目标时候,禁止或显示系统默认菜单。
touch-action取值有一下两种
none:系统默认菜单被禁用
default:系统默认菜单不被禁用
添加样式更改,将滑动报错的标签样式添加: touch-action: none;
或者设置全局公共样式: *{touch-action: none;}
var hello = function(str){
return 'hello' + str;
}
module.exports = {
hello:hello
}
{{tools.hello("Tom")}}
var age = 12;
module.exports = {
age:age
}
{{getAge.age}}
尺寸单位
设备 | rpx换算px (屏幕宽度/750) | px换算rpx (750/屏幕宽度) |
---|---|---|
iPhone5 | 1rpx = 0.42px | 1px = 2.34rpx |
iPhone6(建议) | 1rpx = 0.5px | 1px = 2rpx |
iPhone6 Plus | 1rpx = 0.552px | 1px = 1.81rpx |
使用方法
使用方法和网页一样,都可以使用class
引入css模块:
@import "./../comm.wxss";
内联样式:
style:静态的样式统一写到 class 中。style 接收动态的样式,在运行时会进行解析,请尽量避免将静态的样式写进 style 中,以免影响渲染速度
(1. 方法一
使用icon组件: 略
(2.方法二
使用icon标签属性,标签属性值在icon组件中查找,可以不需要添加组件
/*修改goods-icon组件中的icon标签属性*/
.van-icon.van-icon-star {
color:red;
}
vant支持原选择器的样式覆盖,但不支持更换其它选择器的样式覆盖
比如:在原选择器前添加一个(类、id选择器),则样式覆盖无效
此时可以考虑vant文档中是否有 给根节点添加类名的选项 + 把覆盖样式写在 app.css中,添加层级
--无效的样式
.page-item .van-loading__spinner.van-loading__spinner--spinner,.van-loading__dot
{
width: 60px!important;
height: 60px!important;
}
--有效的样式
.van-loading__spinner.van-loading__spinner--spinner,.van-loading__dot
{
width: 60px!important;
height: 60px!important;
}
// vant组件 可以使用 添加前缀**custom-**,给根节点添加类名。
page, view , swiper, text 微信小程序基础组件,都是作为标签使用, vant组件, 一般不使用组件名称作为选择器使用
**常用方式:**page + xxxx选择器, 可以极大地减少!important的使用。
page .address-item{
width:100rpx!important;
}
全局样式写在app.wxss里面,所有页面共享文件里的样式
- 根节点无法与普通节点共同作用,无法找到索引。
// 选择器无效的示例,找不到子节点
.submit-item .van-button {
height:160rpx;
}
// 选择器有效示例 , 找到具体的子节点
.submit-item van-button .van-button--normal{
height:160rpx;
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PV3tdTVB-1661414245340)(C:\Users\Icy-yun\AppData\Roaming\Typora\typora-user-images\image-20220212125130885.png)]
view组件, 代替div
视图容器组件
**text组件,**代替span
文本组件 hello
**image **图片组件
button表单组件
getUserInfo
block组件,是一个包装元素,只接受控制属性,也不会在页面中做任何渲染。类似于template标签。
view1
view2
用户名:
密码:
性别:
男
女
爱好:
打篮球
乒乓球
羽毛球
用户名:{{username}}
密码:{{password}}
性别:{{sex}}
爱好:{{hobby}}
navigator组件,导航跳转
跳转page3
redirect 跳转page3
redirect 跳转index
redirect 跳转index
这个常用于当作跳转的路由方法。 也可以带参数使用。可以后退,相当于navigatorTo
onLoad: function (options) {
const {id} = options;
// 通过options获取跳转路由的参数
console.log("参数是",id)
},
swiper组件 ,轮播图展示
rich-text组件,解析html
page4.js文件
html_1:'hello
',
html_2:[
{
name:"p",
attrs:{
style:"color:red"
},
children:[
{
type:'text',
text:'hello'
}
]
}
scroll-view组件,常用于组件中内容的滚动监听。
web-view组件,在微信小程序中浏览网页
注意: 需要在微信开发者选项中添加允许访问的业务网站 的域名
微信小程序内嵌网页
定义一个components组件,在组件wxss中不应使用ID选择器、属性选择器和标签名选择器。
1.component组件
-- person.js文件
Component({
/* 组件的接收属性数据 */
properties: {
// 设置接收数据的类型
persons:{
type:Array,
value:[]
}
},
/* 组件的初始数据 */
data: {
title:"我是自定义组件",
msg:"我是子组件中的数据",
// persons:[
// {id:1,name:"Tom",age:10},
// {id:2,name:"mike",age:11},
// ]
},
/* 组件的方法列表 */
methods: {
handleClick(){
console.log("点击了自定义组件中的事件")
},
handleMsg(){
// 派发一个自定义事件, 相当于$emit
this.triggerEvent("getMsg",{msg:this.data.msg})
}
},
/*监听数据的变化*/
Observe:{
showPay: function(newShowPay) {
console.log("111111",newShowPay)
}
},
// 勾子函数,组件的生命周期
lifetimes: {
created: function() {
// 在组件实例进入创建节点树时执行
},
attached: function() {
// 在组件实例进入页面节点树时执行
},
ready: function() {
// 在组件实例进入创建节点树时执行
},
moved: function() {
// 在组件实例进入创建节点树时执行
},
detached: function() {
// 在组件实例被从页面节点树移除时执行
},
},
})
-- person.wxml文件
这里是组件的内部节点
{{title}}
姓名:{{item.name}}
年龄:{{item.age}}
2.page页面
---page.json文件引入组件
{
"usingComponents": {
"Persons":"../../components/Persons/Persons"
}
}
---page.wxml文件
Page5中使用自定义组件
这里的内容会显示在自定义组件中的slot占位
下面使用的方法与vue类似
this.triggerEvent("getMsg",{msg:this.data.msg})
派发一个自定义事件。triggerEvent很类似$emit注意:
vant组件中也可以直接使用wx:for ,等模板语法。(tab组件)。
vant组件的也有slot标签属性(goods-action组件)
把title标签属性的内容作为需要插入的数据 vant组件也可以不添加任何属性,直接在标签体内添加内容,即可成为插槽内容(cell单元格)
Component({
...
observers: {
// 监听单个数据
showPay: function(newShowPay) {
console.log("111111",newShowPay)
}
// 1. 监听多个数据
'numberA, numberB': function(numberA, numberB) {
// 在 numberA 或者 numberB 被设置时,执行这个函数
this.setData({
sum: numberA + numberB
})
},
// 2.监听对象的子数据
'some.subfield': function(subfield) {
// 使用 setData 设置 this.data.some.subfield 时触发
// (除此以外,使用 setData 设置 this.data.some 也会触发)
subfield === this.data.some.subfield
},
// 3.监听列表的子数据
'arr[12]': function(arr12) {
// 使用 setData 设置 this.data.arr[12] 时触发
// (除此以外,使用 setData 设置 this.data.arr 也会触发)
arr12 === this.data.arr[12]
},
// 4.监听所有子数据的变化, 使用双通配符 “**”
'some.field.**': function(field) {
// 使用 setData 设置 this.data.some.field 本身或其下任何子数据字段时触发
// (除此以外,使用 setData 设置 this.data.some 也会触发)
field === this.data.some.field
},
}
...
})
(1. 路由跳转的参数都是串行形式, navigator组件和wx.路由api的效果相同。
(2.网络请求的参数,可以为串行和请求体两种形式
(1.跳转api
保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。使用 wx.navigateBack 可以返回到原页面。小程序中页面栈最多十层。
”关闭当前页面“,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面
// wx.redirectTo({
// url: '/pages/page5/page5',
// })
”关闭所有页面“,打开到应用内的某个页面, 允许跳转到tabbar页面
一般 用于扫码跳转主页面
// wx.reLaunch({
// url: '/pages/page2/page2',
// })
从tab页面,跳转其它 ”所有“ 页面
// wx.navigateTo({
// url: '/pages/page5/page5',
// })
”关闭其他所有非 tabBar 页面“, 允许跳转到 tabBar 页面
// wx.switchTab({
// url: '/pages/page2/page2',
// })
关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages 获取当前的页面栈,决定需要返回几层。
// wx.navigateBack({
// delta: 0,
// })
(2.获取当前页面
getCurrentPages()
函数用于获取当前页面栈的实例,以数组形式按栈的顺序给出,第一个元素为首页,最后一个元素为当前页面。
let pages = getCurrentPages();
let currPage = null;
if (pages.length) {
currPage = pages[pages.length - 1];
}
console.log(currPage.route)
显示消息提示框
wx.showToast({
title: '成功',
icon: 'success',
duration: 2000
})
// 隐藏提示框, 一般与showToast配对使用
setTimeout(()=>{
wx.hideToast( )
},1000)
显示 loading 提示框。需主动调用 wx.hideLoading 才能关闭提示框
wx.showLoading({
title: '加载中',
})
setTimeout(function () {
wx.hideLoading()
}, 2000)
显示模态对话框
wx.showModal({
title: '提示',
content: '这是一个模态弹窗',
success (res) {
if (res.confirm) {
console.log('用户点击确定')
} else if (res.cancel) {
console.log('用户点击取消')
}
}
})
请求数据
注意:get请求的参数,可以写在data上, 可以串行和请求体的方式
vue是有data和params的区分
const requestTask= wx.request({
url: 'https://api.shop.eduwork.cn/api/index', //仅为示例,并非真实的接口地址
method:'get',
data:{
title:'java',
sort:'price'
},
success (res) {
if(res.statusCode == 200){
console.log(res.data)
}
}
})
中断请求
// requestTask.abort();
监听 HTTP Response Header 事件。会比请求完成事件更早
requestTask.onHeadersReceived(()=>{
console.log("onHeadersReceived")
})
异步存储
// 异步存储数据
wx.setStorage({
key:"key",
data:"value"
})
// 异步获取缓存中的数据
wx.getStorage({
key: 'key',
success (res) {
console.log(res.data)
}
})
// 异步获取当前的缓存信息
wx.getStorageInfo({
success (res) {
console.log(res.keys)
console.log(res.currentSize)
console.log(res.limitSize)
}
})
// 异步移除本地缓存
wx.removeStorage({
key: 'key',
success (res) {
console.log(res)
}
})
// 异步清空本地缓存
wx.clearStorage({
success: (res) => {},
})
同步缓存
wx.setStorageSync('age', 12)
const res = wx.getStorageInfoSync( )
console.log( res.keys)
console.log( res.currentSize)
console.log( res.limitSize)
const age = wx.getStorageSync('age')
console.log(age)
wx.removeStorageSync('age')
wx.clearStorageSync()
区别:
- 调用异步api之后。不会等待执行结果,程序继续向下运行
- 调用同步api, 需要等待执行结果,程序暂停运行。
注意:
wx.login
调用接口获取登录凭证(code)。通过凭证进而换取用户登录态信息,包括用户在当前小程序的唯一标识(openid)、微信开放平台帐号下的唯一标识(unionid,若当前小程序已绑定到微信开放平台帐号)及本次登录的会话密钥(session_key)等。用户数据的加解密通讯需要依赖会话密钥完成
wx.getUserProfile(Object object)
获取用户信息。页面产生点击事件(例如 button
上 bindtap
的回调中)后才可调用,每次请求都会弹出授权窗口,用户同意后返回 userInfo
。该接口用于替换 wx.getUserInfo
wx.getClipboardData和 wx.setClipboardData
js中:
// 点击复制openid
textPaste(e){
wx.setClipboardData({
data: e.currentTarget.dataset.openid,
success (res) {
wx.getClipboardData({
success (res) {
console.log(res.data) // data
}
})
}
})
},
wxml中:
{{userObj.openid}}
wx.previewImage 图片预览
// 点击自定义预览层
handleSelfPreview(e){
const url = e.currentTarget.dataset.preview
wx.previewImage({
current:url, // 当前显示图片的http链接
urls:[url] // 需要预览的图片http链接列表
})
},
wx.startPullDownRefresh 和 wx.stopPullDownRefresh 上拉刷新
console.log("下拉刷新")
wx.startPullDownRefresh({
success:function(){
console.log("刷新成功")
}
})
wx.stopPullDownRefresh({
success:function(){
console.log("刷新结束")
}
})
openid和unionid
openid:微信用户相对于不同的公众号,不同的小程序,都有唯一的用户标识,,这个标识就是openid,在同一个公众号或者同一个小程序中,微信用户的openid是唯一的,即每个微信用户的openid是不同的
unionid;微信开放平台帐号下的唯一标识,只有公众号或者小程序绑定到微信开放平台帐号才能获取到unionid,同一个微信用户,在同一个开放平台unionid是惟一的,用做在不同的公众号或者不同的小程序中,识别同一个用户
wx.getUserProfile和wx.login
wx.getUserProfile:获取用户信息。页面产生点击事件(例如 button上 bindtap的回调中)后才可调用,每次请求都会弹出授权窗口,用户同意后返回userlnfo.
wx.login:调用接口获取**登录凭证(code)
。通过凭证进而换取用户登录态信息,包括用户在当前小程序的唯一标识(openid)
**、微信开放平台帐号下的唯一标识(unionid,若当前小程序已绑定到微信开放平台帐号〉及本次登录的会话密钥(session_key)等。
**相同点:**最终的目的都是拿到openid,用于查询数据中的用户信息
**区别:**getUserProfile需要用户操作,不可控制。
wx.login可以实现自动获取openid
总结:
1.前台发起请求:(warning)
App({
onLaunch() {
// 登录
wx.login({
success (res) {
if (res.code) {
//发起网络请求
wx.request({
url: 'https://api.weixin.qq.com/sns/jscode2session',
// 注意,不要以明文的形式, 请求用户数据。
// app.js获取不到封装页面的request文件
data: {
appid:'你自己的appid',
secret:'你自己的secret',
js_code:res.code,
grant_type:'authorization_code'
}
})
} else {
console.log('登录失败!' + res.errMsg)
}
}
})
},
globalData: {
userInfo: null,
baseUrl:'https://api.shop.eduwork.cn'
}
})
2.后台连接微信服务器(建议)
》》 当前小程序
》》appid , 你自己的appid
》》 secret, 你自己的secret
// app.js
App({
onLaunch() {
// 登录
wx.login({
success :(res)=>{
if (res.code) {
//发起网络请求, wx.login获取的code, 然后通过code获取小程序的Openid和用户信息.
// data里面的appid是当前的小程序的身份标识
wx.request({
url: this.globalData.baseUrl+'/api/auth/wx/code',
method:'POST',
data:{
appid:'你自己的appid',
secret:'你自己的secret',
js_code:res.code
},
success(res2){
// 如果当前微信没有绑定过,只能返回openid,缓存openid,用于后续操作。
wx.setStorageSync('openid', res2.data.openid)
// 如果绑定过,会返回access_token和用户信息,缓存access_token和用户信息
// 而小程序是否登录和是否有access_token是直接关系。
if(res2.data.access_token != ''){
wx.setStorageSync("access_token",res2.data.access_token)
wx.setStorageSync("userinfo",res2.data.user)
}
}
})
} else {
console.log('登录失败!' + res.errMsg)
}
}
})
},
globalData: {
userInfo: null,
baseUrl:'https://api.shop.eduwork.cn'
}
})
3.混乱secret密钥
// 检测当前的页面
export const getAlter_sec = ()=>{
return getAlter_C(getAlter_B(getAlter_A()))
}
// 1.混乱的短字段
export const getAlter_A = ()=>{
// 目标数据 a4f eaca b e4e4 67 f26d 8c8d a1eb22 e7 01
const _a = 'a4f a1eb22' // 1 8
const _b = 'b 67' // 3 5
const _c = 'eaca 8c8d 01' // 2 7 10
const _d = ''
const _e = 'e4e4 e7' // 4 9
const _f = 'f26d' // 6
const arr = [1,8,3,5,2,7,10,0,4,9,6]
const alpha = ['a','b','c','d','e','f']
let getA = Array.from('1234567890');
let _turn = -1
arr.forEach((item)=>{
if(item != 0) {
_turn += 1
let t_alpha = [];
alpha.forEach(subItem=>{
var t = 0;
switch(subItem){
case 'a':
t = _a;
break;
case 'b':
t = _b;
break;
case 'c':
t = _c;
break;
case 'd':
t = _d;
break;
case 'e':
t = _e;
break;
case 'f':
t = _f;
break;
}
if(t.length){
t_alpha = [...t_alpha,...t.split(' ')]
}
})
getA.splice(item-1,1, t_alpha[_turn])
}
})
return getA
}
// 2.混乱的短字段2
export const getAlter_B = (newArr)=>{
// 目标数据 67 01 a4f eaca b e4e4 f26d 8c8d a1eb22 e7
// 传递的数据 a4f eaca b e4e4 67 f26d 8c8d a1eb22 e7 01
let arr = Array.from('2345067891');
let getB = Array.from('1234567890');
arr.forEach((item,index)=>{
getB.splice(item,1,newArr[index])
})
return getB
}
// 3.调整顺序,拼接,
export const getAlter_C = (newArr)=>{
// 传入四个字符
const _a = newArr[0]
const _b = newArr[1]
let prefix = _a[0]+_b+_a[1]
return prefix + newArr.slice(2).join('');
}
export const getAlter_appid = () =>{
const _a = 'wx4cfa'
const _c = 'd132eb'
const _b = '9ca05f'
return _a + _b + _c
}
module.exports = {
getAlter_sec,getAlter_appid
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BittewZQ-1661414245342)(C:\Users\Icy-yun\AppData\Roaming\Typora\typora-user-images\image-20220210141956427.png)]
前端js上传图片、文件到阿里云OSS
阿里云简单oss上传
微信小程序与oss直传
vant组件的upload上传(主要参考文章)
// 提交修改头像
handleConfirm(){
var tempFilePath = this.data.updateAvatarList[0].url // 监听url数据,并非data数据流
// 只有更换才会显示发起请求的数据。
if(!tempFilePath.startsWith("http://tmp/")){
wx.showToast({
title: '头像没有变化',
icon:'error',
duration:1500
})
return;
}
this.getOssKey();
},
// 1.首先通过后端api返回一个oss接口信息
getOssKey(){
ossPicKey().then(res=>{
console.log("返回的结果是",res)
this.setData({
ossKey:res
})
this.handleOss();
})
},
// 2.通过组件将oss转换成在线的图片链接
handleOss(){
console.log("处理在线的链接",this.data.ossKey)
//上传的文件信息, 临时的url才有效,已经存在的在线链接,则无效。
var tempFileDataUrl = this.data.updateAvatarList[0].url // 监听url数据,并非data数据流
var prefixUrl = this.data.ossKey.host; // 图片链接前缀
var filename = Date.now() + 'aaa.png' // 文件名称
var filepath = `BoardShopping/${filename}` // 文件路径 (含文件名称)
wx.uploadFile({
// 目标url "https://laravel-book-shop.oss-cn-beijing.aliyuncs.com/",
url: prefixUrl, // 图片链接前缀
filePath: tempFileDataUrl, // 临时url文件
name: 'file', // 文件类型,(图片也可以是file类型)
// 获取oss数据, 必须是后端已经注册的用户
formData: {
name: tempFileDataUrl, // 临时url文件
key: filepath, // 文件路径(含文件名称)
policy: this.data.ossKey.policy, // plicy政策
OSSAccessKeyId: this.data.ossKey.accessid, // osss访问id
success_action_status: "200", // 成功的状态码
signature: this.data.ossKey.signature, // 签名验证
},
success: (res)=>{
const status = `${res.statusCode}`
if(!status.startsWith("2")){
console.log('请求错误1: ', res)
wx.showToast({
title: "上传失败",
icon: 'error',
duration: 1500
})
}else{
// 完成的图片连接
const newLink = prefixUrl + filepath ;
console.log("获取的url链接",newLink)
// 因为是回调函数, 所以并不能在回调函数中获取页面定义的方法,但箭头函数可以在上级查找data数据
this.handleAvatar(newLink);
}
},
fail:(err)=>{
console.log('请求失败2: ', err.errMsg)
wx.showToast({
title: "上传失败",
icon:'error',
duration: 1500
})
},
})
},
// 3.然后将在线图片链接上传到当前帐号
handleAvatar(newLink){
// const newAvatar = 'https://cdn.jsdelivr.net/gh/JackKetty/PicGoCDN/pic/202201051114294.jpg'
const newAvatar = newLink;
const data = {
avatar:newAvatar
}
updateAvatar(data).then(res=>{
wx.showToast({
title: '更换头像成功',
icon:'success',
duration:1500
})
this.setData({
userObj:{
...this.data.userObj,
avatar_url:newAvatar
},
preAvatar:newAvatar,
updateAvatarList:[
{...this.data.updateAvatarList[0],url:newAvatar}
]
})
this.handleChangeAvatar()
})
},
1.使用沙箱支付宝
首先需要使用个人真实支付宝帐号申请一个沙箱帐号,里面包含 商家 和 用户 测试帐号
然后下载沙箱支付宝,使用 沙箱支付宝帐号登录,支付余额可以在 注册的支付宝帐号里面配置(真实)。
支付宝沙箱支付帐号
2.可以查看一下沙箱支付宝处理的流程(配置沙箱环境)
选择支付宝的 研发服务选项, 配置密钥/证书(公钥)
然后配置应用网关,用于接收支付宝沙箱环境的通知
(自己的服务器)服务端配置 支付宝网关地址 、APPID、签名方式
然后配置授权回调地址
沙箱支付环境
1.基础路径
app.wxss文件
@import '/miniprogram_npm/@vant/weapp/common/index.wxss';
app.json文件
url= "pages/homePage/cart/cart" // navigator跳转路径
"iconPath": "/assets/icons/home.png", // assets路径
"pagePath": "pages/homePage/cart/cart", // tabBar路径
"pages":[ // 页面路径
"pages/homePage/index/index",
]
js文件
import {deleteAddress,defaultAddress,addresslist} from '../../../service/address'
import Notify from '../../../miniprogram_npm/@vant/weapp/notify/notify';
json文件(可以在npm构建包中直接找到)
"van-empty": "@vant/weapp/empty/index"
注意:npm构建是将npm包中的组件打包成一个miniprogram_npm 的构建组件。 可以在json文件中直接被找到
2.getapp()方法
Commonjs 语法下的模块引入
将引入的路径,切换到当前路径,使用了变量的形式。
App({
require: ($uri) => require($uri),
})
const app = getApp()
const {data} = app.require('model/test.js')
Es6 语法下的模块引入 (不建议使用)
在app.js文件中声明具体模块,并结合getApp方法获取对应的属性,然后在引入的位置执行函数,获取模块对象。
App({
alias:{
'service':()=>require("service/address")
},
})
const app = getApp();
const {deleteAddress,defaultAddress,addresslist} = app.alias.service( );
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ay4NmrzP-1661414245342)(C:\Users\Icy-yun\AppData\Roaming\Typora\typora-user-images\image-20220203001649152.png)]
3.发布小程序,在微信开发者工具中点击上传,将当前开发版本上传到 微信开发者平台上。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qdjOzGHQ-1661414245344)(C:\Users\Icy-yun\AppData\Roaming\Typora\typora-user-images\image-20220203002638010.png)]
注意:如果出现 小程序真机调试遇到VM13:2 Unhandled promise rejection 90001
生命周期:
组件机制:
vue组件机制,父子之间传递数据,以及使用插槽添加额外的子数据。
微信小程序只有组件和vue类似, property 属性是继承属性, data 是数据源, methods是方法集合。 使用组件的页面可以通过标签属性传递数据, 而组件可以通过 this.triggerEvent派发一个自定义事件,页面通过 onxxxx = “xxx” 接收组件传递数据。使用方法和vue的$emit类似。
同时,可以在组件内定义slot标签,作为插槽的数据。
微信小程序的pages页面也有data数据, 通常使用 this.data.xxx获取指定数据。
pages页面
vue是通过组件的拼接形成的页面。
微信小程序也可以使用组件,但每个页面都有特定的标识。并且,page页面中的js数据源,内部其实是一个类,访问属性与方法是通过this.xxx 或者 this.data.xxx获取。
并且,vue可以直接对data中的属性进行访问,而微信小程序有react中的状态机制,只有通过
this.setData({ a: xxx}) 改变数据。即使结果相同,但是实现的方式不一样。
模块语法
vue采用简洁明了的方式,将数据与标签属性值 ,文本内容绑定。 列表循环,数据绑定,事件绑定, 条件渲染。
微信小程序采用的方法很类似vue,但却不一样。
事件绑定: 按钮采用 bindtab 表示绑定点击事件, 其余的事件采用 bindxxx, 事件名称小写的习惯进行事件绑定。
列表循环, vue采用 v-for=“item in goods” :key=“item.id” 的方式; 微信小程序采用 wx:for = “{{goods}}” wx:key=“id” wx:for-item = “item” wx:for-index = “id” 的方式。
数据绑定, 微信小程序采用 数据绑定wx:xxxx = “{{ xxx}}” , 插值{{xxxx}}
有点类似vue与react的数据绑定的结合。
条件渲染: vue采用的是v-if 和v-show ,控制节点的显示;微信小程序采用wx:if , wx:elif , wx:else 和 hidden 控制节点的显示。使用方法相同。