1.mobx-miniprogram创建 Store 对象
2.在组件中使 用 Store 数据
3.在页面中使用 Store 数据-方式
用component进行构造
4.在页面中使用 Store 数据-方式
5.fields、actions 对象写法
6.实现小程序登录功能
7.使用数据渲染用户信息
8. 更新用户信息-渲染用户信息
9.收集省市区数据
思路分析:
省市区的结构使用了小程序本身自带的`picker` 件,并将组件的 `mode` 属性设置为了 `region`,从而变成省市区选择器
如果想获取省市区的数据,需要给 `picker` 选择组件添加`change` 事件来监听属性值的改变,获取选中的省市区
<!-- 省市县 -->
<view class="item">
<text class="label">省/市/县 (区)</text>
<!-- mode:给组件添加 mode 属性设置为了 region,从而变成省市区选择器 -->
<!-- value:要求是一个数组,表示选中的省市区,默认选中每一列的第一个值 -->
<!-- bindchange:来监听属性值的改变,也就是获取选中的省市区 -->
<picker
mode="region"
value="{{ [provinceName, cityName, districtName] }}"
bindchange="onAddressChange"
>
<view wx:if="{{ provinceName }}" class="region">
{{ provinceName + ' ' + cityName + ' ' + districtName }}
</view>
<view wx:else class="placeholder">请填写收货人所在城市</view>
</picker>
<view class="location" bindtap="onLocation">
<van-icon name="location-o" color="#777" />
<text>定位</text>
</view>
</view>
10.收集新增地址其他请求参数
思路分析:
使用简易双向数据 `model:value` 绑定来收集新增地址表单数据。
在将数据收集以后,需要组织两个数据:
1. 是否是默认地址,0 不设置为默认地址,1 设置为默认地址
2. 拼接完整的收货地址
实现步骤:
1. 使用简易双向数据绑定来收集新增地址表单数据。
3. 给按钮绑定点击事件,在事件处理函数中收集并整理数据
Page({
saveAddrssForm(event) {
// 解构出省市区以及 是否是默认地址
const { provinceName, cityName, districtName, address, isDefault } = this.data
// 拼接完整的地址
const fullAddress = provinceName + cityName + districtName + address
// 合并接口请求参数
const params = {
...this.data,
fullAddress,
isDefault: isDefault ? 1 : 0
}
console.log(params)
}
})
11.拒绝授权的解决方案
async onLocation() {
const { authSetting } = await wx.getSetting()
console.log(authSetting)
const isAuth = !!authSetting['scope.userLocation']
if (!isAuth) {
const modalRes = await wx.modal({
title: '授权提示',
content: '需要需要您的地理位置信息,请确认授权'
})
// 如果用户点击了取消,说明用户拒绝了授权,给用户提示
if (!modalRes) return wx.toast({ title: '您拒绝了授权' })
// 如果用户点击了确定,调用 wx.openSetting 打开微信客户端小程序授权页面
// 并返回授权以后的结果
const { authSetting } = await wx.openSetting()
// 如果用户没有更新授权信息,提示没有更新授权
if (!authSetting['scope.userLocation'])
return wx.toast({ title: '授权失败!' })
try {
const locationRes = await wx.getLocation()
// 打印地理位置信息
console.log(locationRes)
} catch (err) {
console.log(err)
}
} else {
try {
const locationRes = await wx.getLocation()
console.log(locationRes)
} catch (error) {
wx.toast({ title: '您拒绝授权获取地址位置' })
}
}
}
12. 开启腾讯位置服务
13.async-validator 基本使用
1.安装 async-validator
npm i async-validator
2.开发者工具,点击构建 npm
,对 async-validator
进行构建
3.在 js 文件中导入 async-validator
// 1️⃣ 引入 async-validator,async-validator 提供了一个构造函数 import Schema from 'async-validator' Page({ // 2️⃣定义需要验证的数据 data: { name: '你好' }, // 验证数据 onValidate() { // 3️⃣创建表单验证规则 const rules = { // key 建议和 需要验证的数据字段名字保持一致 name: [ // required 是否是必填项 { required: true, message: 'name 不能为空' }, // type 数据的类型 // message 如果验证失败,提示的错误内容 { type: 'string', message: 'name 不是字符串' }, // min 最少位数,max 最大位数 { min: 2, max: 5, message: '名字最少 2 个字,最多 5 个字' } // 正则表达式 // { pattern: '', message: '' } // 自定义验证规则 // { validator: () => {} } ] } // 4️⃣创建表单验证实例 // 在创建实例时需要传入验证规则 const validator = new Schema(rules) // 5️⃣ 调用 validate 实例方法对数据进行验证 // validate 方法接收一个对象作为参数,对象是需要验证的数据 // 注意:validate 方法只会验证和验证规则同名的属性 validator.validate(this.data, (errors, fields) => { // 如果验证失败,errors 是所有错误的数组 // 如果验证成功,errors 是 null console.log(errors) // fields 是需要验证的属性,属性值是数组,数组中包含错误信息 console.log(fields) if (errors) { console.log('验证没有通过') console.log(errors) return } console.log('验证通过') }) } })
14. 封装商品模块接口 API
import http from '../utils/http'
/**
* @description 获取商品列表
* @return Promise
*/
export const reqGoodsList = ({ limit, page, ...reset }) => {
return http.get(`/mall-api/goods/list/${page}/${limit}`, reset)
}
/**
* @description 获取商品详情
* @param {*} goodsId 商品Id
* @returns Promise
*/
export const reqGoodsInfo = (goodsId) => {
return http.get(`/mall-api/goods/${goodsId}`)
}
15. 商品列表-获取商品列表数据并渲染
思路分析:
在准备商品列表的请求参数以后,
在页面调用 `API` 函数获取商品列表的数据,在获取到数据以后,使用后端返回的数据对页面进行渲染。
实现步骤:
1. 在 `/pages/goods/list/list.js` 中导入封装好的获取商品列表的 `API` 函数
2. 页面数据在页面加载的时候进行调用,在 `onLoad` 钩子函数中调用 `reqGoodsList` 方法
3. 在获取到数据以后,使用后端返回的数据对页面进行渲染
/modules/goodsModules/pages/list/list.js`
import { reqGoodsList } from '../../../../../api/good'
Page({
// 页面的初始数据
data: {
goodsList: [], // 商品列表数据
total: 0, // 数据总条数
isFinish: false, // 判断数据是否加载完毕
// 接口请求参数
requestData: {
page: 1, // 页码
limit: 10, // 每页请求多少条数据
category1Id: '', // 一级分类 id
category2Id: '' // 二级分类 id
}
},
// 获取商品列表的数据
async getGoodsList() {
// 调用 API 获取数据
const { data } = await reqGoodsList(this.data.requestData)
// 将返回的数据赋值给 data 中的变量
this.setData({
goodsList: data.records,
total: data.total
})
},
// 生命周期函数--监听页面加载
onLoad(options) {
// 接收传递的参数
Object.assign(this.data.requestData, options)
// 获取商品列表的数据
this.getGoodsList()
}
})
16.商品列表-实现上拉加载
/modules/goodsModule/pages/list/list.js`
import { reqGoodsList } from '../../../api/goods'
Page({
// coding...
// 获取商品列表的数据
async getGoodsList() {
// 调用 API 获取数据
const { data } = await reqGoodsList(this.data.params)
// 将返回的数据赋值给 data 中的变量
this.setData({
goodsList: [...this.data.goodsList, ...data.records],
total: data.total
})
},
// coding...
// 监听页面的上拉操作
onReachBottom() {
let { page } = this.data.requestData
// 页码 + 1
this.setData({
requestData: { ...this.data.requestData, page: page + 1 }
})
// 重新发送请求
this.getGoodsList()
}
})
17. 商品列表-实现下拉刷新
1. 在`页面.json` 中开启允许下拉,同时可以配置 窗口、loading 样式等 2. 在`页面.js` 中定义 `onPullDownRefresh` 事件监听用户下拉刷新
/modules/goodsModule/pages/list/list.json`
{
"usingComponents": {
"goods-card": "/components/goods-card/goods-card"
},
"navigationBarTitleText": "商品列表",
"enablePullDownRefresh": true,
"backgroundColor": "#f7f4f8",
"backgroundTextStyle": "dark"
}
/modules/goodsModule/pages/list/list.js`
// 监听页面的下拉刷新
onPullDownRefresh() {
// 将数据进行重置
this.setData({
goodsList: [],
total: 0,
isFinish: false,
requestData: { ...this.data.requestData, page: 1 }
})
// 重新获取列表数据
this.getGoodsList()}
18封装结算支付的接口 API
/api/orderpay.js`
import http from '@/utils/http'
/**
* @description 获取订单详情
* @returns Promise
*/
export const reqOrderInfo = () => {
return http.get('/order/trade')
}
/**
* @description 获取订单列表
* @param {*} page 页码
* @param {*} limit 每页展示的条数
* @returns Promise
*/
export const reqOrderList = (page, limit) => {
return http.get(`/order/order/${page}/${limit}`)
}
/**
* @description 获取订单收货地址
* @returns Promise
*/
export const reqOrderAddress = () => {
return http.get('/userAddress/getOrderAddress')
}
/**
* @description 获取立即购买商品的详情信息
* @param { Object } params { goodsId: 商品 Id, blessing:祝福语 }
* @returns Promise
*/
export const reqBuyNowGoods = ({ goodsId, ...data }) => {
return http.get(`/order/buy/${goodsId}`, data)
}
/**
* @description 提交订单
* @returns Promise
*/
export const reqSubmitOrder = () => {
return http.post('/order/submitOrder')
}
/**
* @description 获取微信预支付信息
* @param {*} orderNo 订单 ID
* @returns Promise
*/
export const reqPreBuyInfo = (orderNo) => {
return http.get(`/webChat/createJsapi/${orderNo}`)
}
/**
* @description 微信支付状态查询
* @param {*} orderNo
* @returns Promise
*/
export const reqPayStatus = (orderNo) => {
return http.get(`/webChat/queryPayStatus/${orderNo}`)
}
19. 商品结算-更新收货地址功能
思路分析:
当用户需要更改收货地址时,我们需要跳转到收货地址页面,重新选择收货地址
当用户点击了某个地址以后,我们需要将该地址显示到商品结算页面中。
更新收货地址功能,采用 `getApp()` 全局共享数据的方式来实现。
实现步骤:
在 `app.js` 中定义全局共享的数据 `globalData.address`
点击箭头,携带参数跳转到收货地址页面,标识是从订单结算页面进入
在选择收货地址成功以后,将数据存储到 `globalData.address`中,然后返回到订单结算页面。
在订单结算页面判断 `globalData.address` 是否存在收货地址数据,如果存在则渲染
app.js`
App({
// 定义全局共享的数据
globalData: {
address: {}
}
})
/pages/address/list/index.html`
<!-- 每一个收货地址 -->
<view
class="info"
bindtap="changeAddress"
data-id="{{ item.id }}"
>
<view class="user-info">
<text>{{ item.name }}</text>
<text>{{ item.phone }}</text>
<text wx:if="{{ item.isDefault === 1 }}" class="default-tag">默认</text>
</view>
<view class="address-info"> {{ item.fullAddress }} </view>
</view>
20 节流阀
如果事件被频繁触发,节流能够减少事件触发的频率,因此,节流是有选择性地执行一部分事件!
1.定义节流阀
代码如下(示例):
// 步骤1. 定义节流阀
var timer = null //false
2.绑定 mousemove 事件
// 2. 绑定 mousemove 事件
$(document).on('mousemove', function (e) {
// 步骤3:判断节流阀是否为空,如果不为空,则证明距离上次执行间隔不足16毫秒
if (timer) {
return
}
// 3. 设置图片的位置
// 步骤2:开启延时器 2.当设置了鼠标跟随效果后,清空 timer 节流阀,方便下次开启延时器
timer = setTimeout(function () {
$(angel).css('top', e.pageY + 'px').css('left', e.pageX + 'px')
console.log('ok')
timer = null
}, 16)
})
3. 判断节流阀是否为空,如果不为空,说明距离上一次执行时间还没有设定的时间。则返回。
if (timer) {
return
}