原文链接 本文目录
一、生成项目
1.1 初始化项目
1.2 css重置
1.3 UI组件库Element-Plus
1.3.1 测试UI组件库
1.4 按需引入icon
1.5 使用less
1.6 配置unocss
二、项目架构
三、粒子动画
一、生成项目
项目基于node 20.9.0 运行命令:
npm init vue@latest
按照以上提示执行命令,项目运行后效果如下:
1.1 初始化项目
删除文件夹下的文件如下:
这些文件是初始化项目时默认生成的,我们不需要这些文件,进行删除。
1.2 css重置 css重置 运行命令
npm install normalize.css
在main.ts中引入:
import 'normalize.css'
1.3 UI组件库Element-Plus
运行命令安装Element-Plus:
npm install element-plus
按需引入: 首先你需要安装unplugin-vue-components 和 unplugin-auto-import这两款插件:
npm install -D unplugin-vue-components unplugin-auto-import
在vite.config.ts中写入:
// vite.config.ts
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default defineConfig({
// ...
plugins: [
// ...
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
})
1.3.1 测试UI组件库
在App.vue中写入组件:
<script setup lang="ts">
import { ElMessage } from 'element-plus'
import { RouterView } from 'vue-router'
const open = () => {
ElMessage('This is a message.')
}
</script>
<template>
<header></header>
<el-button type="primary">Primary</el-button>
<el-button type="success" @click="open">Success</el-button>
<el-button type="info">Info</el-button>
<el-button type="warning">Warning</el-button>
<el-button type="danger">Danger</el-button>
<RouterView />
</template>
<style scoped></style>
配置完之后重新跑一下项目,会发现在项目根目录下生成了两个文件:
在tsconfig.json或者tsconfig.app.json中的include导入这个两个文件名:
但是当我们点击弹窗时会发现样式出错:
这是因为Element Plus的Feedback反馈组件依赖于样式,我们组件又是按需加载的,所以我们运行命令来按需加载样式:
npm install consola vite-plugin-style-import -D
vite.config.js中配置:
//...
import { createStyleImportPlugin } from 'vite-plugin-style-import'
export default defineConfig({
//...
plugins: [
//...
createStyleImportPlugin({
libs: [
{
libraryName: 'element-plus',
esModule: true,
resolveStyle: (name) => {
return `element-plus/theme-chalk/${name}.css`
},
},
],
}),
]
})
配置后重新启动运行,点击生效:
1.4 按需引入icon
运行命令安装:
npm install unplugin-icons -D
配置:
//vite.config.js
import path from "path"
import Icons from "unplugin-icons/vite"
import IconsResolver from "unplugin-icons/resolver"
const pathSrc = path.resolve(__dirname, "src")
//...
plugins: [
//...
AutoImport({
resolvers: [
//... ,
IconsResolver({
prefix: "Icon",
}),
],
dts: path.resolve(pathSrc, "auto-imports.d.ts"),
}),
Components({
resolvers: [
//... ,
IconsResolver({
enabledCollections: ["ep"],
}),
],
dts: path.resolve(pathSrc, "components.d.ts"),
}),
Icons({
autoInstall: true,
}),
]
然后在页面中使用:
<el-icon :size="20">
<i-ep-Edit />
</el-icon>
效果:
1.5 使用less
运行命令,安装less:
npm install less -D
配置自定义重置/变量css,在如下文件夹中新建如下:
index.less引入另外两个文件:
@import "./reset.less";
@import "./common.less";
main.ts中导入:
//...
import "@/assets/css/index.less"
1.6 配置unocss
运行命令安装unocss:
npm install -D unocss
vite.config.js中配置:
//...
import UnoCSS from 'unocss/vite'
export default defineConfig({
//...
plugins: [
//...
UnoCSS(),
]
})
在main.ts中导入:
//...
import "virtual:uno.css"
在项目根目录想新建文件uno.config.ts写入:
// uno.config.ts
// uno.config.ts
import { defineConfig } from 'unocss'
export default defineConfig({
// 自定义规则集
rules: [
['flex-center', { display: 'flex', 'justify-content': 'center', 'align-items': 'center' }],
],
})
更多规则可查更详细文档。 在App.vue加入这行:
<div class="mb-20px flex-center">unocss</div>
可以看到页面:
二、项目架构
新建NotFound文件夹及文件NotFound.vue,写入代码:
<template>
<div class="not-found">
<h1>not found</h1>
</div>
</template>
<script setup lang="ts"></script>
<style scoped lang="less">
.not-found {
color: red;
}
</style>
新建文件夹及文件如下:
//Login.vue
<template>
<h2>Login</h2>
</template>
<script setup lang="ts"></script>
<style scoped lang="less"></style>
//Main.vue
<template>
<h2 class="m-10px items-center justify-center flex">Main</h2>
<el-button type="primary">Primary</el-button>
<el-button type="success">Success</el-button>
</template>
<script setup lang="ts"></script>
<style scoped lang="less"></style>
//App.vue
<template>
<routerView></routerView>
</template>
<script setup lang="ts"></script>
<style scoped lang="less"></style>
//src/router/index.ts
import { createRouter, createWebHashHistory } from "vue-router"
const router = createRouter({
history: createWebHashHistory(),
routes: [
{
path: "/",
redirect: "/main",
},
{
path: "/login",
component: () => import("@/views/Login/Login.vue"),
},
{
path: "/main",
component: () => import("@/views/Main/Main.vue"),
},
{
path: "/:pathMatch(.*)",
component: () => import("@/NotFound/NotFound.vue"),
},
],
})
export default router
三、粒子动画
运行命令安装粒子动画:
npm install @tsparticles/vue3 @tsparticles/slim
//main.ts
//...
import Particles from "@tsparticles/vue3"
import { loadSlim } from "@tsparticles/slim"
//...
app.use(Particles, {
init: async (engine) => {
await loadSlim(engine)
},
})
//src/components/VueParticles.vue
<template>
<!-- @particles-loaded="particlesLoaded" -->
<vue-particles id="tsparticles" :options="options" />
</template>
<script setup lang="ts">
// const particlesLoaded = async (container: any) => {
// console.log("Particles container loaded", container)
// }
const options = {
background: {
color: {
value: "#fff",
},
},
fpsLimit: 60,
interactivity: {
events: {
onClick: {
enable: true,
mode: "push",
},
onHover: {
enable: true,
mode: "grab",
},
},
modes: {
bubble: {
distance: 150,
duration: 2,
size: 5,
},
push: {
quantity: 4,
},
},
},
particles: {
color: {
value: "#0f88eb",
},
links: {
color: "#0f88eb",
distance: 150,
enable: true,
opacity: 0.5,
width: 1,
},
opacity: {
value: 0.8,
},
move: {
direction: "none",
enable: true,
// outModes: "bounce",
random: true,
speed: 1.5,
straight: false,
},
number: {
density: {
enable: true,
},
value: 130,
},
shape: {
type: "star",
},
size: {
value: { min: 1, max: 5 },
},
},
detectRetina: true,
}
</script>
<style scoped lang="less"></style>
我们需要将粒子动画放在登录处,所以修改Login.vue处代码:
<template>
<h1 class="absolute left-50% top-15% transform-translate-x-[-50%] z-1 flex justify-center mb40px text-#666">
{{ title }}
</h1>
<div class="absolute z-1 left-50% top-45% transform-translate-[-50%] w368px min-h200px">
<el-tabs v-model="activeName" @tab-click="handleClick" stretch>
<el-tab-pane name="first">
<template #label>
<div class="flex-center">
<el-icon><i-ep-calendar /></el-icon>
<span>登录</span>
</div>
</template>
<el-form
ref="ruleFormRef"
style="max-width: 600px"
:model="ruleForm"
:rules="rules"
label-width="auto"
class="demo-ruleForm"
:size="formSize"
status-icon
>
<el-form-item prop="username">
<el-input placeholder="请输入帐号" v-model="ruleForm.username" />
</el-form-item>
<el-form-item prop="password">
<el-input placeholder="请输入密码" v-model="ruleForm.password" />
</el-form-item>
</el-form>
</el-tab-pane>
<el-tab-pane label="忘记密码" name="second">Config</el-tab-pane>
</el-tabs>
</div>
<VueParticles />
</template>
<script setup lang="ts">
const title = import.meta.env.VITE_SITE_TITLE
import type { ComponentSize, FormInstance, FormRules } from "element-plus"
import type { TabsPaneContext } from "element-plus"
const activeName = ref("first")
const handleClick = (tab: TabsPaneContext, event: Event) => {
console.log(tab, event)
}
interface RuleForm {
username: string
password: string
}
const formSize = ref<ComponentSize>("default")
const ruleFormRef = ref<FormInstance>()
const ruleForm = reactive<RuleForm>({
username: "",
password: "",
})
const rules = reactive<FormRules<RuleForm>>({
username: [
{ required: true, message: "请输入帐号!", trigger: "blur" },
{ min: 3, max: 10, message: "长度在3-10之间!", trigger: "blur" },
],
password: [
{ required: true, message: "请输入密码!", trigger: "blur" },
{ min: 3, max: 10, message: "长度在3-10之间!", trigger: "blur" },
],
})
// const submitForm = async (formEl: FormInstance | undefined) => {
// if (!formEl) return
// await formEl.validate((valid, fields) => {
// if (valid) {
// console.log("submit!")
// } else {
// console.log("error submit!", fields)
// }
// })
// }
// const resetForm = (formEl: FormInstance | undefined) => {
// if (!formEl) return
// formEl.resetFields()
// }
// const options = Array.from({ length: 10000 }).map((_, idx) => ({
// value: `${idx + 1}`,
// label: `${idx + 1}`,
// }))
</script>
<style scoped lang="less">
:deep(.el-form-item--default) {
margin-bottom: 24px;
}
:deep(.el-tabs__header) {
margin-bottom: 24px;
}
</style>
看到效果:
在学习的路上,如果你觉得本文对你有所帮助的话,那就请关注点赞评论三连吧,谢谢,你的肯定是我写博的另一个支持。 ————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。