tsconfig.json
“This is the 20th day of my participation in the First Challenge 2022. For details: First Challenge 2022”
TypeScript configuration files when compiled to JavaScript
{
// Compile the configuration
"compilerOptions": {
// Object code - compiled code using esNext syntax
"target": "esnext".// The modularity scheme that the object code needs to use -- the compiled code uses esNext modularity
"module": "esnext".// Enable all strict modes
"strict": true.// What should be done to preserve JSX
"jsx": "preserve".// Auxiliary import function ---- If polyfill is used, use import instead of inserting directly into the file
"importHelpers": true.// Parse modules as Node does
"moduleResolution": "node".// Skip type checking for some libraries (e.g. Axios, etc.)
// 1. Improve performance 2. Avoid collisions in multiple libraries with the same type
"skipLibCheck": true.// The following two options are usually used together
// The purpose is to make ESM and CJS interchangeable
"esModuleInterop": true."allowSyntheticDefaultImports": true.// Create a mapping file (ts -> js)
"sourceMap": true.// Whether json modules can be parsed - that is, whether json files can be imported as a separate module
"resolveJsonModule": true.// The file path is the basic URL (that is, the file path is resolved based on the current path).
"baseUrl": ".".// Specify the type to be used for parsing
"types": ["webpack-env"].// Path resolution (similar to Webpack Alias) - to facilitate TS to resolve our own path alias
"paths": {
// Array indicates that multiple arrays can be configured, but generally one is sufficient
"@ / *": ["src/*"]."components/*": ["src/components/*"]},You can specify which library types can be used in a project
"lib": ["esnext"."dom"."dom.iterable"."scripthost"].// The default root path in vite is the project folder
// The default TSC root path is the system root path
// So we need to unify the compilation behavior of both
"paths": {
//./* -- The relative path is relative to the folder in which tsconfig.json is located
"/ *": [". / *"]}},// Those files need to be parsed by TS
"include": [
"src/**/*.ts"."src/**/*.tsx"."src/**/*.vue"."tests/**/*.ts"."tests/**/*.tsx"].// Those files do not need to be parsed by TS
For example, third-party libraries are introduced in a TS suffix file
// By default, imported third parties are type checked
// Sometimes this will cost performance, so exclude node_modules
// But TS will still do type resolution for the type we introduced, that is, the type we used
"exclude": ["node_modules"]}Copy the code
shims-vue.d.ts
By default, Typescript only parses TS files, not VUE SFC files, so you need to manually declare the types of SFC files
declare module '*.vue' {
// Introduce type DefineComponent
import { DefineComponent } from 'vue'
// Introduce an instance of the Component variable whose type is DefineComponent
const component: DefineComponent<{}, {}, any>
// Export the default type
export default component
}
Copy the code
normalize.css
By default, the interface has some default styles, such as 8px margin and padding
To prevent these default styles from impacting the project’S uI, we can use normalize.css to clear some of the browser’s default styles
The installation
> npm i normalize.css
Copy the code
main.ts
// use it globally
import 'normalize.css'
Copy the code
Use TS in Vuex
store/types.ts
export interface IRootState {
name: string
age: number
}
Copy the code
store/index.ts
import { createStore } from 'vuex'
import login from './login/login'
import { IRootState } from './types'
// Generics can be passed in when createStore is created - the generics correspond to the type of state
const store = createStore<IRootState>({
state() {
return {
name: 'Klaus'.age: 23}},modules: {
login
}
})
export default store
Copy the code
store/login/login.ts
import { Module } from 'vuex'
import { ILoginState } from './types'
import { IRootState } from '.. /types'
interface IAccount {
name: string.password: string
}
// Module is a data type that Vuex provides to represent submodules
// Two generics need to be passed -- required
// The first generic - the return type of the current module's state
// The second generic-the return value type of the root state
const loginModule: Module<ILoginState, IRootState> = {
namespaced: true.state() {
return {
token: ' '}},actions: {
async accountLoginAction({ commit }, payload: IAccount) {
/ /... This is where the asynchronous request logic for the login is placed}}}export default loginModule
Copy the code
Page login logic
Main logic
import { defineStore } from 'pinia'
import Cookies from 'js-cookie'
import router from '/src/router/index'
import { login, getUserInfo, getMenu } from '.. /.. /.. /api/login'
import { IAccount, ILoginType, IUserInfo } from './types'
import { IResponseType } from '.. /.. /.. /types'
interface IState {
token: string
userInfo: IUserInfo | null
menus: []}export default defineStore('loginStore', {
state: (a) :IState= > ({
token: ' '.userInfo: null.menus: []}),actions: {
async login(account: IAccount) {
// Log in to obtain the token
const { data } = await login<IAccount, IResponseType<ILoginType>>(account)
const { token, id } = data
this.$state.token = token
Cookies.set('token', token)
// Get user information after login
this.fetchUserInfo(id)
// Get the menu list that can be operated by the user after login
this.fetchMenu(id)
// Return to home page
router.push('/home')},async fetchUserInfo(id: number) {
const { data } = await getUserInfo<IResponseType<IUserInfo>>(id)
this.$state.userInfo = data
Cookies.set('userInfo'.JSON.stringify(data))
},
// There are two ways to get the dynamic menu
// 1. Use the user ID to go to the server to get the corresponding menu - the way used here
// 2. Define all route objects locally, obtain all accessible route objects based on the user's role, and register them dynamically
async fetchMenu(id: number) {
const { data } = await getMenu(id)
this.$state.menus = data
Cookies.set('menus'.JSON.stringify(data))
},
// Whether a user has logged in after refreshing is determined by the data stored in storage or cookie
// But because the user refreshes the interface, the state in vuex or Pinia is completely empty
// It needs to be reset
initStore() {
const token = Cookies.get('token')
const userInfo = Cookies.get('userInfo')
const menus = Cookies.get('menus')
if (token && userInfo && menus) {
/* eslint-disable no-param-reassign */
this.$patch(state= > {
state.token = token
state.userInfo = JSON.parse(userInfo ?? '{}')
state.menus = JSON.parse(menus ?? '{}')})}}}})Copy the code
api.ts
// Corresponding request API
// The API imported here is actually an instance object of AXIos
// So the corresponding get,post and other methods call the corresponding axios methods
// The corresponding generics are also passed to Axios
import api from '.. /utils/api'
Record
-- Generates a new object type, key of type K, value of type T
,>
// Record
-- equivalent to empty object
,>
export function login<T.R> (account: T) {
return api.post<T, R>('/login', account)
}
export function getUserInfo<R> (id: number) {
return api.get<R>(`/users/${id}`)}export function getMenu<R> (id: number) {
return api.get<R>(`/role/${id}/menu`)}Copy the code
./types.ts
export interface IAccount {
name: string
password: string
}
export interface ILoginType {
id: number
name: string
token: string
}
// The data types returned in the background are generally complex
// It is recommended to use json to ts for direct conversion.
interface Role {
id: number
name: string
intro: string
createAt: Date
updateAt: Date
}
interface Department {
id: number
name: string
parentId: number
createAt: Date
updateAt: Date
leader: string
}
export interface IUserInfo {
id: number
name: string
realname: string
cellphone: number
enable: number
createAt: Date
updateAt: Date
role: Role
department: Department
}
Copy the code
/src/type.ts
// A custom background return value type
The return value type varies from request to request, so it is up to the caller to determine the specific type
export interface IResponseType<T> {
code: number
data: T
}
Copy the code
main.ts
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import router from './router'
import App from './App.vue'
import { useLoginStore } from './store/index'
import 'normalize.css'
const app = createApp(App)
app.use(createPinia())
app.use(router)
// Call store.initstore () globally
// to ensure that every time the user refreshes the page
// The data in vuex or Pinia is effectively initialized
const store = useLoginStore()
store.initStore()
app.mount('#app')
Copy the code