vue3+ts+pinia+unocss开发uniapp总结

580 阅读3分钟

项目的开发采用的是vscode,没有使用hbuildX开发。

1.请求封装

1.1拦截器封装,文件路径为@/src/interceptors/request.ts文件

/* eslint-disable no-param-reassign */
import qs from 'qs'
/* userStore中存储了token信息 */
import { useUserStore } from '@/store'

export type CustomRequestOptions = UniApp.RequestOptions & {
  query?: Record<string, any>
} & IUniUploadFileOptions // 添加uni.uploadFile参数类型

// 请求域名地址
const baseURL = import.meta.env.VITE_SERVER_BASEURL

// 拦截器配置
const httpInterceptor = {
  // 拦截前触发
  invoke(options: CustomRequestOptions) {
    // 接口请求支持通过 query 参数配置 queryString
    if (options.query) {
      const queryStr = qs.stringify(options.query)
      if (options.url.includes('?')) {
        options.url += `&${queryStr}`
      } else {
        options.url += `?${queryStr}`
      }
    }

    // 1. 非 http 开头需拼接地址
    if (!options.url.startsWith('http')) {
      options.url = baseURL + options.url
    }
    // 2. 请求超时
    options.timeout = 10000 // 10s
    // 3. 添加小程序端请求头标识
    options.header = {
      platform: 'mp-weixin', // 可选值与 uniapp 定义的平台一致,告诉后台来源
      ...options.header,
    }
    // 4. 添加 token 请求头标识
    const userStore = useUserStore()
    const { token } = userStore.userInfo as unknown as IUserInfo
    if (token) {
      options.header.Authorization = `Bearer ${token}`
    }
  },
}

export const requestInterceptor = {
  install() {
    // 拦截 request 请求
    uni.addInterceptor('request', httpInterceptor)
    // 拦截 uploadFile 文件上传
    uni.addInterceptor('uploadFile', httpInterceptor)
  },
}

1.2完整请求代码,包括普通请求和文件上传请求


export const http = <T>(options: CustomRequestOptions) => {
  // 1. 返回 Promise 对象
  return new Promise<IResData<T>>((resolve, reject) => {
    uni.request({
      ...options,
      dataType: 'json',
      // #ifndef MP-WEIXIN
      responseType: 'json',
      // #endif
      // 响应成功
      success(res) {
        // 状态码 2xx,参考 axios 的设计
        if (res.status === 200) {
          //将res.data返出去
          resolve(res.data as IResData<T>)
        } else if (res.status === 401) {
          // 状态码为401,清理用户信息
           userStore.clearUserInfo()
           //跳转到登录页
          uni.navigateTo({ url: '/pages/login/index' })
          reject(res)
        } else {
          // 其他错误根据后端错误信息进行提示
          uni.showToast({
            icon: 'none',
            title: (res.data as IResData<T>).msg || '请求错误',
          })
          reject(res)
        }
      },
      // 响应失败
      fail(err) {
        uni.showToast({
          icon: 'none',
          title: '网络错误,请检查网络',
        })
        reject(err)
      },
    })
  })
}

// uni.uploadFile封装
export const uniFileUpload = <T>(options: CustomRequestOptions) => {
  // 1. 返回 Promise 对象
  return new Promise<IResData<T>>((resolve, reject) => {
    uni.uploadFile({
      ...options,
      // 响应成功
      success(res) {
        // 状态码 2xx,参考 axios 的设计
        if (res.status === 200) {
          // 文件上传接口的rea.data的类型为string,这里转一下
          const resData = JSON.parse(res.data) as IResData<T>
          resolve(resData)
        } else if (res.status === 401) {
           // 状态码为401,清理用户信息
           userStore.clearUserInfo()
           //跳转到登录页
          uni.navigateTo({ url: '/pages/login/index' })
          reject(res)
        } else {
          // 其他错误 -> 根据后端错误信息轻提示
          uni.showToast({
            icon: 'none',
            title: '文件上传错误',
          })
          reject(res)
        }
      },
      // 响应失败
      fail(err) {
        uni.showToast({
          icon: 'none',
          title: '网络错误,请检查网络',
        })
        reject(err)
      },
    })
  })
}

2.路由跳转

uniapp跳转有五种方式

2.1 uni.navigateTo(保留当前页面,跳转到应用其他页面,可以通过uni.navigateBack返回到原页面。TODO:不能跳转tabBar页面)

传递的参数在onLoad:function(option){}//这个option就是传过来的参数

    uni.navigateTo({ url: `/pages/product/Detail?productId=${val.productId}&productName=${val.productName}` })

2.2 uni.navigateBack (关闭当前页面,返回上级页面或者多级页面,参数delta,必须为正整数)

可以通过getCurrentPages()方法获取页面栈,决定需要返回到哪一级,delta默认为1,返回到上一级,delta大于现有页面数,返回到首页

 /* 假设在3级页面使用navigateBack,则返回到第一级 */
  uni.navigateBack({ delta: 2 })

2.3 uni.redirectTo (关闭当前页面,跳转到其他页面,而uni.navigateTo是保留了当前页面)

  uni.redirectTo({ url: '/pages/product/Apply' })

2.4 uni.reLaunch(关闭所有页面,跳转到其他页面)

  uni.relaunch({ url: '/pages/product/Apply' })

2.5 uni.switchTab( 跳转tabBar页面专用,即导航栏之间的跳转,TODO:跳转前会关闭所有非导航栏页面)

  uni.switchTab({ url: '/pages/product/Apply' })

3.uniapp的tabbar自定义,TODO:uniapp选取的ui框架为wot-desgin-uni

3.1 page.json里面tabBar属性的custom设置为true

3.2 在components目录下新建一个自定义tabbar组件

<template>
  <wd-tabbar fixed v-model="tabbarStore.curIdx" bordered safeAreaInsetBottom placeholderuni @change="selectTabBar">
    <block v-for="(item, index) in tabbarList" :key="item.path">
      <wd-tabbar-item v-if="item.iconType === 'wot'" :icon="item.icon"></wd-tabbar-item>
      <wd-tabbar-item v-else-if="item.iconType === 'unocss' || item.iconType === 'iconfont'" :title="item.text">
        <template #icon>
          <view h-20 w-20 :class="[item.icon, index === tabbarStore.curIdx ? 'is-active' : 'is-inactive']"> </view>
        </template>
      </wd-tabbar-item>
      <wd-tabbar-item v-else-if="item.iconType === 'local'" :title="item.text">
        <template #icon>
          <image :src="item.icon" h-20 w-20 />
        </template>
      </wd-tabbar-item>
    </block>
  </wd-tabbar>
</template>

<script lang="ts" setup>
import { tabbarStore } from './tabbar'
import { tabBar } from '@/pages.json'
// unocss icon 默认不生效,需要在这里写一遍才能生效!注释掉也是生效的,但是必须要有!
// i-carbon-code
/* 将tabbar中list数据新增path属性 */
const tabbarList = tabBar.list.map((v: any) => ({ ...v, path: `/${v.pagePath}` }))
/* 切换tabbar时 TODO:function声明有变量提升*/
function selectTabBar({ value: index }: { value: number }) {
  console.log(tabbarList, index, 'cjc')
  const url = tabbarList[index].path
  tabbarStore.setCurIdx(index)
  uni.switchTab({ url })
}
onLoad(() => {
  //原生tabbar未隐藏导致出现两个tabbar
  // #ifdef  APP-PLUS | H5
  uni.hideTabBar({
    fail(error) {
      console.log('hideTabBar fail', error)
    },
    success(res) {
      console.log('hideTabBar success', res)
    },
  })
})
</script>

<style lang="scss" scoped>
//
</style>

3.3 创建layout布局


<template>
  <wd-config-provider :themeVars="themeVars">
    <slot />
    <xt-tabbar />
    <wd-toast />
    <wd-message-box />
  </wd-config-provider>
</template>

<script lang="ts" setup>
import type { ConfigProviderThemeVars } from 'wot-design-uni'
const themeVars: ConfigProviderThemeVars = {
  colorTheme: 'red',
  buttonPrimaryBgColor: '#07c160',
  buttonPrimaryColor: '#07c160',
}
</script>

<style lang="scss" scoped></style>

3.4 tabbar的页面设置layout:'tabbar'

4.设置导航栏隐藏

"pages": [
    {
      "path": "pages/index/index",
      "type": "home",
      "layout": "tabbar",
      "style": {
        "navigationBarTitleText": "首页",
        //第一种
        "navigationStyle": "custom",
        // 第二种
        "app-plus": {
          "titleNView":false
        }
      }
    }
   ]
   // 获取屏幕边界到安全区域距离
   const { safeAreaInsets } = uni.getSystemInfoSync()
   safeAreaInsets对象有四个属性top,bottom,left,right

5.uniapp 小程序支持分享微信和朋友圈

5.1首先导入onShareAppMessage(分享微信朋友),onShareTimeLine(分享朋友圈)

import { onShareAppMessage, onShareTimeline } from '@dcloudio/uni-app'

5.2 完善方法参数给定

/** 激活“分享给好友” */
onShareAppMessage((options: Page.ShareAppMessageOption): Page.CustomShareContent => {
  console.log('options:', options)
  return {
    title: '这个是微信小程序',
    desc: '采用unipp开发',
    path: '/pages/index/index?id=xxx',
  }
})
/** 激活“分享到朋友圈”, 注意:需要先激活“分享给好友” */
onShareTimeline((): Page.ShareTimelineContent => {
  return {
    title: '自定义分享标题',
    query: 'a=1&b=2',
  }
})

6.页面跳转navigator 类似html中的a标签

1722242680711.jpg

1722242746160.jpg

7.uniapp判断浏览器还是app

const type = uni.getSystemInfoSync().uniPlatform
console.log(type) // app就是app  web就是浏览器

8.uniapp判断平台判断,微信小程序、H5、app

8.1 html进行判断

 
MP:小程序
           <!-- #ifdef MP -->
            <view> 小程序端 </view>
            <!-- #endif -->
H5:H5端
            <!-- #ifdef H5 -->
            <view> H5端 </view>
            <!-- #endif -->
APP:APP端
            <!-- #ifdef APP-PLUS -->
            <view> APP端 </view>
            <!-- #endif -->

8.2 ts或者js中判断

MP:小程序
            /*#ifdef MP*/
            console.log('微信小程序端')
            /*#endif*/
H5:H5端
            /*#ifdef H5*/
            console.log('H5端')
            /*#endif*/ 
            
APP:APP端
            /*#ifdef APP-PLUS*/
            console.log('APP端')
            /*#endif*/
 

8.3 css判断

MP:小程序
            /*#ifdef MP*/
            top:0;
            /*#endif*/ 
H5H5/*#ifdef H5*/
            top:88rpx;
            /*#endif*/
APP:APP端
            /*#ifdef APP-PLUS*/
            top:0;
            /*#endif*/

9.获取系统信息uni.getSystemInfoSync

1723428805732.jpg

uniapp跳转 navigator标签类似标签

1723454522595.jpg

10.获取微信小程序胶囊位置信息uni.getMenuButtonBoundingClientRect()

1723514312887.jpg

10.自定义工具类全局注册

10.1 在App.vue注册全局工具类

  <script>
  import utilsFunc  from './utils/index.ts'
    export default {
      onLaunch() {
        console.log('App Launch')
      },
      onShow() {
        console.log('App Show')
      },
      onHide() {
        console.log('App Hide')
      },
      globalData(){
        utils:utilsFunc
      }
    }
</script>

10.2 使用页面

    const app = getApp()
    onLoad(() => {
      getUserInfo()
       /*调用工具类方法*/
      app.globalData.utils.currRoute()
    })

11.不同页面之间数据传递

在使用数据页面进行监听uni.$on
传递页面$emit

12.微信小程序里面回去用户地址信息

    uni.chooseAddress({
    success: (res) => {
      console.log(res, 'success')
    },
    fail: (res) => {
      console.log(res, 'error')
    },
  })

同时需要在manifest.json里微信小程序模块进行配置

    'mp-weixin': {
        appid: VITE_WX_APPID,
        setting: {
          urlCheck: false,
        },
        usingComponents: true,
        /* 获取地理位置信息配置 */
        requiredPrivateInfos: [
          'getLocation',
          'onLocationChange',
          'startLocationUpdateBackground',
          'chooseAddress',
        ],
        // __usePrivacyCheck__: true,
  },

13.设置navBartitle

    onLoad(() => {
      /* 设置navBar文字 */
      uni.setNavigationBarTitle({
        title: '我爱cc',
      })
    })

14.小程序开发图表ucharts

官方地址

15.生成全端二维码

uqrcode

16.tabbar切换时走的是v-show逻辑,因此刷新页面需要在页面周期函数onShow执行

17.拨打电话

     uni.makePhoneCall({
        phoneNumber: phone.value,
      })

时间戳和hh:mm:ss

    时分秒时间戳 -> hh:mm:ss
    times(data) {

      var time = Number(data);

      var h = Math.floor(time / 3600);

      var m = Math.floor((time % 3600) / 60);

      var s = parseInt(time % 3600) % 60;

      var hh = h < 10 ? "0" + h : h;

      var mm = m < 10 ? "0" + m : m;

      var ss = s < 10 ? "0" + s : s;

      return hh + ":" + mm + ":" + ss;

    },

   hh:mm:ss -> 时分秒时间戳

    time_to_sec(time) {

      if (time !== null) {

        var s = "";

        var hour = time.split(":")[0];

        var min = time.split(":")[1];

        var sec = time.split(":")[2];

        s = Number(hour * 3600) + Number(min * 60) + Number(sec);

        return s;

      }

    },