Appearance
Vant Weapp 组件库使用
安装
可参考 https://youzan.github.io/vant-weapp/#/quickstart#bu-zou-yi-tong-guo-npm-an-zhuang
- 打开编译器在资源管理器空白处右键点击 “ 在外部中断窗口中打开 ”
bash
npm i @vant/weapp
起步使用
发送数据请求
推荐使用 @escook/request-miniprogram 发送数据请求
使用 npm 包
构建 npm 包
- 在小程序中每次安装一个新的包时必须重新构建依次 npm 包
uniapp 开发
- 开发时如果使用了 less、sass 等预编译语言建议先在 HBuilder 中安装对应插件
新建项目
项目目录
将项目运行到小程序开发工具中
填写 appid
配置微信开发工具路径
- 依次点击 HBuilder 顶部的 “工具” => "设置"
开启微信开发工具服务端口
运行
取消 sitemap 警告
在 manifest.json 文件中添加如下代码即可
创建 tabBar 导航
先在 page 文件夹下创建需要展示的 tabBar 页面文件
然后打开 pages.json 在 pages 节点下引入对应页面,在创建 tabBar 节点对页面进行配置
json
"pages": [{
"path": "pages/home/home",
"style": {}
}, {
"path": "pages/cate/cate",
"style": {}
}, {
"path": "pages/cart/cart",
"style": {}
}, {
"path": "pages/my/my",
"style": {}
}],
"tabBar": {
"selectedColor": "#C00000", // 表示底部 tabBar 显示文字颜色
"list": [{
"pagePath": "pages/home/home",
"text": "首页",
"iconPath": "static/tab_icons/home.png", // 表示该页面未被选中的图标
"selectedIconPath": "static/tab_icons/home-active.png"
},
{
"pagePath": "pages/cate/cate",
"text": "分类",
"iconPath": "static/tab_icons/cate.png",
"selectedIconPath": "static/tab_icons/cate-active.png"
},
{
"pagePath": "pages/cart/cart",
"text": "购物车",
"iconPath": "static/tab_icons/cart.png",
"selectedIconPath": "static/tab_icons/cart-active.png"
},
{
"pagePath": "pages/my/my",
"text": "我的",
"iconPath": "static/tab_icons/my.png",
"selectedIconPath": "static/tab_icons/my-active.png"
}
]
}
tabBar 页面跳转
调用 switchTab 即可跳转到指定 tabBar 页面
js
navClickHandler(item) {
if (item.name === '分类') {
// switchTab 函数用于跳转底部 tabbar 页面
uni.switchTab({
url: '/pages/cate/cate',
// 跳转完成调用
complete: () => {
this.updataRedirectInfo(null)
}
})
}
},
可使用高度
js
export default {
data() {
return {
wh: 0
}
},
onLoad() {
// getSystemInfoSync 可以获取当前设备的详细信息
const sysInfo = uni.getSystemInfoSync()
// windowHeight 可以获取当前设备可使用的高度(整个屏幕除去头部标题区和底部 tabBar 区域就是剩余可使用高度)
this.wh = sysInfo.windowHeight
}
}
重置页面滚动位置
vue
<!-- scroll-top 可以动态设置滚动的位置 -->
<scroll-view
scroll-y="true"
:style="{ height: wh + 'px' }"
:scroll-top="scrollTop"
>
<view class="cate-lv2" v-for="(item2,i2) in cateLevel2" :key="i2">
<view class="cate-lv2-title">/ {{item2.cat_name}} /</view>
<view class="cate-lv3-list">
<view class="cate-lv3-item" v-for="(item3,i3) in item2.children" :key="i3">
<image :src="item3.cat_icon"></image>
<text>{{item3.cat_name}}</text>
</view>
</view>
</view>
</scroll-view>
<script>
export default {
data() {
return {
scrollTop:0
}
},
methods: {
// 切换分类时改变选中项
activeChange(i){
// 重置滚动时不能赋相同的值
this.scrollTop = this.scrollTop === 0 ? 1 : 0
},
}
</script>
跳转指定分包地址页面
js
gotoGoodsList(item){
// 跳转指定分包地址页面
uni.navigateTo({
url:'/subpkg/goods_list/goods_list?cid=' + item.cat_id
})
},
自定义组件
- 在 components 目录中创建自定义组件,在页面中使用
uni-app 组件
vue
<!-- 使用 uni-app 提供的图标组件 -->
<uni-icons type="search" size="30"></uni-icons>
<text class="placeholder">搜索</text>
计数组件
vue
<!-- min 表示最小值 value 表示当前显示的数量 change 表示当数值发生变化时 -->
<uni-number-box
:min="1"
:value="goods.goods_count"
@change="numChangeHandler"
></uni-number-box>
<script>
methods: {
numChangeHandler(val) {
console.log(val); // val 可以拿到改变后的值
}
}
</script>
- 解决计数组件输入非数字数据时出现 NaN
- 打开组件源代码 找到 _onBlur 函数并作出如下改动
js
_onBlur(event) {
this.$emit('blur', event)
// let value = event.detail.value;
let value = parseInt(event.detail.value);
if (!value) {
this.inputValue = 1;
return;
}
},
滑动删除组件
vue
<!-- 使用滑动删除组件之前的代码 -->
<!-- <block v-for="(goods, i) in cart" :key="i">
<my-goods :goods="goods" :showRadio="true" @radio-change="radioChangeHandler" :showNum="true" @num-change="numberChangeHandler"></my-goods>
</block> -->
<!-- 滑动删除组件 -->
<!-- 使用滑动删除组件之后的代码 -->
<uni-swipe-action>
<block v-for="(goods, i) in cart" :key="i">
<uni-swipe-action-item :right-options="options">
<my-goods :goods="goods" :showRadio="true" @radio-change="radioChangeHandler" :showNum="true" @num-change="numberChangeHandler"></my-goods>
</uni-swipe-action-item>
</block>
</uni-swipe-action>
<script>
data() {
return {
// 滑动删除配置项
options: [
{
text: '删除', // 指定滑动组件显示的文本内容
style: {
backgroundColor: '#C00000' // 指定滑动组件的背景颜色
}
}
]
}
},
</script>
为自定义组件添加点击事件
- 这样页面在使用组件时就可以触发点击事件
定义过滤器
- 在 data 平级定义过滤器
js
data() {
return {
// 定义默认图片
defaultPic: 'https://img3.doubanio.com/f/movie/8dd0c794499fe925ae2ae89ee30cd225750457b4/pics/movie/celebrity-default-medium.png'
}
},
// 定义过滤器实现数字精确到百分位
filters:{
tofixed(num) {
return Number(num).toFixed(2)
}
}
- 在页面中使用
vue
<!-- 调用定义好的过滤器 -->
<view class="goods-price">¥{{ goods.goods_price | tofixed}}</view>
持久化存储
onload
- 在 onLoad 函数形参里可以拿到其他页面跳转过来所携带的参数
实现上拉加载功能
- 先在 pages.json 中配置那个需要该功能的页面添加上拉触底距离
json
"path": "goods_list/goods_list",
"style":{
"onReachBottomDistance":150
}
- 在 methods 节点下添加上拉加载事件,并添加节流阀控制请求频率
js
data() {
return {
// 请求参数对象
queryObj: {
query: '',
cid: '',
pegenum: 1,
pagesize: 10
},
goodsList: [],
total: 0,
// 定义上拉加载节流阀
isloading:false
}
},
onLoad(options) {
this.queryObj.query = options.query || ''
this.queryObj.cid = options.cid || ''
this.getGoodsList() // 获取商品列表数据
},
methods: {
// 获取商品列表数据
async getGoodsList() {
this.isloading = true // 开启节流阀
const { data: res } = await uni.$http.get('/api/public/v1/goods/search', this.queryObj)
this.isloading = false // 关闭节流阀
if (res.meta.status !== 200) return uni.$showMsg()
this.goodsList = [...this.goodsList, ...res.message.goods]
this.total = res.message.total
},
// 上拉加载
onReachBottom() {
// 判断数据是否加载完毕
if(this.queryObj.pegenum * this.queryObj.pagesize >= this.total) return
if(this.isloading) return
this.queryObj.pegenum++
this.getGoodsList()
}
}
下拉刷新
- 先在 pages.json 中配置
json
"style":{
"onReachBottomDistance":150, // 上拉加载触发时距离底部距离
"enablePullDownRefresh":true, // 开启上拉刷新
"backgroundColor":"#F8F8F8" // 上拉刷新时的背景颜色
}
- 在 methods 节点下添加下拉刷新事件
js
// 获取商品列表数据
async getGoodsList(cb) {
const { data: res } = await uni.$http.get('/api/public/v1/goods/search', this.queryObj)
//////////////////
cb && cb() // 调用关闭下拉刷新的函数
//////////////////
if (res.meta.status !== 200) return uni.$showMsg()
this.goodsList = [...this.goodsList, ...res.message.goods]
this.total = res.message.total
},
// 下拉刷新
onPullDownRefresh(){
// 重置关键数据
this.queryObj.pagenum = 1
this.total = 0
this.isloading = false
this.goodsList = []
// 重新获取数据
// uni.stopPullDownRefresh() 关闭下拉刷新
this.getGoodsList(() => uni.stopPullDownRefresh())
}
图片预览
- 为需要预览的地方添加点击事件
vue
<swiper-item v-for="(item, i) in goods_info.pics" :key="i" @click="preview(i)">
<image :src="item.pics_big"></image>
</swiper-item>
- 在 methods 节点下定义这个点击事件
js
// 图片预览功能
preview(i) {
// uni.previewImage 图片预览功能
uni.previewImage({
current: i, // 当前预览哪一张图片
urls: this.goods_info.pics.map(item => item.pics_big) // 需要预览的图片的 url 地址,是一个数组
})
}
渲染 html 代码片段
- rich-text 组件能快速帮我们把一段富文本 html 字符串渲染为 html 代码
vue
<!-- rich-text 组件渲染后端返回的一段富文本 html 代码 nodes 节点传递一个 html 代码片段-->
<rich-text :nodes="goods_info.goods_introduce"></rich-text>
- webp 格式的图片在 IOS 端支持度不好,可能无法正常显示图片
底部购物车组件
vue
<!-- fill 表示按钮是否是圆角的 options 表示配置对象 buttonGroup 表示右侧按钮配置 -->
<!-- click 表示左侧点击事件 buttonClick 表示右侧按钮点击事件-->
<uni-goods-nav
:fill="true"
:options="options"
:buttonGroup="buttonGroup"
@click="onclick"
@buttonClick="buttonClick"
></uni-goods-nav>
<script>
data() {
return {
options: [
{
icon: 'shop',
text: '店铺',
infoBackgroundColor: '#007aff',
infoColor: 'red'
},
{
icon: 'cart',
text: '购物车',
info: 2
}
],
buttonGroup: [
{
text: '加入购物车',
backgroundColor: '#ff0000',
color: '#fff'
},
{
text: '立即购买',
backgroundColor: '#ffa200',
color: '#fff'
}
]
}
},
</script>
点击左侧按钮事件
修改 tabBar 右上角图标
js
// 当该页面刚显示时触发
onShow() {
this.setBadge()
},
methods: {
// 更改购物车页面商品数量图标
setBadge() {
// uni.setTabBarBadge 可以设置 tabBar 的信息
uni.setTabBarBadge({
index: 2, // 修改的索引 (要修改哪个 tabBar )
text: this.total + '' // 更改 tabBar 右上角的徽标 text 必须是字符串
})
}
}
mixins 代码混入
借助 mixins 能把一些重复的代码抽离出去,其他页面按需引入即可
先创建文件和编写代码
- 在其他页面使用
js
// 引入 mixins 代码
import badgeMix from '@/mixins/tabbar-badge.js'
export default {
// 挂载 mixins
mixins: [badgeMix]
}
选择地址 API
js
// 当点击选择收货地址按钮时
async chooseAddress() {
// chooseAddress uniapp 提供的选择地址API 返回值是一个 promise err 代表调用api时的错误对象,succ代表成功调用的对象
const [err, succ] = await uni.chooseAddress().catch(err => err)
// 判断是否在调用 API 期间发生错误
if(err === null && succ.errMsg === 'chooseAddress:ok') {
console.log(succ)
}
}
- 解决用户第一次未能给小程序授权访问地址信息,下一次不再提示,就不能再选择地址问题
js
// 当点击选择收货地址按钮时
async chooseAddress() {
// chooseAddress uniapp 提供的选择地址API 返回值是一个 promise err 代表调用api时的错误对象,succ代表成功调用的对象
const [err, succ] = await uni.chooseAddress().catch(err => err)
// 判断是否在调用 API 期间发生错误
if (err === null && succ.errMsg === 'chooseAddress:ok') {
this.updateAddress(succ)
}
// 解决方案///////////////////////////////////////////////////////
if (err && (err.errMsg === 'chooseAddress:fail auth deny' || err.errMsg === 'chooseAddress:fail authorize no response')) {
// 当用户再次点击填写地址时调用 reAuth 进行重新授权
this.reAuth()
}
/////////////////////////////////////////////////
}
async reAuth() {
// showModal 可以打开一个提示框
const [err2, confirmResult] = await uni.showModal({
content: '检测到您没有打开地址权限,是否去设置打开?',
confirmText: '确认',
cancelText: '取消'
})
// 如果发生错误时
if (err2) return
if (confirmResult.cancel) return uni.$showMsg('您取消的地址授权')
// 当点击确定时
// openSetting uniapp 提供的API 可以打开设置面板
if (confirmResult.confirm)
return uni.openSetting({
success: settingResult => {
// 用户未开启授权地址按钮
if (!settingResult.authSetting['scope.address']) return uni.$showMsg('您取消的地址授权')
uni.$showMsg('授权成功!')
}
})
}
- 开启提示框
js
// showModal 可以打开一个提示框
const [err2, confirmResult] = await uni.showModal({
content: '检测到您没有打开地址权限,是否去设置打开?',
confirmText: '确认',
cancelText: '取消'
})
- 调用 openSetting 方法打开设置
js
uni.openSetting({
success: settingResult => {
// 用户未开启授权地址按钮
if (!settingResult.authSetting['scope.address'])
return uni.$showMsg('您取消的地址授权')
uni.$showMsg('授权成功!')
}
})
一键登录
vue
<!-- open-type 表示希望获取用户的基本信息 open-type="getUserInfo" 是固定写法 -->
<!-- 能在 @getuserinfo 事件的形参中获取到用户的基本信息 @getuserinfo="" 是固定写法 -->
<button
type="primary"
class="btn-login"
open-type="getUserInfo"
@getuserinfo="getUserInfo"
>一键登录</button>
<script>
// 用户授权后,获取用户的基本信息
getUserInfo(e) {
console.log(e) // 获取用户基本信息
}
}
</script>
获取登录信息
js
getUserInfo(e) {
// 判断用户是否授权
if (e.detail.errMsg === 'getUserInfo:fail auth deny') return uni.$showMsg('您取消的登录授权!')
this.updataUserInfo(e.detail.userInfo)
this.getToken(e.detail)
},
// 获取 token
async getToken(info) {
// uni.login() 获取登录信息
const [err,res] = await uni.login().catch(err=>err)
// 判断调用 uni.login() 时是否出错
if(err || res.errMsg !== 'login:ok') return uni.$showMsg('登录失败!')
console.log(res);
}
订单支付
具体步骤
支付接口所需参数
发布
打开微信公众平台小程序后台,点击提交审核即可
打包为 app
依次选择 ‘’使用公共测试证书“ => ”打正式包“ 然后点击打包即可
耐心等待打包完成控制台会返回 app 下载链接