开场白: 要是在 vscode 书写代码, 需要添加 几个插件来支持 uni-app
npx degit dcloudio/uni-preset-vue#vite-ts my-vue3-project
运行命令: pnpm dev:mp-weixin,会生成dist 文件目录,导入到微信开发者工具查看
官网地址:uni-app 官网 使用uni-ui
npm i @dcloudio/uni-ui 或 yarn add @dcloudio/uni-ui
// pages.json
{
// 自动导包配置
"easycom": {
"autoscan": true,
"custom": {
// uni-ui 规则如下配置
"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue"
}
},
// 其他内容
pages:[
// ...
]
}
uni-helper/uni-ui-types
后面的所有的点击事件对象都可以用 UniHelper 提供的类型
<swiper @change="onChange">
<swiper-item>...</swiper-item>
<swiper-item>...</swiper-item>
</swiper>
// js
const onChange: UniHelper.SwiperOnChange = (event) => {
// UniHelper.SwiperOnChange 这样 event 里面的所有的类型都有了
}
pnpm i -D uni-helper/uni-ui-types
在 tsconfig.json 文件中 compilerOptions 配置上
"compilerOptions": {
"allowJs": true,
"sourceMap": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
},
"lib": ["esnext", "dom"],
"types": [
"@dcloudio/types",
"miniprogram-api-typings",
"@uni-helper/uni-app-types",
"@uni-helper/uni-ui-types" // 配置的uni-ui类型,书写标签时,鼠标划上之后有代码提示
]
},
pinia 的使用和 vue3 一样 pinia配置,只是持久化的时候需要改一下
// TODO: 持久化
{
persist: {
storage: {
getItem(key) {
return uni.getStorageSync(key)
},
setItem(key, value) {
uni.setStorageSync(key, value)
},
},
},
},
utils包里面创建 http.ts 文件
// http.ts
import { useMemberStore } from '@/stores' // store 取 token
const baseUrl = 'https://pcapi-xiaotuxian-front-devtest.itheima.net'
// 拦截器
const httpInterceptor = {
// 拦截前触发
invoke(options: UniApp.RequestOptions) {
options.url = baseUrl + options.url
options.timeout = 10000
options.header = {
...options.header,
'source-client': 'miniapp',
}
const memStore = useMemberStore()
const token = memStore.profile?.token
if (token) {
options.header.Authorization = token
}
},
}
// 添加 request 请求拦截 和 文件上传拦截
uni.addInterceptor('request', httpInterceptor)
uni.addInterceptor('uploadFile', httpInterceptor)
// 封装响应
interface Data<T> {
code: string
message: string
result: T
}
export const http = <T>(options: UniApp.RequestOptions) => { // http 函数接受 泛型,由调用 http 函数地方传进来
return new Promise<Data<T>>((resolve, reject) => { // Promise 响应数据进行泛型约束,Data 在上面定义好了,只有 result 类型会变化,所以从 http 函数调用者传进来
uni.request({
...options,
success(response) {
if (response.statusCode >= 200 && response.statusCode < 300) {
resolve(response.data as Data<T>)
} else {
uni.showToast({ icon: 'none', title: '请求错误' })
reject(response)
}
},
fail(err) {
uni.showToast({ icon: 'none', title: '服务器异常' })
reject(err)
},
})
})
}
在 api / index.ts 目录下
import { http } from '@/utils/http'
/**
* 首页轮播图
* @param distributionSite 区分首页还是分类页面
* @returns promise
*/
export const getHomeBannerAPI = (data: Banner ) => {
return http<BannerItem[]>({
url: '/home/banner',
method: 'GET',
data
})
}
在组件中正常使用就好了
<Son ref='sonComponent' />
const sonComponent = ref<InstanceType<typeof Son>>() // typeof xxx 组件类型 InstanceType 获取的是实例类型
sonComponent.value.getMore // 父组件拿到子组件的属性和方法
子组件需要暴露出来(vue3中)
defineExpose({
getMore: getGuessData // 前面定义的名字,让父组件拿到, 后面是子组件中的属性和方法
})
// 分页参数
const params = {
currrentPage: 1,
pageSize: 10
}
// 定义的数组
const tableDataList = ref([])
// 是否加载完数据
const isFinish = ref(false)
// 加载中状态
let isLoading = false
// 页面和加载更多方法
const getDataList = async (params) => {
if(isLoading || isFinish.value) return // 加载中或者数据没有加载完, 都不进行请求数据
isLoading = true // 请求数据制成 true
const res = await API(params)
tableDataList.value = [...tableDataList.value, res.result.list] // 数据拼接
isLoading = false // 数据回来,加载中的状态制成 false
// 判断要是当前的页码大于等于列表数据的总页码,停止加载(数据加载完了)
if(params.currentPage >= res.result.pages) {
isFinish.value = true // 数据加载完了
return uni.showToast({title: "数据加载完了", icon: "none"})
}
params.currentPage++ // 加载下一页的数据
}