小白笔记整理 整理中非常乱......
vite CDN 加速
- vite-plugin-cdn-import
vite.CDN.config.ts
推荐使用 饿了么的CDN加速 //npm.elemecdn.com
import type { Options } from 'vite-plugin-cdn-import';
export const viteCDNConfig = (): Options => {
return {
modules: [
{
name: 'vue',
var: 'Vue',
// path: '//cdn.jsdelivr.net/npm/vue@3.2.39/dist/vue.global.prod.js',
path: '//npm.elemecdn.com/vue@3.2.39/dist/vue.global.prod.js',
},
// 一些基于 vue-demi 开发的框架依赖于这个包
{
name: 'vue-demi',
var: 'VueDemi',
// path: '//cdn.jsdelivr.net/npm/vue-demi@0.13.11/lib/index.iife.js',
path: '//npm.elemecdn.com/vue-demi@0.13.11/lib/index.iife.js',
},
{
name: 'vue-router',
var: 'VueRouter',
// path: '//cdn.jsdelivr.net/npm/vue-router@4.1.5/dist/vue-router.global.prod.js',
path: '//npm.elemecdn.com/vue-router@4.1.5/dist/vue-router.global.prod.js',
},
{
name: 'axios',
var: 'axios',
// path: '//cdn.jsdelivr.net/npm/axios@0.27.2/dist/axios.min.js',
path: '//npm.elemecdn.com/axios@0.27.2/dist/axios.min.js',
},
// pinia 20 kb
{
name: 'pinia',
var: 'Pinia',
path: '//npm.elemecdn.com/pinia@2.0.22/dist/pinia.iife.prod.js',
},
{
name: 'echarts',
var: 'echarts',
// path: '//unpkg.zhimg.com/echarts@5.3.3/dist/echarts.min.js',
// path: '//cdn.jsdelivr.net/npm/echarts@5.3.3/dist/echarts.simple.js',
// path: '//cdn.bootcdn.net/ajax/libs/echarts/5.3.3/echarts.min.js',
path: '//npm.elemecdn.com/echarts@5.3.3/dist/echarts.min.js',
},
{
name: 'vue-request',
var: 'VueRequest',
// path: '//cdn.jsdelivr.net/npm/vue-request@1.2.4/dist/vue-request.min.js',
path: '//npm.elemecdn.com/vue-request@1.2.4',
},
{
name: '@arco-design/web-vue',
var: 'ArcoVue',
// path: '//cdn.jsdelivr.net/npm/@arco-design/web-vue@2.36.1/dist/arco-vue.min.js',
path: '//npm.elemecdn.com/@arco-design/web-vue@2.36.1/dist/arco-vue.min.js',
css: '//npm.elemecdn.com/@arco-design/web-vue@2.36.1/dist/arco.min.css',
},
/*
接近 800kb直接放弃
{
name: 'vue-echarts',
var: 'vue-echarts',
path: '//cdn.jsdelivr.net/npm/vue-echarts@6.2.3/dist/index.umd.min.js',
},*/
],
};
};
vite.config.ts
- unplugin-vue-components/vite cdn 打包有冲突,不知道该怎么解决
- AutoImport.imports 如果指定了 vue 会报找不到 vue异常
- AutoImport.dirs 指定的包,需要重新启动 vite 才会 生成在 auto-import.d.ts 中......
import vue from '@vitejs/plugin-vue';
import AutoImport from 'unplugin-auto-import/vite';
// import { ArcoResolver } from 'unplugin-vue-components/resolvers';
// import Components from 'unplugin-vue-components/vite';
import { visualizer } from 'rollup-plugin-visualizer';
import { Plugin as importToCDN } from 'vite-plugin-cdn-import';
import { viteMockServe } from 'vite-plugin-mock';
import Pages from 'vite-plugin-pages';
import Layouts from 'vite-plugin-vue-layouts';
import { viteCDNConfig } from './vite.CDN.config';
export const vitePluginsConfig = (command: string): Plugin[] => {
return [
vue(),
AutoImport({
include: [
/.[tj]sx?$/, // .ts, .tsx, .js, .jsx
/.vue$/,
/.vue?vue/, // .vue
],
resolvers: [],
dts: './src/types/auto/imports.d.ts',
imports: ['@vueuse/core', 'vue-router', 'pinia'], // 这里没指定 vue
dirs: ['./src/hooks', './src/common/utils'],
}),
/*Components({
resolvers: [
ArcoResolver({
sideEffect: true,
importStyle: 'css',
}),
],
directoryAsNamespace: true,
dts: './src/types/auto/components.d.ts',
}),*/
visualizer({
open: true,
}),
importToCDN(viteCDNConfig()),
viteMockServe({
mockPath: './src/server/mock',
localEnabled: command === 'serve',
supportTs: true,
}),
Pages({
dirs: [
{
dir: './src/pages',
baseRoute: '/',
},
],
exclude: ['**/components/*.vue'],
importMode: 'async',
extensions: ['vue'],
}),
Layouts({
layoutsDirs: './src/common/layouts',
defaultLayout: 'default',
}),
];
};
ts 警告处理
tsconfig.node.json 添加 include
{
"compilerOptions": {
"composite": true,
"module": "ESNext",
"moduleResolution": "Node",
"allowSyntheticDefaultImports": true
},
"include": [
"vite.config.ts",
"vite.plugins.config.ts",
"vite.resolve.config.ts",
"vite.build.config.ts",
"vite.CDN.config.ts"
]
}
集成 unocss
在项目中你能够编写 windicss 语法
能够使用 windicss 语法
<template>
<h1 class="text-blue-500 text-[2rem]">Login 登陆页面</h1>
</template>
最终生成 css
.text-blue-500 {
--un-text-opacity: 1;
color: rgba(59, 130, 246, var(--un-text-opacity));
}
.text-[2rem] {
font-size: 2rem;
}
或者通过 @apply 指定
注意 依赖 @unocss/transformer-directives
<style scoped>
.br_title {
@apply text-blue-500 text-[2rem];
}
</style>
集成 Icon
在项目中你能够轻松使用 iconify 网站的所有 icon 图标 以及 本地指定目录的 icon 图标
1. iconify
你可以访问该网站 icones.js.org 复制任意需要的图标名, 到你的项目中
注意你得加上
icon- , 如需要自定义前缀 前往 unocss.config.ts 配置
vue
<template>
<div class="icon-fluent-alert-20-filled" />
</template>
2. 本地 Icon
-
./src/assets/banner/ -
./src/assets/icon/目录也能通过
class获取svg, 你只需要加上icon-br-icon-[svg文件名]或icon-br-banner-[svg文件名]就能获取svg
vue
<template>
<div class="icon-br-icon-manager" />
<!-- 配置了 mask, 彩图需要加 ?bg 后缀 -->
<icon icon="br-banner-not-fount?bg" />
</template>
[小案例]
<template>
<!-- A basic anchor icon from Phosphor icons -->
<div class="i-ph-anchor-simple-thin" />
<!-- An orange alarm from Material Design Icons -->
<div class="i-mdi-alarm text-orange-400" />
<!-- A large Vue logo -->
<div class="i-logos-vue text-3xl" />
<!-- Sun in light mode, Moon in dark mode, from Carbon -->
<button class="i-carbon-sun dark:i-carbon-moon" />
<!-- Twemoji of laugh, turns to tear on hovering -->
<div class="i-twemoji-grinning-face-with-smiling-eyes hover:i-twemoji-face-with-tears-of-joy" />
</template>
0. 代码实现
package.json
"devDependencies": {
"@iconify/json": "^2.1.105",
"@unocss/preset-attributify": "^0.45.18",
"@unocss/preset-icons": "^0.45.18",
"@unocss/preset-wind": "^0.45.18",
"unocss": "^0.45.18",
}
vite.config.ts
import { defineConfig } from 'vite';
import Unocss from 'unocss/vite';
const config = defineConfig(({ command }) => {
return {
plugins: [, /*...*/ Unocss() /* <- 只加这个 🧬 */],
};
});
export { config as default };
unocss.config.ts
-
@unocss/preset-wind
- windicss 语法 你能够指定类
py-4、py-[2rem]...... 生成 css -
.py-4 { padding-top: 1rem; padding-bottom: 1rem; } .py-4 { padding-top: 2rem; padding-bottom: 2rem; }
- windicss 语法 你能够指定类
-
@unocss/preset-icons
- 让你能够 通过类 生成 @iconify/json icon 图标
<div class="icon-logos-vitejs" /> <!-- vite 图标 -->
<div class="icon-logos-vitejs?bg" /> <!-- vite 图标 -->
-
@unocss/preset-attributify
- 少写前缀 😅
<template> <!-- windiscss --> <h2 class="text-teal-500">案例</h2> <!-- windiscss + unocss + @unocss/preset-attributify --> <h2 text="teal-500">案例</h2> </template>
unocss.config.ts
根目录下
import {
defineConfig,
presetWind,
presetIcons,
presetAttributify,
} from 'unocss';
import transformerDirective from '@unocss/transformer-directives';
import { FileSystemIconLoader } from '@iconify/utils/lib/loader/node-loaders';
export default defineConfig({
presets: [
presetIcons({
mode: 'mask', // 自定义 br-icon 默认是 bg 模式加载不能修改字体颜色
scale: 1.4,
prefix: 'icon-',
extraProperties: {
display: 'inline-block',
'vertical-align': 'middle',
},
collections: {
// 自定义路径下的 svg -> 类 format: icon-br-banner-[filename] or icon-br-icon-[filename]
'br-banner': FileSystemIconLoader('./src/assets/banner', (svg) => svg),
'br-icon': FileSystemIconLoader('./src/assets/icon', (svg) => svg),
},
customizations: {
iconCustomizer(collection, icon, props) {
// banner 尺寸调整
if (collection === 'br-banner') {
props.height = '20em';
props.width = '20em';
}
},
},
}),
presetWind(),
presetAttributify(),
],
// 能够使用 @apply......
transformers: [transformerDirective()],
});
集成 day.js
对日期进行处理
距离现在 距离 n 秒 / n 分 / n 时 / n 天 / n 年
import { day } from '~plugins/day';
day(createAt).fromNow(); // 19 年前
config
import dayjs from 'dayjs';
import isLeapYear from 'dayjs/plugin/isLeapYear';
import relativeTime from 'dayjs/plugin/relativeTime';
import 'dayjs/locale/zh-cn';
dayjs.extend(isLeapYear);
dayjs.extend(relativeTime);
dayjs.locale('zh-cn');
export { dayjs as day };
集成 axios
IApiEntity.d.ts
export interface IApiEntity<T = unknown> {
status: number;
message: string;
data: T;
}
api/index.ts
import type { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios';
import axios from 'axios';
import { Message } from '@arco-design/web-vue';
import type { IApiEntity } from '~types/entity/IApiEntity';
import { closeLoading, startLoading } from '~plugins/nprogress';
const server = axios.create({
baseURL: import.meta.env.VITE_BASE_API,
timeout: 1000 * 7,
});
// 请求拦截器
server.interceptors.request.use(
(conf: AxiosRequestConfig) => {
// 添加验证请求头......
return conf;
},
(err: AxiosError) => {
// err
return Promise.reject(err);
}
);
// 响应拦截器
server.interceptors.response.use(
async (res: AxiosResponse<IApiEntity>) => {
const { status, message, data: resData } = res.data;
switch (true) {
case status === 200: {
break;
}
// ......
default: {
Message.error(message);
break;
}
}
return res;
},
(err: AxiosError) => {
return Promise.reject(err);
}
);
const useBaseHttp = <T>(config: AxiosRequestConfig) => {
startLoading();
return (
new Promise() <
T >
((resolve, reject) => {
server
.request(config)
.then((response) => {
resolve(response.data);
})
.catch((error) => {
reject(error);
})
.finally(() => {
closeLoading();
});
})
);
};
const useHttp = <T>(config: AxiosRequestConfig) => {
return useBaseHttp < IApiEntity < T >> config;
};
export { useHttp as default, useHttp, useBaseHttp };
api 案例
UserMessageDto.ts
export interface UserMessageDto {
id: number;
message: string;
createAt: string;
user: IUserEntity;
}
IBaseEntity.d.ts
export interface IBaseEntity {
// 主键
id: number;
// 创建时间
createAt: string;
// 最后更新时间
updateAt: string;
// 创建人
createBy: number;
// 最后更新人
updateBy: number;
// 是否启用 `0` 关闭 `1` 开启
isStatus: boolean;
// 逻辑删除 `0` 未删除 `null` 删除
isDeleted: boolean;
// 备注
remark: string;
// 乐观锁
version: number;
// ip
ip: string;
// ip address
ipAddr: string;
}
IUserEntity.d.ts
import type { IBaseEntity } from '~types/entity/IBaseEntity';
declare global {
interface IUserEntity extends IBaseEntity {
username: string;
email: string;
address: string;
gender: boolean;
age: number;
icon: string;
loginCount: number;
ip: string;
ipAddr: string;
birthday: string;
}
}
import useHttp from '~/server';
import type { UserMessageDto } from '~dto/user/UserMessageDto';
/**
* @since 2022-9-10
* @description 获取当前用户信息
*/
export const getUserSelfMessagesApi = () => {
return useHttp<UserMessageDto[]>({
method: 'GET',
url: '/user/self',
});
};
使用
- 集成
vue-request请求库
<script lang="ts" setup>
import SimpleCartList from '~comp/message/SimpleCartList.vue';
import { getUserSelfMessagesApi } from '~api/user';
import { useRequest } from 'vue-request';
import { computed } from 'vue';
import type { UserMessageDto } from '~dto/user/UserMessageDto';
const {
data: res,
loading,
refresh,
} = useRequest(getUserSelfMessagesApi, {
manual: false,
});
const list = computed<UserMessageDto[]>(() => {
return res.value?.status === 200 ? res.value.data : [];
});
</script>
<template>
// a-xx by arco ui comp.
<a-space>
<h3>Default 默认页面</h3>
<a-button :loading="loading" @click="refresh">刷新</a-button>
</a-space>
// 自定义组件
<SimpleCartList :list="list" :loading="loading" />
</template>
<style scoped></style>
集成 nprogress
加载进度条
路由跳转
import { createRouter, createWebHashHistory } from 'vue-router';
// routes......
const router = createRouter({
history: createWebHashHistory(),
routes: routes,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
scrollBehavior(to, from, savedPosition) {
// 始终滚动到顶部
return { top: 0 };
},
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
router.beforeEach(async ({ fullPath, name }, from) => {
// 跳转 前加载
startLoading();
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
router.afterEach((to, from, failure) => {
// 跳转 后结束加载
closeLoading();
});
export { router as default, router };
请求
import type { AxiosRequestConfig } from 'axios';
import { closeLoading, startLoading } from '~plugins/nprogress';
const useBaseHttp = <T>(config: AxiosRequestConfig) => {
startLoading();
return (
new Promise() <
T >
((resolve, reject) => {
server
.request(config)
.then((response) => {
setTimeout(() => resolve(response.data), ANALOG_DELAY);
})
.catch((error) => {
reject(error);
})
.finally(() => {
closeLoading();
});
})
);
};
config
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
NProgress.configure({
showSpinner: false, // 是否显示加载 icon
easing: 'ease',
speed: 500,
});
const startLoading = () => {
NProgress.start();
};
const closeLoading = () => {
NProgress.done();
};
export { startLoading, closeLoading, NProgress };