前言:
- 微信小程序开发框架的目标是通过尽可能简单,高效的方式让开发者可以在微信中开发具有原生APP体验的服务。
- 整个小程序框架系统分为两部分,逻辑层,视图层,小程序提供了自己的视图层描述语言,
WXML
和Wxss
,以及基于javascript的逻辑层框架, 并在视图层与逻辑层间提供了数据传输和事件系统,让开发者能够专注于数据与逻辑。
优点:
-
微信用户量大,开发门槛低,推广成本低,跨平台,无需安装。
-
微信小程序开发门槛低,可以实现消息通知,线下扫码,公众号关联等七大功能
-
同类型的小程序: 支付宝小程序,qq小程序。
微信小程序APP(ID): xxxxx
1.配置环境
1.应用配置
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。 |
2.页面配置
每一个小程序页面也可以使用同名 .json
文件来对本页面的窗口表现进行配置,页面中配置项会覆盖 app.json
的 window
中相同的配置项。完整配置项说明请参考小程序页面配置
{
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"navigationBarTitleText": "微信接口功能演示", // 页面导航标题
"backgroundColor": "#eeeeee",
"backgroundTextStyle": "light"
"enablePullDownRefresh":true, // 上拉刷新,开启后onPullDownRefresh才有效
"backgroundTextStyle": "dark", // 上拉刷新的等待图标
"usingComponents": { // 引入组件
...
}
}
2.小程序生命周期
1.应用级生命周期
属性 | 类型 | 默认值 | 必填 | 说明 | 最低版本 |
---|---|---|---|---|---|
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;
2.页面级生命周期
注意:前台、后台定义: 当用户点击左上角关闭,或者按了设备 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")
},
})
3.组件生命周期
组件的生命周期,指的是组件自身的一些函数,这些函数在特殊的时间点或遇到一些特殊的框架事件时被自动触发。其中,最重要的生命周期是 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) {
// 页面尺寸变化
}
}
})
3.wxml的使用
1."{{ }}"数据绑定
注意: 在标签中使用变量,必需使用双括号和引号共同作用,才能进行数据的绑定。
使用方式 和vue类似,都可以在双括号内使用变量,进行数据绑定。
双括号内可以进行三元运算、和算术运算, 组成新的数据, 但唯一不允许构造成对象使用
1.数据绑定
<!-- 在标签中的属性使用变量,需要双括号和引号共同使用 -->
<view data-msg="{{msg}}">{{obj.age}}</view>
<view wx:if="{{num == 1}}">{{ [msg,num] }}</view>
2.表单数据的双向绑定
// vant组件中使用model进行绑定
<van-cell-group>
<van-field model:value="{{ value }}"
placeholder="请输入用户名" border="{{ false }}" />
</van-cell-group>
2.wx:for列表循环
使用方法也与vue相同, 但是需要添加wx的专属属性绑定和数据绑定
<!-- 1.简写模式 -->
<view wx:for="{{arr}}" wx:key="*this">{{item}}</view>
<!-- 2.完整模式 -->
<!-- (1.遍历数组 -->
<!-- 默认列表项是item,索引是index, 可以省略 -->
<view wx:for="{{persons}}"
wx:for-item="item" // wx:for-item是默认的
wx:for-index="index" // wx:for-index是默认的
wx:key="id"> // wx:key 关键区分字段
<view>索引:{{index}}</view>
<view>姓名:{{item.name}}</view>
</view>
<!-- (2.遍历对象 -->
<view wx:for="{{obj}}"
wx:key="*this" // *this表示当前的item数据项
wx:for-item="value"
wx:for-index="key" >
<view>对象的key:{{key}} </view>
<view>对象的value:{{value}} </view>
</view>
3.wx:if条件渲染
小程序是wx:elif,vue是v-else-if
- wx:if是惰性的,hidden是活动的。
- hidden就类似于v-show,它始终会被渲染,只是简单的控制显示与隐藏
- wx:if是惰性的,如果在初始渲染条件为false,则不会有任何变化。如果条件为真,则才会开始局部渲染。
- 也可以用
wx:elif
和wx:else
来添加一个 else 块:
<!-- if条件判断 -->
<view wx:if="{{num == 1}}">{{ [msg,num] }}</view>
<!-- if..elif..条件判断 -->
<view wx:if="{{length > 5}}"> 1 </view>
<view wx:elif="{{length > 2}}"> 2 </view>
<view wx:else> 3 </view>
<!-- wx:for列表渲染 -->
4.wx模板和引用
1.创建模板
模板拥有自己的作用域,只能使用 data 传入的数据以及模板定义文件中定义的 <wxs />
模块。
- 方法一:组件内定义模板
- 方法二:组件外定义模板,使用import导入 wxml文件。 (使用方法比组件更简单)
<!-- 定义模板 -->
<template name="msgItem">
<view>
<text> {{index}}: {{msg}} </text>
<text> Time: {{time}} </text>
</view>
</template>
<!-- 使用模板 -->
<template is="msgItem" data="{{...item}}"/>
<template is="msgItem" data="{{index:item.index, msg:item.msg, time:item.time}}"/>
2.引用模板
- import方式: 可以在文件中使用目标文件定义的template
<!-- item.wxml -->
<template name="odd">
<text> 单数</text>
</template>
<template name="even">
<text> 复数</text>
</template>
<!-- 引入模板 -->
<import src="item.wxml"/>
<block wx:for="{{[1,2,3,4,5]}}" wx:key="*this">
<text>{{item}}</text>
<template is="{{item % 2 == 0 ? 'even' : 'odd'}}" />
</block>
- include可以将目标文件除了 外的整个代码引入,相当于拷贝代码
<!-- index.wxml -->
<include src="header.wxml"/>
<view> body </view>
<include src="footer.wxml"/>
<!-- header.wxml -->
<view> header </view>
3.使用实例
<!--pages/components/load/load.wxml-->
<!-- 加载模板, 1.组件内模板,2.组件外模板, -->
<!-- 作用:可以有效因页面加载缓慢,而导致的空数据 -->
<template name="loadMask">
<view wx:if="{{judge}}" class="mask"></view>
</template>
<!-- 使用方法 -->
<!-- 1.组件内模板 -->
<!--
<template name="loadMask">
<view wx:if="{{judge}}" class="mask"></view>
</template>
-->
<!-- 2.import导入模板, 引入wxss无效,需要组件内自定义 -->
<!--
<import src="../components/load/load.wxml"/>
<template is="loadMask" data="{{judge:!like_goods.length}}"/>
-->
<!--2.1 wxss 样式
.mask{
width: 100vw;
height: 100vh;
}
-->
5.bind事件绑定
-
bindtap, bindchange, bindinput 是原生 小程序的事件绑定
-
bind:click , bind:change, 是vant组件常用的事件绑定方式
-
catchtap 禁用事件冒泡,一般设置为中间层
<-- 监听点击事件-->
<view bind:tap="onHandleClick()"> </view>
<-- 阻止冒泡事件-->
<view catchtp >
<view bind:tap="onHandleClick()"> </view>
</view>
6.获取文档节点(略)
通过api获取当前页面对象,再使用select方法查找节点
警告:微信小程序,不是非常支持修改页面。所以,不建议获取页面文档,也无法做到浏览的复杂渲染的页面。因为这种基于数据绑定的应用,本身就脱离了页面的直接控制。
(1.selectorComponent方法
vant组件中的选择节点方法。
const checkbox = this.selectComponent(`.checkboxes-${index}`);
checkbox.toggle(); // 执行实例的方法
(2.SelectorQuery方法
- SelectorQuery.in (对应的组件)
- 将选择器的选取范围更改为自定义组件 component 内
- 初始时,选择器仅选取页面范围的节点,不会选取任何自定义组件中的节点
- SelectorQuery.select(string selector)
- 在当前页面下选择第一个匹配选择器 selector 的节点
- SelectorQuery.selectAll()
- 在当前页面下选择匹配选择器 selector 的所有节点。
- SelectorQuery.selectViewport()
- 选择显示区域
- 用于获取显示区域的尺寸、滚动位置等信息
- SelectorQuery.exec(function callback)
- 执行所有的请求
- 请求结果按请求次序构成数组,在callback的第一个参数中返回
let query = wx.createSelectorQuery()
query.select('#payTicketBtm').boundingClientRect().exec(function(res) {
console.log("rect",res[0].height)
//res就是 所有标签为payTicketBtm的元素的信息 的数组
})
4.js数据源的使用
1.函数传值
-
获取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文件
<input bindinput="handleInput" style="border:1px solid red"/>
<button bindtap="handleClick">点我加一</button>
<view>求和的结果是:{{count}}</view>
<button bindtap="handleParams" data-name="Tome">点我传参</button>
2.阻止冒泡事件
- 微信小程序的事件,并非是浏览器的事件,所以不能使用event.stopPropagation阻止 事件冒泡
- 使用 捕获事件的方式阻止冒泡向外扩散
- vant组件采用catch:tap 禁用默认的事件。
1.基本方法catchtap
// 添加一个中间层,捕获冒泡事件
<view catchtap="handleStopPropagation">
<view bind:change="xxx">xxxx</view>
</view>
// 捕获事件冒泡,防止向父层扩散
handleStopPropagation(){
// 不执行任何数据
},
2.vant组件的 catch修饰
// vant checkbox组件的默认切换事件, 使用catch修饰tap方法
<view class=" check-item" data-check="{{item.id}}" bindtap="handleCheck" >
<van-checkbox name="{{item.id}}" class="checkboxes-{{ item.id }}" catch:tap="handleStopPropagation"/>
</view>
3.滚动事件监听
-
scroll-view组件,常用于组件中内容的滚动监听。
-
我们只需要将滑动报错的标签上加上一个样式即可 touch-action: none;
touch-action :当你触摸并按住触摸目标时候,禁止或显示系统默认菜单。
touch-action取值有一下两种
none:系统默认菜单被禁用
default:系统默认菜单不被禁用 -
添加样式更改,将滑动报错的标签样式添加: touch-action: none;
或者设置全局公共样式: *{touch-action: none;}
4.空白加载处理
- 可以使用wx:if + 加载数据标记判断数据
- 可以使用hidden + 延迟显示标记方式
- 添加占位空白页面 + 加载数据标记判断数据
5.wxs公有模块
var hello = function(str){
return 'hello' + str;
}
module.exports = {
hello:hello
}
<!-- 使用wxs -->
<!-- 方法一:引入wxs文件,并重命名模块 -->
<wxs src="./../comm.wxs" module="tools"/>
<view>{{tools.hello("Tom")}}</view>
<!--方法二:直接在当前文件定义模块 -->
<wxs module="getAge">
var age = 12;
module.exports = {
age:age
}
</wxs>
<view >{{getAge.age}}</view>
5.wxss样式的使用
尺寸单位
- rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
设备 | 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";
-
内联样式:
<!--动态样式--> <view style="color:{{color}};" />
-
style:静态的样式统一写到 class 中。style 接收动态的样式,在运行时会进行解析,请尽量避免将静态的样式写进 style 中,以免影响渲染速度
1.vant的icon图标
(1. 方法一
使用icon组件: 略
(2.方法二
使用icon标签属性,标签属性值在icon组件中查找,可以不需要添加组件
- 一般线框风格是 xxx-o, 实底风格是xxx
/*修改goods-icon组件中的icon标签属性*/
.van-icon.van-icon-star {
color:red;
}
2.vant样式的覆盖
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-**,给根节点添加类名。
<view class="page-item">
<van-loading type="spinner" custom-class="inner-spinner"/>
</view>
3.普通样式覆盖
-
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)]
6.视图容器(组件)
1.view基础组件
-
view组件, 代替div
-
<view hover-class="bg-red">视图容器组件</view>
-
**text组件,**代替span
-
<text user-select decode>文本组件 hello</text>
-
**image **图片组件
- mode属性可以设置图片的裁剪方式
scaleToFill默认, 宽高拉伸满,占满容器
aspectFit长边拉伸满, 短边自适应,常用
aspectFill短边拉伸满,长边会裁剪,不常用
widthFix 宽度100%,高度自适应,常用
- mode属性可以设置图片的裁剪方式
-
<image class="image" mode="aspectFill" src="https://res.wx.qq.com/wxdoc/dist/assets/img/0.4cb08bb4.jpg"></image>
-
button表单组件
- open-type按钮的开放能力
contact 打开微信客服,只能在正式appid的真机测试下运行
share转发朋友,不能发送朋友圈
getPhoneNumber 获取用户手机号,配合bindgetphonenumber事件来使用,返回的是一个加密的数据
getUserInfor 获取用户信息。小程序建议使用getUserProfile, 具有弹窗提示
launchApp 打开app, 只能加回跳到app
openSetting 打开授权设置页
feedback 打开意见反馈页面, 需要真机测试
- open-type按钮的开放能力
-
<button size="mini" type="primary" loading="{{true}}">按钮</button> <button open-type="contact">contact</button> <button open-type="share">share</button>getUserInfo <button open-type="getPhoneNumber" bindgetphonenumber="bindgetphonenumber">getPhoneNumber</button> <button open-type="getUserInfo" bindgetuserinfo="bindgetuserinfo">bindgetuserinfo</button> <button bindtap="getUserInfo" >获取用户信息</button> <button open-type="launchApp" >launchApp</button> <button open-type="openSetting" >打开授权页</button> <button open-type="feedback" >打开反馈页面</button>
-
block组件,是一个包装元素,只接受控制属性,也不会在页面中做任何渲染。类似于template标签。
-
<block wx:if="{{true}}"> <view> view1 </view> <view> view2 </view> </block>
2.input表单组件
- input组件
- radio组件 + radio-group
- checkbox组件 + checkbox-group
- form组件,
用户名:
<input placeholder="请输入用户名" bindinput="handleUsername"/>
密码:
<input placeholder="请输入密码" bindinput="handlePassword"/>
性别:
<radio-group bindchange="handleRadio">
<radio value="男"/>男
<radio value="女"/>女
</radio-group>
爱好:
<checkbox-group bindchange="handleHobby">
<checkbox value="打篮球" checked="{{true}}"/>打篮球
<checkbox value="乒乓球"/>乒乓球
<checkbox value="羽毛球"/>羽毛球
</checkbox-group>
<p>
<view>用户名:{{username}}</view>
<view>密码:{{password}}</view>
<view>性别:{{sex}}</view>
<view>爱好:{{hobby}}</view>
</p>
<button form-type="submit">提交 </button>
3.navigator高级组件
-
navigator组件,导航跳转
- target跳转目标,默认是当前小程序open-type跳转的方式
navigate默认,跳转之后,可以返回
redirect关闭当前页面,跳转之后不能返回
switchTab跳转到tabBar页面,并关闭其他所有非tabBar 页面, 设置为tabBar的页面专属
reLaunch 关闭所有页面,打开到应用内的某个页面
navigateBack关闭当前页面,返回上一页面
- target跳转目标,默认是当前小程序open-type跳转的方式
-
<navigator url="/pages/page3/page3" >跳转page3</navigator> <navigator url="/pages/page3/page3" open-type="redirect">redirect 跳转page3</navigator> <navigator url="/pages/index/index" open-type="switchTab">redirect 跳转index</navigator> <navigator url="/pages/index/index" open-type="reLaunch">redirect 跳转index</navigator>
-
这个常用于当作跳转的路由方法。 也可以带参数使用。可以后退,相当于navigatorTo
-
<navigator url="/pages/goods/goods?id={{itemm.id}}"> </navigator> onLoad: function (options) { const {id} = options; // 通过options获取跳转路由的参数 console.log("参数是",id) },
-
swiper组件 ,轮播图展示
- 1.swiper默认的宽高,宽100%, 高150px
2.images默认宽320px,高240px
3.让swiper的高通过使用的图片的宽高计算出来
s_height = s_width * i_height / i_width
height:calc(750rpx * 240 / 320 )
4.常用属性
autoplay自动播放
interval 指定播放间隔
indicator-dots 指示切换点
- 1.swiper默认的宽高,宽100%, 高150px
-
<swiper autoplay="{{true}}" indicator-dots> <swiper-item wx:for="{{images}}" wx:key="*this" wx:for-item="url"> <image src="{{url}}"/> </swiper-item> </swiper>
-
rich-text组件,解析html
-
page4.js文件 html_1:'<p style="background:red">hello</p>', html_2:[ { name:"p", attrs:{ style:"color:red" }, children:[ { type:'text', text:'hello' } ] }
-
<!-- 5.rich-text属性渲染html --> <rich-text nodes="{{html_1}}"></rich-text> <rich-text nodes="{{html_2}}"></rich-text>
-
scroll-view组件,常用于组件中内容的滚动监听。
-
<scroll-view scroll-y="true" style="height: 100%" bindscrolltolower="onScrollBottom" > </scroll-view>
-
web-view组件,在微信小程序中浏览网页
-
注意: 需要在微信开发者选项中添加允许访问的业务网站 的域名
-
<web-view src="https://www.xxxxxxxxx.com/index.html" />
-
7.components组件
1.创建组件
定义一个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文件
<view class="main">
<view>这里是组件的内部节点</view>
<slot></slot>
<view>{{title}}</view>
<view class="item" wx:for="{{persons}}" wx:key="id">
<view>姓名:{{item.name}}</view>
<view>年龄:{{item.age}}</view>
</view>
<button bindtap="handleClick">点击触发自定义组件中的事件</button>
<button bindtap="handleMsg">传递给父组件</button>
</view>
2.page页面
---page.json文件引入组件
{
"usingComponents": {
"Persons":"../../components/Persons/Persons"
}
}
---page.wxml文件
<view>Page5中使用自定义组件</view>
<Persons persons="{{persons}}" bindgetMsg="getMsg" >
这里的内容会显示在自定义组件中的slot占位
</Persons>
下面使用的方法与vue类似
2.property父传子
- page页面向组件传递数据,使用标签属性
- 子组件可以在properties 中设置传递的数据类型
- 子组件可以自由使用传递的数据
3.triggerEvent子传父
- 子组件在点击事件触发后,在methods选项中定义点击事件的方法,方法里面再使用
this.triggerEvent("getMsg",{msg:this.data.msg})
派发一个自定义事件。triggerEvent很类似$emit - 父组件绑定是子组件派发的自定义事件(bindgetMsg=“handleMsg”)
4.slot 插槽标签
- 在使用组件的位置,可以在内部定义slot内容
- 而组件可以设置slot标签 的位置
- 如果没有传递参数, 设置 default数据无效
注意:
vant组件中也可以直接使用wx:for ,等模板语法。(tab组件)。
vant组件的也有slot标签属性(goods-action组件)
<van-cell value="内容" > <view slot="title"> 把title标签属性的内容作为需要插入的数据 </view> </van-cell>
vant组件也可以不添加任何属性,直接在标签体内添加内容,即可成为插槽内容(cell单元格)
<van-cell title="设置为默认地址" > <van-switch checked="{{ checked }}" size="24px" /> </van-cell>
5.observe监听器
- 监听的数据,可以是不添加引号的键名。
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
},
}
...
})
8.常用API: wx.—
1.navigateTo路由跳转
(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)
2.showToast交互
-
显示消息提示框
-
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('用户点击取消') } } })
3.request网络请求
-
请求数据
-
注意: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") })
4.storage数据缓存
-
异步存储
-
// 异步存储数据 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, 需要等待执行结果,程序暂停运行。
注意:
- 微信小程序没有其它的缓存处理,所以一般使用同步缓存,并且storage可以不需要使用JSON.stringify处理,可以直接缓存对象。
- 用户信息,token, openid都是存放在storage中
- 微信小程序没有多线程和async,一般都是同步的。即使有如同react的组件状态,却依然是同步执行。
5.wx.-开放接口
-
wx.login
-
调用接口获取登录凭证(code)。通过凭证进而换取用户登录态信息,包括用户在当前小程序的唯一标识(openid)、微信开放平台帐号下的唯一标识(unionid,若当前小程序已绑定到微信开放平台帐号)及本次登录的会话密钥(session_key)等。用户数据的加解密通讯需要依赖会话密钥完成
-
wx.getUserProfile(Object object)
-
获取用户信息。页面产生点击事件(例如
button
上bindtap
的回调中)后才可调用,每次请求都会弹出授权窗口,用户同意后返回userInfo
。该接口用于替换wx.getUserInfo
6.wx.-设备接口
-
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中: <text class='shopName' bindtap='textPaste' data-openid="{{userObj.openid}}">{{userObj.openid}}</text>
-
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("刷新结束") } })
9.登录接口(openid)
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
-
总结:
- 微信小程序使用wx.login获取的code发送给后台服务器,后台服务器再去访问微信服务器地址,获取openid。(小程序appid, 应该避免暴露); 查询数据库表当前openid是否存在(因为一个用户只能获取到唯一的一个openid)来判断用户是否存在; 如果用户不存在,则只返回openid, 用于微信注册绑定帐号; 如果用户存在,则会返回openid和用户信息(直接登录,并返回用户信息)
- 自动登录流程:根据获取的openid, 查找openid对应的帐号,如果存在,则返回token, 用户信息,openid, 如果不存在,则只返回openid。
- 手动登录流程:用户手动输入帐号和密码,提交到后台, 如果返回的数据没有openid, 则跳转微信绑定。
- 注册流程:请求获取微信授权,申请获取用户的帐号信息,然后将用户数据提交到后台注册帐号(此时,应该是将前面获取的openid 绑定当前微信帐号)。
- 微信绑定流程:通过传入openid,确认当前帐号是否绑定的是当前微信。微信绑定也是下一次自动登录的关键。
- openid的作用:openid是当前小程序对当前微信用户的唯一身份标识!以根据微信帐号和系统帐号连接在一起。相对来说,openid是小程序连接自动登录 的关键,而access_token 作为身份认证使用。而网页端是以保存access_token作为自动登录和身份认证的功能。(应该也可以根据openid反向获取用户信息)
1.小程序登录流程
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
}
2.oss文件直传
- 因为我们走的是STS模式,所以首先去后台获取oss配置(accessKeyId,accessKeySecret,stsToken)
- 创建oss实例,前后端商量好文件上传路径,直接上传,返回的是在线图片链接
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BittewZQ-1661414245342)(C:\Users\Icy-yun\AppData\Roaming\Typora\typora-user-images\image-20220210141956427.png)]
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()
})
},
3.支付宝沙箱支付
1.使用沙箱支付宝
-
首先需要使用个人真实支付宝帐号申请一个沙箱帐号,里面包含 商家 和 用户 测试帐号
-
然后下载沙箱支付宝,使用 沙箱支付宝帐号登录,支付余额可以在 注册的支付宝帐号里面配置(真实)。
2.可以查看一下沙箱支付宝处理的流程(配置沙箱环境)
-
选择支付宝的 研发服务选项, 配置密钥/证书(公钥)
-
然后配置应用网关,用于接收支付宝沙箱环境的通知
-
(自己的服务器)服务端配置 支付宝网关地址 、APPID、签名方式
-
然后配置授权回调地址
10.微信小程序上线
1.项目根路径
1.基础路径
- 在项目下所有的json文件中,根路径都是项目所在的路径。
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文件中只能使用相对路径引入
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( );
2.开发平台上线
- 构建npm包,真机扫码预览,打开开发者调试模式。(因为会校验合法域名)
- 校验合法域名(使用https), 在开发者管理配置服务器信息,";"号分隔, 添加可能请求的域名(包括图片)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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
- 小程序开发中真机调试突然接口加载失败,排查了好多次,最后发现接口域名证书导致的
VM13:2 Unhandled promise rejection 90001, 重新安装一下域名证书就好了
11.框架知识总结
1.与vue的相同点
-
生命周期:
-
- vue有8个生命周期: beforeCreate,created, beforeMount, mounted, beforeUpdate, updated, beforeUnmount, unmounted
- 微信小程序有3种类型的生命周期:
- 应用生命周期:(常用)onLaunch, onShow, onHide, onError, onPageNotFound
- 页面生命周期:(常用)onLoad, onShow, onHide, onReady, onUnload, onPUllDownRefresh, onReachBottom
- 组件生命周期:(常用):略
-
组件机制:
-
-
vue组件机制,父子之间传递数据,以及使用插槽添加额外的子数据。
-
微信小程序只有组件和vue类似, property 属性是继承属性, data 是数据源, methods是方法集合。 使用组件的页面可以通过标签属性传递数据, 而组件可以通过 this.triggerEvent派发一个自定义事件,页面通过 onxxxx = “xxx” 接收组件传递数据。使用方法和vue的$emit类似。
同时,可以在组件内定义slot标签,作为插槽的数据。
-
微信小程序的pages页面也有data数据, 通常使用 this.data.xxx获取指定数据。
-
-
2.与vue的区别
-
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 控制节点的显示。使用方法相同。
-
-