每次上官网查阅资料就很累,所以从官网cv了点下来

常用中间件

Vue-Router 路由

https://router.vuejs.org/zh/guide/

安装

npm install vue-router@4
yarn add vue-router@4
pnpm add vue-router@4

使用

import { createRouter } from 'vue-router'

router.ts

路由一般配置在src/router/index.ts文件下

import { createMemoryHistory, createRouter } from 'vue-router'

import HomeView from './HomeView.vue'
import AboutView from './AboutView.vue'

const routes = [
  { path: '/', component: HomeView },
  { path: '/about', component: AboutView },
]

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

export default router

然后在src/main.ts中使用注册

// const app = createApp(App)
app.use(router)
// app.mount('#app')

在页面中使用

父元素

<template>
  <router-link to="/home">Home</router-link>
  <router-view />
</template>

在router.ts中注册

const routes = [{ path: '/path', component: Comp }]

如果嵌套

const routes = [
  {
    path: '/user/:id',    // 可以在{{ $route.params.id }}匹配到(string类型)
    component: User,
    children: [
      {
        // 当 /user/:id/profile 匹配成功
        // UserProfile 将被渲染到 User 的 <router-view> 内部
        path: 'profile',
        component: UserProfile,
      },
      {
        // 当 /user/:id/posts 匹配成功
        // UserPosts 将被渲染到 User 的 <router-view> 内部
        path: 'posts',
        component: UserPosts,
      },
    ],
  },
]

const routes = [
  {
    path: '/user/:id',
    component: User,  // 父组件component其实可以去掉
    // 请注意,只有子路由具有名称
    children: [{ path: '', name: 'user', component: UserHome }],
  },
]

导航守卫

不登陆不给看

const router = createRouter({ ... })

router.beforeEach((to, from) => {
  // ...
  // 返回 false 以取消导航
  return false
})

可以返回的值如下:

  • false: 取消当前的导航。如果浏览器的 URL 改变了(可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。

  • 一个路由地址: 通过一个路由地址重定向到一个不同的地址,如同调用 router.push(),且可以传入诸如 replace: truename: 'home' 之类的选项。它会中断当前的导航,同时用相同的 from 创建一个新导航。

router.beforeEach(async (to, from) => {
  if (!isAuthenticated && to.name !== 'Login') return { name: 'Login' }
  return false;
})

路由元信息

定义

const routes = [
  {
    path: '/posts',
    component: PostsLayout,
    children: [
      {
        path: 'new',
        component: PostsNew,
        // 只有经过身份验证的用户才能创建帖子
        meta: { requiresAuth: true },
      },
      {
        path: ':id',
        component: PostsDetail
        // 任何人都可以阅读文章
        meta: { requiresAuth: false },
      }
    ]
  }
]

使用

router.beforeEach((to, from) => {
  if (to.meta.requiresAuth && !auth.isLoggedIn()) {
    // 此路由需要授权,请检查是否已登录
    // 如果没有,则重定向到登录页面
    return {
      path: '/login',
      // 保存我们所在的位置,以便以后再来
      query: { redirect: to.fullPath },
    }
  }
})

ts声明类型(.d.ts)

// 这段可以直接添加到你的任何 `.ts` 文件中,例如 `router.ts`
// 也可以添加到一个 `.d.ts` 文件中。确保这个文件包含在
// 项目的 `tsconfig.json` 中的 "file" 字段内。
import 'vue-router'

// 为了确保这个文件被当作一个模块,添加至少一个 `export` 声明
export {}

declare module 'vue-router' {
  interface RouteMeta {
    // 是可选的
    isAdmin?: boolean
    // 每个路由都必须声明
    requiresAuth: boolean
  }
}

Pinia 状态存储

https://pinia.vuejs.org/zh/

又想全局存储登录用户的信息,又不想写规范点而不是单纯的export defult {} ,这个时候就需要状态存储

安装

npm install pinia
pnpm i pinia

# Vue 版本低于 2.7
npm i @vue/composition-api

创建实例(Vue3)

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

const pinia = createPinia()
const app = createApp(App)

app.use(pinia)
app.mount('#app')

定义store

文件一般保存在src/store/目录下(单一状态存储用index.ts命名即可)

import { defineStore } from 'pinia';

// 选项式 更容易使用
export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0
  }),

  getters: {
    func_a: (state) => state.count * 2,
    func_b(state) {},
  },

  actions: {
    increment(/* 这里当然可以加参数 */) {
      this.count++
    },
  },
})

// 组合式 更灵活和强大
export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  const doubleCount = computed(() => count.value * 2)
  function increment() { 
    count.value++
  }

  // 这里假定 `app.provide('appProvided', 'value')` 已经调用过
  const appProvided = inject('appProvided')
  return { count, doubleCount, increment, appProvided }
})

组合式api注意事项:

要让 pinia 正确识别 state,你必须在 setup store 中返回 state的所有属性。这意味着,你不能在 store 中使用**私有**属性。不完整返回会影响 SSRhttps://pinia.vuejs.org/zh/cookbook/composables.html,开发工具和其他插件的正常运行。

——pinia官网

使用store

<script setup>
import { storeToRefs } from 'pinia'
import { useCounterStore } from '@/stores/counter'
const store = useCounterStore()

const { name, doubleCount } = storeToRefs(store)
const { increment } = store
</script> 

<template> 
  <!-- 直接从 store 中访问 state -->
  <div>Current Count: {{ store.count }}</div>
</template>

你可以定义任意多的 store,但为了让使用 pinia 的益处最大化 (比如允许构建工具自动进行代码分割以及 TypeScript 推断),你应该在不同的文件中去定义 store

一旦 store 被实例化,你可以直接访问在 store 的 stategettersactions 中定义的任何属性。我们将在后续章节继续了解这些细节,目前自动补全将帮助你使用相关属性。

请注意,store 是一个用 reactive 包装的对象,这意味着不需要在 getters 后面写 .value。就像 setup 中的 props 一样,我们不能对它进行解构

为了从 store 中提取属性时保持其响应性,你需要使用 storeToRefs()。它将为每一个响应式属性创建引用。当你只使用 store 的状态而不调用任何 action 时,它会非常有用。请注意,你可以直接从 store 中解构 action,因为它们也被绑定到 store 上

state操作

  • 重置store.$reset()

  • 替换store.$patch({ count: 24 })

pinia插件

核心是pinia.use(xxx)

示例:

import { createPinia } from 'pinia'

// 创建的每个 store 中都会添加一个名为 `secret` 的属性。
// 在安装此插件后,插件可以保存在不同的文件中
function SecretPiniaPlugin() {
  return { secret: 'the cake is a lie' }
}

const pinia = createPinia()
// 将该插件交给 Pinia
pinia.use(SecretPiniaPlugin)

// 在另一个文件中
const store = useStore()
store.secret // 'the cake is a lie'

Pinia 插件是一个函数,可以选择性地返回要添加到 store 的属性。它接收一个可选参数,即 context

export function myPiniaPlugin(context) {
  context.pinia // 用 `createPinia()` 创建的 pinia。
  context.app // 用 `createApp()` 创建的当前应用(仅 Vue 3)。
  context.store // 该插件想扩展的 store
  context.options // 定义传给 `defineStore()` 的 store 的可选对象。
  // ...
}

然后用 pinia.use() 将这个函数传给 pinia

pinia.use(myPiniaPlugin)

插件只会应用于在 pinia 传递给应用后创建的 store,否则它们不会生效。

vue-i18n 国际化

https://vue-i18n.intlify.dev/

安装

npm i vue-i18n

作为vue插件

import { createApp } from 'vue'
import { createI18n } from 'vue-i18n'

const app = createApp({
  // something vue options here ...
})

const i18n = createI18n({
  // something vue-i18n options here ...
})
app.use(i18n)

app.mount('#app')

例子

App.vue

<script setup> 
import { useI18n } from 'vue-i18n'
const { t } = useI18n() 
</script>

<template>
  <h1>{{ $t("message.hello") }}</h1>
</template>

main.ts

const i18n = createI18n({
  legacy: false, // you must set `false`, to use Composition API
  locale: 'ja',
  fallbackLocale: 'en',
  messages: {
    en: {
      message: {
        hello: 'hello world'
      }
    },
    ja: {
      message: {
        hello: 'こんにちは、世界'
      }
    }
  }
})

组合包

// 1、创建中文语言包对象
const zh = {
  username: '用户名',
  email: '邮箱',
  mobile: '手机'
}
// 2、创建英文语言包对象
const en = {
  username: 'Username',
  email: 'Email',
  mobile: 'Mobile'
}

// 3、组合语言包对象
const messages = {
  zh,
  en
}

// 4、创建 VueI18n 实例,并为 messages 和 locale 属性赋值
const i18n = new VueI18n({
  messages,
  locale: 'en'
})

变量

定义

const messages = {
  en: {
    message: {
      hello: '{msg} world'
    }
  }
}

使用

<p>{{ $t('message.hello', { msg: 'hello' }) }}</p>

另一种方式:

const messages = {
  en: {
    message: {
      hello: '{0} world'
    }
  }
}

// <p>{{ $t('message.hello', ['hello']) }}</p>

结合v-html

<p v-html="$t('message.hello')"></p>