【转载】vue3项目搭建,Element-Plus,less等

117 阅读2分钟

原文链接 本文目录

一、生成项目

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

image.png 按照以上提示执行命令,项目运行后效果如下: image.png

1.1 初始化项目

删除文件夹下的文件如下:

image.png 这些文件是初始化项目时默认生成的,我们不需要这些文件,进行删除。

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-componentsunplugin-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>

配置完之后重新跑一下项目,会发现在项目根目录下生成了两个文件:

image.png

在tsconfig.json或者tsconfig.app.json中的include导入这个两个文件名:

image.png

image.png

但是当我们点击弹窗时会发现样式出错:

image.png

这是因为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`
          },
        },
      ],
    }),
  ]
})

配置后重新启动运行,点击生效:

image.png

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>

效果:

image.png

1.5 使用less

运行命令,安装less:

npm install less -D

配置自定义重置/变量css,在如下文件夹中新建如下:

image.png

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>

可以看到页面:

image.png

二、项目架构

新建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>

新建文件夹及文件如下:

image.png

//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>

看到效果:

image.png

在学习的路上,如果你觉得本文对你有所帮助的话,那就请关注点赞评论三连吧,谢谢,你的肯定是我写博的另一个支持。 ————————————————

                        版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                    

原文链接:blog.csdn.net/weixin_4410…