vue3 + vite + TS + vue-router + vuex + less + 组合式API + 多语言vue-i18n
vue3安装
安装最新稳定版
$ npm install vue@next
用vite创建项目
vite不需要单独安装
npm init vite-app my_project
cd my_project
npm install
npm run dev
// 浏览器中打开localhost:3000,即可看到启动的项目
TypeScript配置
vue3+vite+ts在配置过程中会报错,找不到App.vue模块相应的类型声明,等配置完成即可解决。
- /src/main.js,重命名为/src/main.ts
- /src/index.html,引入的main.js,改成main.ts
- /src/App.vue,<script> 修改为 <script lang="ts">
- 安装TypeScript
$ npm install -D typescript
根目录创建ts配置文件:tsconfig.json,并修改配置为
{
"compilerOptions": {
// TypeScript 默认会把代码编译为 ECMAScript 3
// esnext 表示仅仅校验转换 TypeScript 类型,不进行语法编译
"target": "esnext",
"module": "esnext",
// 开启严格模式,这使得对“this”的数据属性进行更严格的推断成为可能
"strict": true,
"jsx": "preserve",
"moduleResolution": "node",
"paths": {
"/@/*": [
"./src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"src/types/images.d.ts",
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": [
"node_modules"
]
}
- 添加类型声明文件
用来解决前面所说的报错
创建文件:/src/shims-vue.d.ts,并修改配置
// /src/shims-vue.d.ts
declare module '*.vue' {
// Vue 3
import { defineComponent } from 'vue'
const Component: ReturnType<typeof defineComponent>
export default Component
}
6 build时添加tsc校验
/package.json,修改scripts.build的值为tsc --noEmit && vite build
"build": "tsc --noEmit && vite build"
ts配置完成
路径别名设置
根目录vite配置文件,
// vite.config.js
import {resolve} from "path";
export default {
alias: {
'/@/': resolve(__dirname, 'src'),
'/@styles/': resolve(__dirname, 'src/assets/styles'),
'/@components/': resolve(__dirname, 'src/components'),
'/@pages/': resolve(__dirname, 'src/pages'),
'/@store/': resolve(__dirname, 'src/store'),
},
};
// tsconfig.json
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "es5",
/* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */
"module": "commonjs",
/* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
// "lib": [], /* Specify library files to be included in the compilation. */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
// "outDir": "./", /* Redirect output structure to the directory. */
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true,
/* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
"baseUrl": "./",
/* Base directory to resolve non-absolute module names. */
"paths": {
"/@/*": [
"src/*"
],
"/@styles/*": [
"src/assets/styles/*"
],
"/@pages/*": [
"src/pages/*"
],
"/@components/*": [
"src/components/*"
],
"/@store/*": [
"src/store/*"
]
},
/* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true,
/* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
/* Advanced Options */
"skipLibCheck": true,
/* Skip type checking of declaration files. */
"forceConsistentCasingInFileNames": true
/* Disallow inconsistently-cased references to the same file. */
},
"include": [
"src/**/*.ts",
"src/**/*.d.ts",
"src/**/*.tsx",
"src/**/*.vue",
"src/**/*.less"
],
"exclude": [
"node_modules"
]
}
路由配置vue-router
采用模块化路由配置
- 安装路由
npm install vue-router@4
- 创建页面目录pages与页面文件a.vue,b.vue
script中加入lang='ts'
// a.vue
<template>
<div>page-a</div>
</template>
<script lang="ts">
export default {
name: "a"
}
</script>
<style scoped>
</style>
// b.vue
<template>
<div>page-a</div>
</template>
<script lang="ts">
export default {
name: "b"
}
</script>
<style scoped>
</style>
- 创建路由文件/router.ts
import {createRouter, createWebHistory} from "vue-router";
// 懒加载:component的值是函数
const routes = [
{path: '/', component: () => import('./pages/a.vue')},
{path: '/b', component: () => import('./pages/b.vue')}
]
const router = createRouter({
history: createWebHistory(),
routes,
// 切换页面后,返回顶部
scrollBehavior() {
return {top: 0}
}
});
// 权限检查
function canUserAccess(){
return new Promise(resolve => {
return resolve(true)
})
}
router.beforeEach(async (to, from,next) => {
// 获取菜单、用户信息、调用store等异步操作
// 检查权限,true继续,false进入登录
let isAllow = await canUserAccess()
isAllow ? next() : next({name:'login'})
})
export default router;
- 挂载到vue
修改/main.ts
import { createApp } from 'vue'
import router from './router'
import App from './App.vue'
import './index.css'
const app = createApp(App);
app.use(router)
app.mount('#app')
状态管理器配置vuex
- 安装
npm install vuex@next
- 创建文件
- /src/store/index.ts
*/src/store/modules/users.store.ts
````js
// /src/store/index.ts
import {createStore, useStore as baseUseStore, Store} from "vuex";
import {InjectionKey} from 'vue'
export interface State {
count: number,
name: string
}
export const key: InjectionKey<Store<State>> = Symbol();
const state = {
count: 0,
name: 'cq'
}
const getters = {
name1(state: State) {
return state.name
}
}
const mutations = {
increase(state:State){
state.count++
}
}
const actions = {
// @ts-ignore
add({commit}){
commit('increase');
}
}
export const store = createStore<State>({
state,
getters,
mutations,
actions,
})
export function useStore() {
return baseUseStore(key)
}
// /src/store/modules/users.store.ts
interface IState {}
const state:IState = {}
const getters = {}
const mutations = {}
const actions = {}
export default {
state,
getters,
mutations,
actions
}
- 修改main
import { createApp } from 'vue'
import router from './router'
import {store,key} from './store/index'
import App from './App.vue'
import './index.css'
const app = createApp(App);
app.use(router)
app.use(store,key)
app.mount('#app')
Less
- 安装
npm install less less-loader --dev
- style标签加入lang=less
<style lang='less'></style>
未解决的问题:
同一个文件使用@import导入两个文件,第二个失效
多语言vue-i18n
1. 安装
npm install vue-i18n@next
2. 创建目录、文件
- /src/language/zh.language/index.ts
中文语言包的输出文件
- /src/language/zh.language/modules/home-page.language.ts
将内容通过模块划分,一个模块一个文件
- /src/language/en.language/index.ts
- /src/language/en.language/modules/home-page.language.ts
- /src/language/index.ts
整个语言包的输出文件
// /src/language/zh.language/index.ts
import home_page from './modules/home-page.language'
export default {
example: '语言包示例',
home_page
}
// /src/language/zh.language/modules/home-page.language.ts
export default {
title:'首页',
// 一个component一个对象
navs:{
list:[],
name:'nav list'
},
}
// /src/language/zh.language/modules/home-page.language.ts
import home_page from './modules/home-page.language'
export default {
example: 'language package example',
home_page
}
// /src/language/en.language/modules/home-page.language.ts
export default {
title:'home page',
navs:{
list:[],
name:'nav list'
}
}
// /src/language/index.ts
import {createI18n} from "vue-i18n";
import zh from './zh.language/index'
import en from './en.language/index'
const messages = {zh, en}
// 判断当前浏览器是哪种语言
const language = (
(navigator.language
? navigator.language
// @ts-ignore
: navigator.userLanguage)
|| 'zh'
).toLowerCase();
const i18n = createI18n({
fallbackLocale: 'zh',
globalInjection: true,
legacy: false,
locale: language.split("-")[0] || 'zh',
messages
})
export default i18n;
3. 引入vue
在mian.ts中引入语言包
import i18n from "/@/language/index";
app.use(i18n);
4. vue页面中使用
<div>
{{$t(`example`)}}
{{$t(`home_page.title`)}}
</div>
多语言配置完成