unibest框架开发uniapp项目:兼容小程序问题

50 阅读2分钟

小程序运行发布

  • 运行:pnpm dev:mp-weixin,然后打开微信开发者工具,导入本地文件夹,选择本项的 dist/dev/mp-weixin 文件。
  • 发布:pnpm build:mp-weixin,打包后的文件在 dist/build/mp-weixin,然后通过微信开发者工具导入,并点击右上角的“上传”按钮进行上传。

注意:小程序审核如果项目需要登录,需要测试的账号和密码才能审核通过

常见问题:

可以先查看unibest中的常见问题中是否有总结:https://unibest.tech/base/14-faq

以下是我开发时遇到的相关问题:

1.运行小程序发现样式不生效

unibest框架使用的Ui组件库是[Wot Design Uni](https://wot-design-uni.netlify.app/),该组件如果是在小程序中使用外部样式类不能使用class应该要用custom-class

2.小程序中请求失败

uniapp使用的请求方式是uni.request(),如果是小程序使用请求,要配置responseType: 'json',否则请求是通的但是无法返回结果

uni.request({
  ...options,
  dataType: 'json',
  // #ifndef MP-WEIXIN
  responseType: 'json',
  // #endif

  // 响应成功
  success(res) {
     const resData = res.data as ResData<T> || {}
     // 正常状态码 2xx
     if (res.statusCode >= 200 && res.statusCode < 300) {
       resolve(resData)
     }
     else if (res.statusCode === 401) {
       reject(res.data)
     }
     else {
       reject(resData)
     }
  },
  // 响应失败
  fail(err) {
    // 网络错误提示
    toast.show('网络错误,请稍后再试')
    toast.loaded()
    reject(err)
  },
})
3.使用wotUI在组件中无法覆盖组件库样式

在自定义组件中使用 Wot UI 组件时,需开启styleIsolation: 'shared'选项

<wd-button type="primary">主要按钮</wd-button>

Vue 3.2 及以下版本可以使用如下配置开启styleIsolation: 'shared'选项:

<script lang="ts"> 
export default { 
  options: { 
    styleIsolation: 'shared' 
  }
} 
</script>
/* 组件样式 */ 
:deep(.wd-button) { 
  color: blue !important; 
}

Vue 3.3+ 可以通过defineOptions开启styleIsolation: 'shared'选项:

<script setup lang="ts">
defineOptions({
  options: {
    styleIsolation: 'shared',
  },
})
4.小程序中无法通过$router.getRoute()获取标题,获取pages.json的page配置做兼容
<script setup lang="ts">
import pagesJson from '@/pages.json'

const { title } = $router.getRoute()
const currentTitle = ref<string>(title)
function setTitle() {
  const { route } = $utils.currRoute() || {}
  currentTitle.value = pagesJson?.pages?.find((item: any) => item.path === route)?.style?.navigationBarTitleText || title || ''
}

onMounted(() => {
  /* #ifdef MP-WEIXIN */
  setTitle()
  /* #endif */
})
</script>

$utils.currRoute()的处理:

/** 主要是处理 arr.at(-1) 在安卓机上运行报错的 兼容性问题 */
export function getArrElementByIdx(arr: any[], index: number) {
  if (index < 0)
    return arr[arr.length + index]
  if (index >= arr.length)
    return undefined
  return arr[index]
}
/**
 * 解析 url 得到 path 和 query
 * 比如输入url: /pages/login/index?redirect=%2Fpages%2Fdemo%2Fbase%2Froute-interceptor
 * 输出: {path: /pages/login/index, query: {redirect: /pages/demo/base/route-interceptor}}
 */
function ensureDecodeURIComponent(url: string) {
  if (url.startsWith('%')) {
    return ensureDecodeURIComponent(decodeURIComponent(url))
  }
  return url
}
export function getUrlObj(url: string) {
  const [path, queryStr] = url?.split('?')

  const query: Record<string, string> = {}
  queryStr?.split('&').forEach((item) => {
    const [key, value] = item?.split('=')
    query[key] = ensureDecodeURIComponent(value) // 这里需要统一 decodeURIComponent 一下,可以兼容h5和微信y
  })
  return { path, query }
}

export const getLastItem = (arr: any[]) => getArrElementByIdx(arr, -1)
/**
 * 获取当前页面路由的 path 路劲和 redirectPath 路径
 * path 如 ‘/pages/login/index’
 * redirectPath 如 ‘/pages/demo/base/route-interceptor’
 */
export function currRoute() {
  const pages = getCurrentPages()
  const lastPage = getLastItem(pages)
  const currRoute = (lastPage as any).$page
  const { fullPath } = currRoute as { fullPath: string }
  return {
    ...getUrlObj(fullPath),
    route: lastPage?.route || '',
  }
}
5.小程序中使用自定义字体,不能直接引用本地的字体文件,需要使用在线的,目前项目中使用的是阿里巴巴矢量图标库
@font-face {
  font-family: 'AlimamaShuHeiTi';
  font-display: swap;
  // 本地字体地址
  // src: url('./fonts/AlimamaShuHeiTi.woff2') format('woff2');
  // 在线字体地址
  src:
    url('//at.alicdn.com/wf/webfont/rW8Dcsdy6laW/uB3biRkZ7u7W.woff2') format('woff2'),
    url('//at.alicdn.com/wf/webfont/rW8Dcsdy6laW/zqFrlMRoEcYX.woff') format('woff');
}