从0到1搭建一个后台管理项目

998 阅读3分钟

运用了ts、vite、vue3、其中有axios拦截器、路由、vuex、elementUI

1. 使用vite 不用vue create了,他直接就使用什么框架了

npm init @vitejs/app
cd ./vite-project
npm install
npm run dev

2.配置stylelint

npm install stylelint-config-standard stylelint-order --save-dev

创建文件 stylelint.config.js

module.exports = {
  processors: [],
  plugins: [],
  extends: ['stylelint-config-standard', 'stylelint-config-recess-order', 'stylelint-config-css-modules'], // 这是官方推荐的方式
  rules: {
    'indentation': null, // 缩进,可以设置int类型的数字,也可以设置"tab"
    'comment-whitespace-inside': 'always',
    'no-descending-specificity': null, // 优先级规则,禁用
    'no-empty-source': null, // 是否可以为空,禁用
    'declaration-block-trailing-semicolon': null, // 结尾是否必须要分号,禁用
    'at-rule-no-unknown': [true, {
      'ignoreAtRules': [
        'extend',
        'at-root',
        'debug',
        'warn',
        'error',
        'if',
        'else',
        'for',
        'each',
        'while',
        'mixin',
        'include',
        'content',
        'return',
        'function'
      ]
    }], // 排除的部分规则,支持 SCSS 语法中的语法
    'selector-pseudo-class-no-unknown': [true, {
      'ignorePseudoClasses': 'deep'
    }],
    'selector-pseudo-element-no-unknown': [true, {
      'ignorePseudoElements': ['deep']
    }]
  }
}

3. 在vite环境下,按需引入elemen-UI

npm install element-plus --save
npm i vite-plugin-style-import -D
npm i unplugin-vue-components -D
// vite.config.ts

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'


// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    Components({
      resolvers: [ElementPlusResolver()],
    })
  ],
})
// main.ts
import { components, plugins } from './element-plus'
const app = createApp(App)
components.forEach((com: any) => {
  app.component(com.name, com)
})
plugins.forEach((plugin) => {
  app.use(plugin)
})

新建element-plus文件夹>index.ts

// element-plus组件按需引入
import {
  ElButton,
  ElSelect,
  ElMessage,
  ElMessageBox,
  ElTooltip,
  ElOption,
  ElColorPicker,
  ElSlider,
  ElInput,
  ElDialog,
  ElPopover,
  ElScrollbar,
  ElDrawer,
  ElTabs,
  ElTabPane,
  ElContainer,
  ElAside,
  ElMenu,
  ElMenuItem,
  ElMenuItemGroup,
  ElTable,
  ElTableColumn,
  ElImage,
  ElCard,
  ElBreadcrumb,
  ElUpload,
  ElDropdown,
  ElDropdownMenu,
  ElDropdownItem,
  ElBadge,
  ElEmpty,
  ElLoading
} from 'element-plus'
import 'element-plus/dist/index.css'
export const components = [
  ElButton,
  ElSelect,
  ElTooltip,
  ElOption,
  ElColorPicker,
  ElSlider,
  ElInput,
  ElDialog,
  ElPopover,
  ElScrollbar,
  ElDrawer,
  ElTabs,
  ElTabPane,
  ElContainer,
  ElAside,
  ElMenu,
  ElMenuItem,
  ElMenuItemGroup,
  ElTable,
  ElImage,
  ElCard,
  ElBreadcrumb,
  ElUpload,
  ElDropdown,
  ElDropdownMenu,
  ElDropdownItem,
  ElBadge,
  ElEmpty,
  ElLoading
]

export const plugins = [
  ElMessage,
  ElMessageBox,
  ElTableColumn,
]

4. 配置路由

npm i vue-router@next -D

新建router文件夹> index.ts

import { createRouter, createWebHashHistory } from 'vue-router'
import Home from '@/comments/HelloWorld.vue'

const Router = createRouter({
  history: createWebHashHistory(),
  routes: [{
    path: '/',
    name: 'home',
    component: Home
  }]
})

export default Router

报错:vite找不到@,他不认为这个是根目录

npm install @types/node --save-dev

vite.config.ts

import { resolve } from 'path'

const pathResolve = (dir: string): any => {
  return resolve(__dirname, '.', dir)
}
const alias: Record<string, string> = {
  '@': pathResolve('src/'),
}
export default defineConfig({
  plugins: [
    vue(),
    Components({
      resolvers: [ElementPlusResolver()],
    })
  ],
  resolve: { alias }
})

5. vuex

npm i vuex@next -D

store文件夹>index.ts

import { createStore } from 'vuex'

const store = createStore({
  state: {
  },
  getters: {
  },
  mutations: {
  },
  actions: {
  },
  modules: {
  }
})
export default store

main.ts

import store from './store'
import router from './router'
app.use(router)
app.use(store)

6.scss

npm install -D sass-loader node-sass

7.axios和拦截器

npm install axios -S

配置代理 新建文件夹 utils>storage.ts

/**
 * window.localStorage 浏览器永久缓存
 * @method set 设置永久缓存
 * @method get 获取永久缓存
 * @method remove 移除永久缓存
 * @method clear 移除全部永久缓存
 */
 export const Local = {
	// 设置永久缓存
	set(key: string, val: any) {
		window.localStorage.setItem(key, JSON.stringify(val))
	},
	// 获取永久缓存
	get(key: string) {
		let json: any = window.localStorage.getItem(key)
		return JSON.parse(json)
	},
	// 移除永久缓存
	remove(key: string) {
		window.localStorage.removeItem(key)
	},
	// 移除全部永久缓存
	clear() {
		window.localStorage.clear()
	},
}

/**
 * window.sessionStorage 浏览器临时缓存
 * @method set 设置临时缓存
 * @method get 获取临时缓存
 * @method remove 移除临时缓存
 * @method clear 移除全部临时缓存
 */
export const Session = {
	// 设置临时缓存
	set(key: string, val: any) {
		window.sessionStorage.setItem(key, JSON.stringify(val))
	},
	// 获取临时缓存
	get(key: string) {
		let json: any = window.sessionStorage.getItem(key)
		return JSON.parse(json)
	},
	// 移除临时缓存
	remove(key: string) {
		window.sessionStorage.removeItem(key)
	},
	// 移除全部临时缓存
	clear() {
		window.sessionStorage.clear()
	},
}

/**
 * 浏览器 cookie 设置
 * @method set 设置临时缓存
 * @method get 获取临时缓存
 * @method remove 移除临时缓存
 * @method clear 移除全部临时缓存
 */
 export const Cookie = {
	// 设置缓存
	set(cname:string, cvalue:any, exdays = 720) {
		let d = new Date()
		d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000))
		let expires = 'expires=' + d.toUTCString()
		document.cookie = cname + '=' + cvalue + '; ' + expires
	},
	// 获取临时缓存
	get(cname:string) {
		let name = cname + '='
		let ca = document.cookie.split(';')
		for (let i = 0; i < ca.length; i++) {
			let c = ca[i]
				while (c.charAt(0) === ' ') c = c.substring(1)
				if (c.indexOf(name) !== -1) {
						return c.substring(name.length, c.length)
				}
		}
		return ''
	},
	// 移除临时缓存
	remove(cname:string) {
		let d = new Date()
		d.setTime(-1)
		let expires = 'expires=' + d.toUTCString()
		document.cookie = cname + '=\'\'; ' + expires
	},
}

request.ts

import axios from 'axios'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Session } from '@/utils/storage'


// 配置新建一个 axios 实例
const service = axios.create({
	baseURL: import.meta.env.VITE_API_URL as any,
	timeout: 60000,
	headers: { 'Content-Type': 'application/json' },
})

//
// axios.defaults.withCredentials = true
// 添加请求拦截器
service.interceptors.request.use(
	(config) => {
		// 发送请求之前 token
		if (Session.get('token')) {
			config.headers.common['Authorization'] = Session.get('token')
		}
		return config
	},
	(error) => {
		// 请求错误
		return Promise.reject(error)
	}
)

// 添加响应拦截器
service.interceptors.response.use(
	(response) => {
		// 响应数据
		const res = response.data
		if (res.code && res.code !== 0) {
			// `token` 过期或者账号已在别处登录
			if (res.code === 401 || res.code === 4001) {
				Session.clear() // 清除浏览器全部临时缓存
				window.location.href = '/' // 去登录页
				ElMessageBox.alert('你已被登出,请重新登录', '提示', {})
					.then(() => {})
					.catch(() => {})
			}else if(res.code === 1001){
				ElMessage.error('密码错误')
			}
			return Promise.reject(service.interceptors.response)
		} else {
			return response.data
		}
	},
	(error) => {
		// 对响应错误做点什么
		if (error.message.indexOf('timeout') !== -1) {
			ElMessage.error('网络超时')
		} else if (error.message === 'Network Error') {
			ElMessage.error('网络连接错误')
		} else {
			console.log(error)
			if (error.response.data) {
        ElMessage.error(error.response.statusText)
      }
      else ElMessage.error('接口路径找不到')
    }
    return Promise.reject(error)
  }
)

// 导出 axios 实例
export default service

api文件夹下login.ts

import axios from '@/utils/request.ts
export function signIn(params: object) {
    return request({
	url: '/login',
	method: 'post',
	data: params,
    })
}

已搭框架项目 gitee.com/bigwhitexin…