项目介绍
效果演示
技术架构
创建项目
HBuilderX创建
下载HBuilderX编辑器
HBuilderX/创建项目: 选择模板/选择Vue版本/创建
安装插件: 工具/插件安装/uni-app(Vue3)编译器
vue代码不能直接运行在小程序环境, 编译插件帮助我们进行代码转换
绑定微信开发者工具: 指定微信开发者工具安装目录后, HBX才能启动微信开发者工具
开启服务端口: 微信开发者工具/设置/安全设置/开启服务端口, 开启服务端口后HBX才能启动微信开发者工具
运行项目: 运行/小程序模拟器/微信开发者工具
开发技巧: 模拟器窗口分离/置顶
目录解析
tabbar切换案例
- 创建页面: page/右键新建页面
- 设置tabbar和窗口表现
// 页面配置文件
{// 页面路由和窗口表现, 创建页面自动添加"pages": [// pages数组中第一项表示应用启动页{"path": "pages/index/index","style": {"navigationStyle": "custom", // 隐藏默认导航"navigationBarTextStyle": "white","navigationBarTitleText": "首页"}},{"path": "pages/my/my","style": {"navigationStyle": "custom","navigationBarTextStyle": "white","navigationBarTitleText": "我的"}},],// 全局页面设置"globalStyle": {"navigationBarTextStyle": "black","navigationBarTitleText": "","navigationBarBackgroundColor": "#F8F8F8","backgroundColor": "#F8F8F8"},// 设置 TabBar, 至少两个"tabBar": {"color": "#333","selectedColor": "#27ba9b","backgroundColor": "#fff","borderStyle": "white","list": [{"text": "首页","pagePath": "pages/index/index","iconPath": "static/tabs/home_default.png","selectedIconPath": "static/tabs/home_selected.png"},{"text": "我的","pagePath": "pages/my/my","iconPath": "static/tabs/user_default.png","selectedIconPath": "static/tabs/user_selected.png"}]}
}
- 配置应用信息: 配置微信appid后, 才能使用微信开发者工具进行真机预览
uniapp对比原生小程序: 每个页面都是.vue文件, 数据绑定和事件处理遵循 vue 规范就可以了
- 属性绑定 src="{{ url }}" 升级为 :src="url"
- 事件绑定 bindtap="xxx" 升级为 @tap="xxx" , 支持()传参
- 支持Vue常用指令 v-for/v-if/v-show/v-model
- 多端开发使用 uni 替换 wx 调用接口能力
实现轮播图效果和大图预览效果
<template><swiper class="banner" indicator-dots circular :autoplay="false"><swiper_item v-for="item in pictures" :key="item.id"><image @tap="onPreviewImage(item.url)" :src="item.url"></image></swiper-item></swiper>
</template><script>
export default {data() {return {// 轮播图数据pictures:[{ id: '1',url: "https://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/uploads/goods_preview 1.jpg"},{ id: '2',url: "https://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/uploads/goods_preview 2.jpg"},{ id: '3',url: "https://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/uploads/goods_preview 3.jpg"},]} },methods: {onPreviewImage(url) {uni.previewImage({urls:this.pictures.map(v=>v.url),current:url})}}
}
</scripr>
命令行创建
创建项目
- 打开cmd, 执行命令: npx degit dcloudio/uni-preset-vue#vite-ts 自定义项目名称
- npx是node自带的包管理工具
- 官网链接: uni-app官网创建uni-app
- 如果下载失败可以去官网下载, 或者切换网络尝试
运行项目
- 项目中src目录下存放的就是uni-app工程代码
- 添加appid: 在manifest.json文件配置appid
- 安装依赖: pnpm install
- 项目编译: pnpm dev:mp-weixin
- 项目运行: 把编译后的文件 dist/dev/mp-weixin 导入微信开发者工具
vscode编译器配置: 目前vscode对TS类型支持友好
- 插件安装uni-app插件
安装uni-create-view插件
功能: 快速创建页面
安装uni-helper插件
功能: uniapp代码提示, ctrl + i
安装 uniapp小程序扩展 插件
功能: 鼠标悬停查看文档
- 配置ts类型校验
- 作用: 使用uniapp或微信组件时, 如果属性配置错误, 在编码阶段直接爆红, 开发效率更高
- 依赖安装: pnpm i -D @types/wechat-miniprogram @uni-helper/uni-app-types
{"compilerOptions": {... ..."types": ["@dcloudio/types", // 默认的TS类型文件"miniprogram-api-typings", //微信小程序组件类型增强文件"@uni-helper/uni-app-types", //uniapp组件类型增强文件]},"vueCompilerOptions": {// 配置vue的编辑器模式为uniapp// 已废弃,现调整为 nativeTags,请升级 Volar 插件至最新版本// experimentalRuntimeMode: "runtime-uni-app","nativeTags": ["block","component","template","slot"]},
}
- 解决json注释问题
- HBX中, 允许JSON文件中出现注释
- vscode中, JSON文件默认是严格JSON模式, 把JSON配置文件配置成jsonc模式, 就可以正确识别注释了
- uniapp中, 只有pages.json和manifest.json文件支持注释, 其他的json文件不要配置
基础架构
模版代码: git clone http://gititcast.cn/heimagianduan/erabbit-uni-app-vue3-ts.git heima-shop
安装依赖: pnpm install
配置appid:
{/* 小程序特有相关 */"mp-weixin" : {"appid" : "wxb161c259ad057faaaa","setting" : {"urlCheck" : false},"usingComponents" : true},
}
编译代码: pnpm dev:mp-weixin
运行代码: 微信小程序打开dist/dev/mp-weixin
安装uni-ui组件库, 并配置uni-ui组件的自动按需导入
{// 组件自动引入规则"easycom": {// 开启自动扫描"autoscan": true,// 以正则方式自定义组件匹配规则"custom": {// uni-ui 规则如下配置"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue",}},"pages": [... ...],
}
- 执行 pnpm i @dcloudio/uni-ui 命令安装组件库
- 自动导入原理: 当我们使用uni-cart 组件时, 由于组件名以 uni- 开头, 就会被custom规则匹配到, 把组件的名称提取出来, 然后交给$1变量读取, 拼接后是完整组件地址, 就能被引入到项目中
uni ui是基于JS开发的, 本身没有提供TS类型支持, 第三方社区开源了uni-ui的类型增强文件, 供我们使用
{"extends": "@vue/tsconfig/tsconfig.json","compilerOptions": {... ..."types": [// 默认的类型增强文件也是必须的"@dcloudio/types",// 添加安装的uni-ui类型增强文件"@uni-helper/uni-ui-types"]},"include": ["src/**/*.ts","src/**/*.d.ts","src/**/*.tsx",// 要确保包含使用uni组件的vue文件"src/**/*.vue"]
}
- 安装命令: pnpm i -D @uni-helper/uni-ui-types
- 安装配置完成后需要重启项目, 才能生效
状态管理: 基础代码中已经集成了pinia仓库, 我们只进行持久化配置就可以了
// 定义 Store
export const useMemberStore = defineStore('member',() => { },// 持久化配置{// 网页端配置// persist: true,// 小程序端配置persist: {storage: {setItem(key, value) {uni.setStorageSync(key, value)},getItem(key) {return uni.getStorageSync(key)},},},},
)
- 由于网页端和小程序使用不同的本地存储API, 所以持久化配置的方式略有不同
请求拦截器: 拦截request/uploadFile请求, 配置基地址,超时时间, 请求头表示和token
import { useMemberStore } from '@/stores'/*** 请求拦截*/// 封装请求
const baseURL = 'https://pcapi-xiaotuxian-front-devtest.itheima.net'// 请求拦截器
const httpInterceptor = {// 拦截前触发invoke(options: UniApp.RequestOptions) {// 1,非http开头需要拼接地址if (!options.url.startsWith('http')) {options.url = baseURL + options.url}// 2, 请求超时(10s)options.timeout = 10000// 3,添加小程序端请求头标识options.header = {...options.header,'source-client': 'miniapp',}// 4,添加tokenconst memberStore = useMemberStore()const token = memberStore.profile?.tokenif (token) {options.header.Authorization = token}},
}// 添加拦截器
uni.addInterceptor('request', httpInterceptor)
uni.addInterceptor('uploadFile', httpInterceptor)
请求函数: 二次封装uni.request函数, 对返回结果进行promise化
/*** 请求函数*/
// 接口(定义后台返回数据的类型)
interface Data<T> {code: stringmsg: stringresult: T
}export const http = <T>(options: UniApp.RequestOptions) => {// 1,返回Promise对象return new Promise<Data<T>>((resolve, reject) => {uni.request({...options,// 响应成功(uni.requres中只要服务器有响应,就执行success回调)success(res) {if (res.statusCode >= 200 && res.statusCode < 300) {// 2,成功resolve(res.data as Data<T>)} else if (res.statusCode === 401) {// 清理用户信息,调整到登录页const memberStore = useMemberStore()memberStore.clearProfile()uni.navigateTo({url: '/pages/login/login',})reject(res)} else {// 其他错误uni.showToast({title: (res.data as Data<T>).msg || '请求错误',icon: 'none',})reject(res)}},fail(err) {// 3,失败uni.showToast({title: '请求失败,换个网络试试',icon: 'none',})reject(err)},})})
}
- uni.request函数的sucess成功回调, 只要服务有响应就会执行, 我们需要对状态码进行更准确的判断
- 如果状态码是401就跳转到登录页, 如果是其他错误就展示后台返回的错误信息
- 如果网络出现问题, 服务器不会响应, 就会触发fail失败回调, 提示网络错误就行了
首页导航栏
安全区域: 通过 uni.getSystemInfoSync() 方法获取不同机型导航栏的安全距离
准备导航栏组件, 使用导航栏组件
<script setup lang="ts">
// 获取屏幕边界到安全区域距离
const { safeAreaInsets } = uni.getSystemInfoSync()
</script><template><view class="navbar" :style="{ paddingTop: safeAreaInsets!.top + 10 + 'px' }"><!-- logo文字 --><view class="logo"><image class="logo-image" src="@/static/images/logo.png"></image><text class="logo-text">新鲜 · 亲民 · 快捷</text></view><!-- 搜索条 --><view class="search"><text class="icon-search">搜索商品</text><text class="icon-scan"></text></view></view>
</template><style lang="scss">
/* 自定义导航条 */
.navbar {background-image: url(@/static/images/navigator_bg.png);background-size: cover;position: relative;display: flex;flex-direction: column;padding-top: 20px;.logo {display: flex;align-items: center;height: 64rpx;padding-left: 30rpx;.logo-image {width: 166rpx;height: 39rpx;}.logo-text {flex: 1;line-height: 28rpx;color: #fff;margin: 2rpx 0 0 20rpx;padding-left: 20rpx;border-left: 1rpx solid #fff;font-size: 26rpx;}}.search {display: flex;align-items: center;justify-content: space-between;padding: 0 10rpx 0 26rpx;height: 64rpx;margin: 16rpx 20rpx;color: #fff;font-size: 28rpx;border-radius: 32rpx;background-color: rgba(255, 255, 255, 0.5);}.icon-search {&::before {margin-right: 10rpx;}}.icon-scan {font-size: 30rpx;padding: 15rpx;}
}
</style>
<script setup lang="ts">
import CustomNavbar from './components/CustomNavbar.vue'</script><template><!-- 自定义导航组件 --><CustomNavbar />
</template>
隐藏首页的默认导航栏
{"pages": [{"path": "pages/index/index","style": {"navigationStyle": "custom", // 隐藏默认导航"navigationBarTextStyle": "white","navigationBarTitleText": "首页"}},],
}
实现效果