从零开始创建vue3项目,最简单版(2)

153 阅读2分钟

1.配置路由

新建router文件夹

文件夹内新建routes.ts, index.ts

//routes.ts  

import { RouteRecordRaw } from 'vue-router'

export const routes: Array<RouteRecordRaw> = [
  {
    path: '/',
    redirect: '/home',
    component: () => import('@/layout/index.vue'),
    children: [
      {
        path: 'home',
        component: () => import('@/views/home.vue'),
        meta: {
          title: '首页',
          keepAlive: true
        }
      },
      {
        path: 'mine',
        component: () => import('@/views/mine.vue'),
        meta: {
          title: '我的',
          keepAlive: true
        }
      }
    ]
  },
  {
    path: '/login',
    component: () => import('@/views/login.vue'),
    meta: {
      title: '登录',
      keepAlive: true
    }
  }
]

export default routes

先随便建几个页面一会用

  //懒加载形式

  compoennt: () => import('xx')
  

layout文件夹内是导航部分,说句题外话,实际上移动端页面包含底部导航也没有几个。

mata 是路由元信息, 里面可以随便放

这里的title到时候显示在nav-bar上, keepAlive用来配置当前页面是否缓存

 //index.ts 
import { createRouter, createWebHashHistory } from 'vue-router'
import routes from './routes'
import { useUserStore } from '@/store/modules/user'
//进度条
import NProgress from 'nprogress'

NProgress.configure({ showSpinner: false })

const router = createRouter({
  history: createWebHashHistory(),
  routes
})

//路由白名单
const whiteList = ['/login']

router.beforeEach(async (to, from, next) => {
  NProgress.start()

  const userStore = useUserStore()

  console.log('userStore.token', userStore.token, to.path);

  if (userStore.token) {
    if (to.path === '/login') {
      next({ path: '/' })
      NProgress.done()
    } else {
      next()
      NProgress.done()
    }
  } else {
    if (whiteList.includes(to.path)) {
      // 白名单
      next()
      NProgress.done()
    } else {
      next('/login')
      NProgress.done()
    }
  }
})

router.afterEach(() => {
  NProgress.done()
})

export default router

这里添加了路由守卫,因为是移动端,暂时没有加动态路由,后续也许不需要

路由守卫原理也很简单,是就是判断是否符合条件(token)然后跳转到相关页面,注意不要死循环就行

1.2 layout配置

// layout index.vue
<template>
  <van-nav-bar :title="$route.meta.title" />

  <div class="main-page">
    <RouterView v-slot="{ Component }" v-if="$route.meta.keepAlive">
      <keep-alive>
        <component :is="Component" :key="$route.path" />
      </keep-alive>
    </RouterView>
    <RouterView v-if="!$route.meta.keepAlive" :key="$route.path" />
  </div>

  <van-tabbar route>
    <van-tabbar-item replace to="/home" icon="home-o">首页</van-tabbar-item>
    <van-tabbar-item replace to="/mine" icon="friends-o">我的</van-tabbar-item>
  </van-tabbar>
</template>

<style scoped lang="scss">
.main-page {
  box-sizing: border-box;
  height: calc(100vh - 92px);
  overflow-y: scroll;
  overflow-x: hidden;
  padding-left: 30px;
  padding-right: 30px;
}
</style>

van-tabbar 直接使用的路由模式

2 配置pinia

pinia是干啥的应该都清楚...

src 下新建store文件夹

//store index.ts
import { createPinia } from 'pinia';

//持久化存储
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';

const store = createPinia();
store.use(piniaPluginPersistedstate);

export default store;

模块化配置的话,store文件夹下新增modules文件夹

//user.ts 

import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state: () => {
    return {
      user_token: ''
    }
  },
  getters: {
    token: (state) => state.user_token
  },
  actions: {
    setToken(token: string) {
      // 登录接口
      return new Promise((resolve, reject) => {
        this.user_token = token
        resolve(true)
      })
    }
  },
  persist: {
    key: 'user_token',
    // 默认为local
    storage: localStorage,
    paths: ['user_token']
  }
})

这里采用的是模拟从后台获取token,所以搞了一个promise

重点说一下persist

这个是持久化配置,key就是存储的key,storage可以选择sessionStorage或者localStorage

  //源码
  persist?: boolean | PersistedStateOptions | PersistedStateOptions[];

persist这里可以发挥一个boolean值,也可以返回一个对象,或者一个对象数组

//源码
interface PersistedStateOptions {
    /**
     * Storage key to use.
     * @default $store.id
     */
    key?: string;
    /**
     * Where to store persisted state.
     * @default localStorage
     */
    storage?: StorageLike;
    /**
     * Dot-notation paths to partially save state. Saves everything if undefined.
     * @default undefined
     */
    paths?: Array<string>;
    /**
     * Customer serializer to serialize/deserialize state.
     */
    serializer?: Serializer;
    /**
     * Hook called before state is hydrated from storage.
     * @default null
     */
    beforeRestore?: (context: PiniaPluginContext) => void;
    /**
     * Hook called after state is hydrated from storage.
     * @default undefined
     */
    afterRestore?: (context: PiniaPluginContext) => void;
    /**
     * Logs errors in console when enabled.
     * @default false
     */
    debug?: boolean;
}

在这里actions里有一个setToken方法,按照正常逻辑,应该在登录页面调用

import { useUserStore } from '@/store/modules/user'

import { useRouter } from 'vue-router'

const userStore = useUserStore()

const router = useRouter()

const handleLogin = async () => {
    // 实际上这里应该是username与password
    let data = await userStore.setToken('token')

    if (data) {
        router.push('/home')
    }

}

具体pinia怎么使用,直接看官方文档,解释的比较清晰,不用看其他人的一堆示例

插一句,css预处理使用的scss