Skip to content

UNIBEST 使用 ​

修改配置文件 ​

找到 env>.env 文件

js
VITE_APP_TITLE = 'unibest' // title
VITE_APP_PORT = 9000 // 端口号

VITE_UNI_APPID = 'H57F2ACE4' // uni-app appid
VITE_WX_APPID = 'xxxxx' // 微信小程序appid

# h5部署网站的base,配置到 manifest.config.ts 里的 h5.router.base
VITE_APP_PUBLIC_BASE=/          // 路径前缀

VITE_SERVER_BASEURL = 'https://ukw0y1.laf.run'  // 数据请求地址
VITE_UPLOAD_BASEURL = 'https://ukw0y1.laf.run/upload'  // 数据上传地址

# h5是否需要配置代理
VITE_APP_PROXY=false
VITE_APP_PROXY_PREFIX = '/api'  // 代理前缀

增加分包配置 ​

  • 找到 vite.config.ts 文件

修改里面的 subPackages 目录

js
UniPages({
  exclude: ['**/components/**/**.*'],
  routeBlockLang: 'json5', // 虽然设了默认值,但是vue文件还是要加上 lang="json5", 这样才能很好地格式化
  // homePage 通过 vue 文件的 route-block 的type="home"来设定
  // pages 目录为 src/pages,分包目录不能配置在pages目录下
  subPackages: ['src/pages-sub', 'src/pages-sub2'], // 是个数组,可以配置多个,但是不能为pages里面的目录
  dts: 'src/types/uni-pages.d.ts',
}),
  • 在 pages 目录下创建 pages-sub 和 pages-sub2 目录

里面新建文件夹然后在新建 index.vue 文件

页面里面 ​

  • 组件部分要是组件名同文件名.可以不用引入直接使用(自动引入)

  • 钩子函数可以直接用

  • 默认支持 scss 插件

路由配置 ​

routeblock ​

  • 每个页面的开头都要加上 route-block
js
<route lang="json5" type="page">
  {
  layout: 'demo',
  style: {
    navigationStyle: 'custom',
    navigationBarTitleText:'首页',
    },
    needLogin: true,
    others: '哈哈哈哈',
   }
</route>
<template>
  xxxxxxxx
</template>
  • layout: 'demo' 是指使用哪个 layout,在 layouts 目录下

  • style: 是指当前页面的样式,可以配置 navigationBarTitleText,navigationStyle,backgroundColor 等

  • needLogin: 是否需要登录(写了这个属性路由验证那里就需要 token 验证)

  • others: 其他配置(随意)

路由拦截 ​

  • 第一步 先创建好pages/login/index.vue页面
vue
<script lang="ts" setup>
definePage({
  style: {
    navigationBarTitleText: "登录页面",
  },
});

function settoken() {
  uni.setStorageSync("token", { username: "张三", password: "12345" });
  // 如果有 redirect 参数,跳回原页面
  const pages = getCurrentPages();
  const currentPage = pages[pages.length - 1] as {
    options?: Record<string, string>;
  };
  const redirect = currentPage.options?.redirect;
  uni.reLaunch({
    url: redirect ? decodeURIComponent(redirect) : "/pages/index/index",
  });
}
</script>

<template>
  <view class="mt-10 text-center text-green-500">
    <button @click="settoken">登录</button>
  </view>
</template>
  • 第二步 改路由拦截器(核心)

把 src/router/interceptor.ts 改成这样:

ts
/**
 * 路由拦截,通常也是登录拦截
 */
import { getTabbarRedirectPath, tabbarStore } from "@/tabbar/store";
import { getLastPage, parseUrlToObj } from "@/utils/index";
import { useTokenStore } from "@/store/token";

export const FG_LOG_ENABLE = false;

// 登录页路径
const LOGIN_PAGE = "/pages/login/index";

// 不需要登录就能进的页面(白名单),至少要包含登录页本身,否则死循环
const NO_NEED_LOGIN_LIST = [LOGIN_PAGE];

export const navigateToInterceptor = {
  invoke({ url, query }: { url: string; query?: Record<string, string> }) {
    if (url === undefined) {
      return;
    }
    let { path, query: _query } = parseUrlToObj(url);
    const myQuery = { ..._query, ...query };

    // 处理相对路径(原有逻辑)
    if (!path.startsWith("/")) {
      const currentPath = getLastPage()?.route || "";
      const normalizedCurrentPath = currentPath.startsWith("/")
        ? currentPath
        : `/${currentPath}`;
      const baseDir = normalizedCurrentPath.substring(
        0,
        normalizedCurrentPath.lastIndexOf("/"),
      );
      path = `${baseDir}/${path}`;
    }

    // ===== 新增:登录校验 =====
    // 目标页不在白名单,且本地没有 token,就拦到登录页
    if (!NO_NEED_LOGIN_LIST.includes(path)) {
      const token = uni.getStorageSync("token");
      if (!token) {
        uni.reLaunch({
          url: `${LOGIN_PAGE}?redirect=${encodeURIComponent(url)}`,
        });
        return false; // 返回 false 表示阻止这次跳转
      }
    }
    // ===== 新增结束 =====

    // 原有:tabbar 角色越权兜底
    const redirectPath = getTabbarRedirectPath(path);
    if (redirectPath) {
      uni.reLaunch({ url: redirectPath });
      return false;
    }

    // 原有:修正 tabbar 高亮
    tabbarStore.setAutoCurIdx(path);
  },
};

export const routeInterceptor = {
  install() {
    uni.addInterceptor("navigateTo", navigateToInterceptor);
    uni.addInterceptor("reLaunch", navigateToInterceptor);
    uni.addInterceptor("redirectTo", navigateToInterceptor);
    uni.addInterceptor("switchTab", navigateToInterceptor);
  },
};
  • 第三步 处理首页拦不到的问题

仅仅在首页(src/pages/index/index.vue)的 onShow 里加:

ts
import { onShow } from "@dcloudio/uni-app";

onShow(() => {
  const token = uni.getStorageSync("token");
  if (!token) {
    uni.reLaunch({ url: "/pages/login/index" });
  }
});
  • 退出登录的地方:uni.removeStorageSync('token')。

  • 除了首页其他页面需要登录验证

html
<script lang="ts" setup>
  definePage({
    style: {
      navigationBarTitleText: "我的",
    },
    needLogin: true,
  });
</script>

Store ​

举例 在 store 文件夹下面 ​

  • 新增一个 count.ts
js
import { defineStore } from "pinia";
import { ref } from "vue";

export const useCountStore = defineStore(
  "countnum",
  () => {
    const countnumInfo = ref(0);

    const setCountnumInfo = (val: number) => {
      countnumInfo.value = val;
    };

    const clearCountnumInfo = () => {
      countnumInfo.value = 0;
    };
    return {
      countnumInfo,
      setCountnumInfo,
      clearCountnumInfo,
    };
  },
  {
    persist: true,
  }
);
  • 在 store 里面引入模块
js
import { createPinia } from "pinia";
import { createPersistedState } from "pinia-plugin-persistedstate"; // 数据持久化

const store = createPinia();
store.use(
  createPersistedState({
    storage: {
      getItem: uni.getStorageSync,
      setItem: uni.setStorageSync,
    },
  }),
);

export default store;

// 模块统一导出
export * from "./user";
export * from "./count";
  • 使用
js
<route lang="json5" type="page">
{
  layout: 'demo',
  style: {
    navigationStyle: 'custom',
    navigationBarTitleText: '首页',
  },
  needLogin: true,
  others: '哈哈哈哈',
}
</route>
<template>
  <view>我自己的页面</view>
  <wd-icon name="add-circle" class="text-green" color="red" size="32"></wd-icon>
  <view class="text-green">{{ store.countnumInfo }}</view>
  <wd-button type="success" @click="createadd">点击改变</wd-button>
  <wd-button type="success" @click="delall">点击删除</wd-button>
  <button @click="gotourl">点击跳转</button>
</template>

<script setup lang="ts">
import { useCountStore } from '@/store'
const store = useCountStore()
onLoad((option) => {
  console.log(option)
  uni.hideTabBar({
    animation: false,
  })
})
const createadd = () => {
  store.setCountnumInfo(15)
}
const delall = () => {
  store.clearCountnumInfo()
}
const gotourl = () => {
  uni.switchTab({
    url: '/pages/index/index?id=16',
  })
}
</script>

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

自定义 tabbar ​

找到 src>pages.config.ts 文件 ​

  • list 里面写你自己的要定义的 tabbar
js
  tabBar: {
    custon: true,
    color: '#999999',
    selectedColor: '#018d71',
    backgroundColor: '#F8F8F8',
    borderStyle: 'black',
    height: '50px',
    fontSize: '10px',
    iconWidth: '24px',
    spacing: '3px',
    list: [
      {
        pagePath: 'pages/index/index',
        text: '首页',
      },
      {
        pagePath: 'pages/about/about',
        text: '关于',
      },
      {
        pagePath: 'pages/me/index',
        text: '听风',
      },
    ],
  },
  • 自己在 components>新建一个 CustomTabBar.vue 文件
js
<template>
  <wd-tabbar v-model="tabbar" @change="changeItem" fixed>
    <wd-tabbar-item title="首页" icon="home" :value="1"></wd-tabbar-item>
    <wd-tabbar-item title="关于" icon="cart" :value="2"></wd-tabbar-item>
    <wd-tabbar-item title="我的" icon="user" :value="3"></wd-tabbar-item>
  </wd-tabbar>
</template>

<script setup>
const tabbar = ref(0)

const changeItem = (index) => {
  tabbar.value = index.value
  console.log('点击了', index)
  if (index.value == 0) {
    uni.switchTab({
      url: '/pages/index/index',
    })
  }
  if (index.value == 1) {
    uni.switchTab({
      url: '/pages/about/about',
    })
  }
  if (index.value == 2) {
    uni.switchTab({
      url: '/pages/me/index',
    })
  }
}
</script>

<style lang="scss" scoped></style>
  • 在 list 那几个路径的页面里面引用,并且把原生隐藏
js
onLoad((options) => {
  uni.hideTabBar({
    animation: false,
  });
});