微信小程序开发 外部链接别人的总结查看(超详细保姆式教程)
Page({
data: {
motto: 'Hello World',
id:18
}
})
单项数据流:Mustache 语法
a)模板结构中使用双大括号 {{data}}
<text id="{{id}}">{{motto}}</text>
<input type="text" value="{{motto}}"/>
双向数据绑定
a)表单项使用 model:value = ‘{{data}}’
<input type="text" model:value="{{motto}}"/>
b)坑!!!
<input type="text" model:value="{{a}}"/>
this.setData({message: ‘修改之后的数据’}, callback)
Page({
data: {
motto: 'Hello World',
a: 'abc'
},
onLoad(){
this.setData({
motto: 'change data'
})
}
})
2)非冒泡事件
bind绑定:事件绑定不会阻止冒泡事件向上冒泡
<view bindtap="handleTap" class='start_container'>
<text class='start'>开启小程序之旅</text>
</view>
catch 绑定: 事件绑定可以阻止冒泡事件向上冒泡
<view catchtap="handleTap" class='start_container'>
<text class='start'>开启小程序之旅</text>
</view>
<button catchtap="changeName" data-name='{{firstName}}'>点击修改名称</button>
获取: event.target.dataset.key || event.currentTarget.dataset.key
Event.target 和 event.currentTarget的区别
a.) Event.target是触发事件的对象,但不一样是绑定事件的对象,如: 事件委托,冒泡
b) currentTarget触发事件的对象一定是绑定事件的对象, 没有事件委托
wx:for="{{arr}}"
wx:key="唯一值或者index"
<view wx:for="{{ list }}" wx:key="id">
<view>{{ index }} -- {{ item.content }}</view>
</view>
同Vue一样,循环遍历的时候需要为每一个item添加唯一的key值
Key值分类:
a)Item本身就是唯一值,如: number,string
b)*this,代表item本身,同样需要item自身是唯一的,如;number,string
c)Item的唯一属性,如: id; 官网没有明确语法说明,只能在示例代码中找到
注意事项:
a)Wx:key后跟的变量不需要使用插值语法,即不需要使用大括号包裹
b)Item中如果有唯一值属性,可以直接使用
如:item = {id: 1}, 则wx:key = 'id'
1.默认的个体: item
2.默认的下标: index
3.自定义个体变量名称: wx:for-item=’myItem’
4.自定义下标变量名称: wx:for-index=’myIndex’
<view wx:for="{{ list }}" wx:key="id" wx:for-item="myItem" wx:for-index="myIndex">
<view>{{ myIndex}} -- {{myItem.content}}</view>
</view>
wx:if=’条件’
wx:elif=’条件’
wx:else
<view>
<!-- 条件渲染 -->
<view wx:if="{{ isShow }}">表白成功</view>
<view wx:else>表白失败</view>
<!-- <view wx:else="{{ !isShow }}">表白失败</view> -->
<view>-----------------</view>
<view wx:if="{{ sex === 0 }}">男</view>
<view wx:elif="{{ sex === 1 }}">女</view>
<view wx:else>未知</view>
</view>
1.hidden用法:
2.wx:if 等同于 v-if, 条件为false的时候不加载,条件切换的时候决定元素销毁或者重新加载渲染
3.hidden 等同于 v-show, 始终加载元素, 条件切换的时候决定元素的显示和隐藏
官方图示:官方图
生命周期函数 | 执行时机 | 执行次数 | 特点说明 |
---|---|---|---|
onLoad | 页面加载时触发 | 1 | 可以通过参数获取打开当前页面路径中的参数 |
onShow | 页面显示/切入前台时触发 | 多次 | 如页面没有被销毁,会重复多次显示隐藏,可以在此发送请求获取最新数据 |
onReady | 页面初始化渲染完成时触发 | 1 | 可以同UI界面进行交互 |
onHide | 页面隐藏/切入后台时触发 | 多次 | wx.navigateTo 或底部 tab 切换到其他页面,小程序切入后台等 |
onUnload | 页面卸载时触发 | 1 | wx.redirectTo或wx.navigateBack到其他页面时 |
个人见解
官网生命周期图示是错误的;错误部分:标注onLoad及onShow执行的位置不对
参考:小程序启动执行的所有流程
参考地址:
https://developers.weixin.qq.com/miniprogram/dev/framework/performance/tips/start_process.html
小程序适配单位: rpx
规定任何屏幕下宽度为750rpx
小程序会根据屏幕的宽度不同自动计算rpx值的大小
Iphone6下: 1rpx = 1物理像素 = 0.5px
组件传参 - 把标题"猜你喜欢", "人气推荐"传入到组件中
怎么传? — 标签直接帮属性即可
怎么接?
组件内使用 properties 接(不支持数组,支持对象和配置对象)
// 不支持数组写法
// properties: ["title"],
// 支持对象写法
// properties: {
// title: String,
// },
// 支持配置对象写法
properties: {
title: {
type: String,
required: true
},
list: {
type: Array,
required: true
}
},
使用标签和js都可以跳转
标签跳转
<navigator
url="/pages/goods/list/list?category2Id={{item.id}}"
>navigator>
同时携带了 query 参数(路由带参)
js跳转
wx.navigateTo({
url: '/pages/goods/list/list',
});
没带参数
wx.switchTab 跳转到tabbar页面
wx.redirectTo 关闭当前页面,跳转下一个页面,当前页面不在历史记录中
wx.navigateTo 跳转页面(有历史记录)
wx.navigateBack({ delta: 1 }) 回退页面,没有参数默认是1
wx.reLaunch 关闭所有的页面,打开到应用内的某个页面
https://developers.weixin.qq.com/miniprogram/dev/api/storage/wx.setStorage.html
https://developers.weixin.qq.com/miniprogram/dev/api/storage/wx.setStorage.html
路由地址中 + query传参数
url?a=123
wx.navigateTo({
url: '/pages/target/target?a=1&b=2',
});
onLoad(options){
const {a, b} = options;
}
pubsub-js
npm install pubsub-js
import PubSub from ‘pubsub-js’
PubSub.subscribe(‘eventName’, callback)
PubSub.publish(‘eventName’, data)
PubSub.unsubscribe(‘eventName’)
获取事件总线对象
a)目标页面中通过: 实例.getOpenerEventChannel()
b)示例: const eventChannel = this.getOpenerEventChannel()
const app = getApp()
app.currentAddress = currentAddress;
const app = getApp()
let currentAddress = app.currentAddress
获取数据{
"component": true,
"usingComponents": {},
"navigationStyle": "custom" -----> 自定义导航 导航栏样式
"navigationBarTitleText": "登录" -----> 自定义文字
}
1.使用组件的页面的json文件中注册使用组件
{
"usingComponents": {
"goods-list": "/components/goods-list/goods-list"
}
}
<goods-list title="猜你喜欢" list="{{ likeList }}">goods-list>
npm init
npm install packageName
wx.getUserInfo()
a) 依然可以使用,但不会出现授权弹窗
b) 获取到的用户名为 ‘微信用户’, 头像为灰色头像
8.6.2.3 登录流程说明
发送code给服务器端
服务器端发送请求携带参数(code, appSecret, appId)给微信服务器获取openId
a) 微信接口API: GET https://api.weixin.qq.com/sns/jscode2session
服务器获取openId后进行加密返回给前端Token标识
npm i @vant/weapp -S --production
yarn add @vant/weapp –production
"packNpmRelationList": [
{
"packageJsonPath": "./package.json",
"miniprogramNpmDistDir": "./"
}
],
微信开发工具 —> 工具 —> 构建npm
{
"usingComponents": {
"van-action-sheet": "@vant/weapp/action-sheet/index",
"van-stepper": "@vant/weapp/stepper/index",
"van-icon": "@vant/weapp/icon/index",
"van-button": "@vant/weapp/button/index"
}
}
8.7.6 使用组件
<van-button block type="primary" round bindtap='handleSubmit'>确定van-button>
a)异步加载组件
// subPackageA/pages/index.json
{
"usingComponents": {
"button": "../../commonPackage/components/button",
"list": "../../subPackageB/components/full-list",
"simple-list": "../components/simple-list"
},
"componentPlaceholder": {
"button": "view",
"list": "simple-list"
}
}
b)异步加载js文件
/* 回调函数形式 */
let findUserAddress, delAddress;
require('../../../../utils/api', utils => {
findUserAddress = utils.findUserAddress;
delAddress = utils.deleteAddress;
}, ({mod, errMsg}) => {
console.error(`path: ${mod}, ${errMsg}`)
})
/* promise形式 */
(async function(){
let utils = await require('../../../../utils/api')
console.log(utils)
findUserAddress = utils.findUserAddress;
delAddress = utils.deleteAddress;
})()
https://developers.weixin.qq.com/miniprogram/dev/framework/subpackages.html
wx.requestPayment()
https://pay.weixin.qq.com/wiki/doc/apiv3_partner/open/pay/chapter2_8_2.shtml
整体流程:
用户下单,发请求给商家服务器(这一步前端做),商家服务器生成订单,然后给腾讯服务发请求,生成预付单,生成腾讯生成预付单的目的是为了知道这个订单要收多少钱,腾讯服务知道收多钱之后反馈给商家服务器,生成支付签名信息返回给小程序
小程序端接收到商家返回的支付签名信息,调用 wx.requestPayment()
发起微信支付(这一步前端做)
发起之后要去腾讯服务鉴权,鉴定有没有实名、有没有绑定银行卡,鉴权成功之后告诉小程序可以调起微信支付,此时要去弹出密码输入框(这一步是调用完 requestPayment
)小程序自己和腾讯服务的交互
小程序弹出密码弹框,用户输入密码,授权付款,钱在腾讯服务上,所以授权要发送给腾讯服务,腾讯服务接到授权后,会把用户账号中的款扣了,把钱划给商家,返回支付成功告诉用户,提示"支付成功",这里的支付成功可以理解为"扣款成功"(这时会弹一个弹框,微信弹的)
在这个步骤的同时,会异步告诉商家服务,该用户已经付款,可以发货
点击微信弹出弹框确认之后,要回到商家的小程序,小程序也要提示用户"订单支付成功",所需小程序发请求给商家服务,商家服务接到请求之后,找腾讯服务确认用户是否支付成功,确认之后,返回给用户支付成功的数据,小程序展示"订单支付成功"页面
前端步骤:
调用创建订单接口,创建出订单,返回 orderId
拿着 orderId 获取支付信息
拿着支付信息调用 wx.requestPayment()
去支付
只有支付成功之后,才会走 wx.requestPayment()
的 success 回调
在支付成功之后,调用接口查询订单状态(已支付),跳转支付成功页
app.json
{
"pages":[
"pages/index/index"
],
"window":{
"navigationBarBackgroundColor": "#9c0211",
"navigationBarTitleText": "慕尚花坊",
"navigationBarTextStyle":"white"
},
}
<swiper
class="banner-container"
indicator-dots
indicator-color="#fff"
indicator-active-color="#ff734c"
autoplay
circular
interval="2200"
duration="400"
>
<swiper-item
class="banner-item"
wx:for="{{ bannerList }}"
wx:key="id"
>
<image class="banner-img" src="{{ item.imageUrl }}">image>
swiper-item>
swiper>
<view class="action">
<image class="action-img" src="{{backgroundImg}}" mode="widthFix">image>
view>
注意: image 组件的 mode="widthFix" 是设置宽度,保持图片的宽高比不变,自己去算高度
页面宽高设置100%是相对于父级的,而父级是 page 这个元素,这个元素需要设置 宽高100%才可以,这个元素样式在 app.wxss 中设置,这是个全局的,每个页面的根元素都是 page 这个元素
<view class="category-container">
<view class="menu">
<scroll-view
class="menu-list"
scroll-y
>
<view class="menu-item active">
鲜花玫瑰
view>
<view class="menu-item">
鲜花玫瑰
view>
<view class="menu-item">
鲜花玫瑰
view>
<view class="menu-item">
鲜花玫瑰
view>
scroll-view>
view>
注意:scroll-view 如果要使用flex布局,需要设置enable-flex属性
button 组件添加 open-type="chooseAvatar"
属性点击才能展示出选择头像的弹框
input 组件添加 type="nickname"
属性才能弹出选择昵称的弹框
function request ({
url,
method = 'GET',
data,
header = {},
timeout = 30000
}) {
wx.showLoading({ title: '加载中' }); // 显示loading
const baseURL = `https://gmall-prod.atguigu.cn`
header = {
'content-type':'application/json',
...header
}
// 获取个人信息需要携带token
let token = wx.getStorageSync("TOKEN");
if (token) {
header.token = token
}
return new Promise((resolve, reject) => {
// wx.request 微信提供的,直接用,没有跨域这一说
wx.request({
url: baseURL + url, // 请求的url
method, // 请求方式
data, // 携带数据
header, // 请求头
timeout, // 超时时间
dataType: 'json', // 数据类型是json
responseType: 'text', // 响应类型是文本
success: (response) => { // 请求成功之后会执行success回调
let res = response.data // 拿到响应体(也就是后端返回的数据,包含code、data、message)
if (res && res.code == 200) {
resolve(res.data)
} else if (res.code == 208) { // 未登录的兜底处理,只要返回code是208都去登录页
wx.showModal({
title: '警告',
content: '未登录,请先登录',
showCancel: true,
cancelText: '取消',
cancelColor: '#000000',
confirmText: '确定',
confirmColor: '#3CC51F',
success: (result) => {
console.log(result)
if(result.confirm){ // 点击确认跳转登录页
wx.navigateTo({
url: '/pages/login/login'
});
}
}
});
} else {
// 弹出提示框
wx.showToast({ // 给用户提示
title: '请求失败',
icon: 'error', // none success error
// image: '/static/images/1.png',
duration: 1500
});
console.error(res) // 给程序员看的
reject(res || '请求失败')
}
},
fail: (err) => { // 请求失败执行的回调(断网的时候会走到fail中,超时也会只有fail,url错误(指url不是字符串)也会走fail)
wx.showToast({ // 给用户提示
title: '请求失败',
icon: 'error',
duration: 1500
});
console.error(err) // 给程序员看的
reject(err)
},
complete: () => { // 不管成功失败都会执行的回调
wx.hideLoading(); // 隐藏loading
}
});
})
}
export default request
在 app.json 中配置
{
"resolveAlias": {
"@/*": "/*"
},
}
地址: https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html#tabBar
app.json 文件中配置
"tabBar": {
"color": "#333",
"selectedColor": "#ff582f",
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "/static/tabbar/home-icon1.png",
"selectedIconPath": "/static/tabbar/home-icon1-1.png"
},
{
"pagePath": "pages/category/category",
"text": "分类",
"iconPath": "/static/tabbar/home-icon2.png",
"selectedIconPath": "/static/tabbar/home-icon2-2.png"
},
{
"pagePath": "pages/cart/cart",
"text": "购物车",
"iconPath": "/static/tabbar/home-icon3.png",
"selectedIconPath": "/static/tabbar/home-icon3-3.png"
},
{
"pagePath": "pages/personal/personal",
"text": "我的",
"iconPath": "/static/tabbar/home-icon4.png",
"selectedIconPath": "/static/tabbar/home-icon4-4.png"
}
]
},
onReachBottom的使用 页面触底回调
页面触底的时候要发送请求,需要页面触底的回调(于data配置项同级)
data: {
......
status: 'more' // 页面发请求的状态,总共有以下几个值: 'more'更多 'no-more'没有更多 'loading'加载中 'error'错误
},
// 页面触底回调
onReachBottom() {
if (this.data.status == 'no-more') {
return
}
// 翻页
this.setData({
page: this.data.page + 1
})
this.getGoodsList()
},
async getGoodsList() {
this.setData({ status: 'loading' })
// 组转数据
const { page, limit, category2Id } = this.data
let data = {}
if (category2Id) {
data.category2Id = category2Id
}
// 发送请求
try {
let result = await reqGoodsList(page, limit, data)
let goodsList = this.data.goodsList.concat(result.records) // 之前列表中的值不能清空
let status = 'more'
if (goodsList.length == result.total) { // 当获取到所有的数据之后,状态改为no-more
status = 'no-more'
}
......
这里使用 goosList.length 和 totoal 去判断也可以