【vue3后台项目】登录页面ui及图标组件封装

构建登录页面

1.创建views/login/index.vue文件;

views/login/index.vue 复制代码
<template>
  <div class="login-container">
    <el-form class="login-form">
      <div class="title-container">
        <h3 class="title">用户登录</h3>
      </div>
      <el-form-item>
        <span class="svg-container">
          <el-icon><Avatar /></el-icon>
        </span>
        <el-input placeholder="username" name="username" type="text"></el-input>
      </el-form-item>
      <el-form-item>
        <span class="svg-container">
          <el-icon><Avatar /></el-icon>
        </span>
        <el-input placeholder="password" name="password"></el-input>
        <span class="show-pwd">
          <el-icon><Avatar /></el-icon>
        </span>
      </el-form-item>
      <el-button type="primary" style="width: 100%; margin-bottom: 30px"
        >登录</el-button
      >
    </el-form>
  </div>
</template>

<script setup>
import { Avatar } from '@element-plus/icons'
</script>

<style lang="scss" scoped>
$bg: #2d3a4b;
$dark_gray: #889aa4;
$light_gray: #eee;
$cursor: #fff;

.login-container {
  min-height: 100%;
  width: 100%;
  background-color: $bg;
  overflow: hidden;
  .login-form {
    position: relative;
    width: 520px;
    max-width: 100%;
    padding: 160px 35px;
    margin: 0 auto;
    overflow: hidden;
    .title-container {
      width: 100%;
      padding-bottom: 20px;
      text-align: center;
      font-weight: bold;
      color: #fff;
      font-size: 26px;
    }
    ::v-deep .el-form-item {
      border: 1px solid rgba(255, 255, 255, 0.1);
      background-color: rgba(0, 0, 0, 0.1);
      border: 5px;
      color: #454545;
    }
    .svg-container {
      display: inline-block;
      text-align: center;
    }
    ::v-deep .el-input {
      display: inline-block;
      width: 85%;
      height: 47%;

      input {
        background: transparent;
        border: 0px;
        border-radius: 0px;
        color: $light_gray;
        padding: 12px 5px 12px 15px;
        caret-color: $cursor;
      }
    }
  }
  .svg-container {
    padding: 6px 5px 6px 15px;
    color: $dark_gray;
    vertical-align: middle;
    display: inline-block;
  }
  .show-pwd {
    position: absolute;
    right: 10px;
    top: 7px;
    font-size: 16px;
    color: $dark_gray;
    cursor: pointer;
    user-select: none;
  }
}
</style>

2.在route/index.js中增加一下路由配置;

route/index.js 复制代码
import { createRouter, createWebHashHistory } from 'vue-router'

const publicRoutes = [
  {
    path: '/login',
    component: () => import('@/views/login/index')
  }
]

const router = createRouter({
  history: createWebHashHistory(),
  routes: publicRoutes
})

export default router

3.创建全局的style

style/index.scss 复制代码
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
  -moz-osx-font-smoothing: grayscale;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB,
    Microsoft YaHei, Arial, sans-serif;
}

#app {
  height: 100%;
}

*,
*:before,
*:after {
  box-sizing: inherit;
  margin: 0;
  padding: 0;
}

a:focus,
a:active {
  outline: none;
}

a,
a:focus,
a:hover {
  cursor: pointer;
  color: inherit;
  text-decoration: none;
}

div:focus {
  outline: none;
}

.clearfix {
  &:after {
    visibility: hidden;
    display: block;
    font-size: 0;
    content: ' ';
    clear: both;
    height: 0;
  }
}

main.ts中导入:

main.ts 复制代码
import '@/styles/index.scss'

Icon图标

之前都是通过路径引入图标:

html 复制代码
<img src="../assets/icons/user.svg" />

显然是很不方便的,此次封装的目的就是为了简化写法和可复用性;

在我们项目中该所使用的icon图标,一共分为两类:

1.element-plus的图标;

2.自定义的svg图标;

对于element-plus的图标我们可以直接通过el-icon来进行显示,但是自定义图标的话,我们需要自定义组件,来显示自定义的svg图标;

这个组件需要拥有两种能力:

1.显示外部svg图标;

2.现实项目内的svg图标;

创建图标组件

创建utils/validate.js;

utils/validate.js 复制代码
/**
 * 判断是否为外部资源
 */
export function isExternal(path) {
  return /^(https?:|mailto:|tel:)/.test(path)
}

创建components/SvgIcon/index.vue;

components/SvgIcon/index.vue 复制代码
<template>
  <!--展示外部图标-->
  <div
    v-if="isExternal"
    :style="styleExternalIcon"
    class="svg-external-icon svg-icon"
    :class="className"
  ></div>
  <!--展示内部图标-->
  <svg v-else class="svg-icon" :class="className" aria-hidden="true">
    <use :xlink:href="iconName"></use>
  </svg>
</template>

<script setup>
import { defineProps, computed } from 'vue'
import { isExternal as external } from '@/utils/validate'
const props = defineProps({
  // icon图标
  icon: {
    type: String,
    required: true
  },
  // 图标类名
  className: {
    type: String,
    default: ''
  }
})
/**
 *判断当前图标是否为外部图标
 */
const isExternal = computed(() => external(props.icon))
/**
 * 外部图标样式
 */
const styleExternalIcon = computed(() => ({
  mask: `url(${props.icon}) no-repeat 50% 50%`,
  '-webkit-mask': `url(${props.icon}) no-repeat 50% 50%`
}))
/**
 * 内部图标
 */
const iconName = computed(() => `#icon-${props.icon}`)
</script>

<style lang="scss" scoped>
.svg-icon {
  /** 将icon大小设置和字体大小一致,后续在通过svg-icon使用icon的时候,可直接设置图标的font-size即可控制图标的大小 */
  width: 1em;
  height: 1em;
  vertical-align: -0.15em;
  /** 因icon大小被设置为字体大小一致,而span等标签的下边缘会和字体的基线对齐,顾需设置一个往下的偏移比例,来纠正视觉上的未对齐效果*/
  fill: currentColor;
  /** 定义元素的颜色,currentColor是一个变量,这个变量就表示当前元素的color,如果当前元素未设置color值,则从父元素继承 */
  overflow: hidden;
}

.svg-external-icon {
  background: currentColor;
  mask-size: cover !important;
  display: inline-block;
}
</style>

接着在login页面使用图标组件,这里是一个外部图标的显示:

views/login/index.vue 复制代码
<span class="svg-container">
  <SvgIcon icon="https://res.lgdsunday.club/user.svg"></SvgIcon>
</span>

外部图标成功显示出来;

处理内部svg图标显示

处理内部svg图标显示的步骤:

1.首先导入所有的svg图标: 大家可以去我的git仓库直接拷贝src/icons/svg文件夹到自己的目录下;

2.在icons目录下创建index.js文件,该文件中需要完成两件事情,这个过程类似于Element-plus的导入:

  • 导入所有的svg图标;
  • 完成SvgIcon的全局注册;

webpack导入依赖

创建icons/svg/index.js

icons/svg/index.js 复制代码
import SvgIcon from '@/components/SvgIcon'
const svgRequire = require.context('./svg', false, /\.svg$/)
// 返回一个Require函数,可以接受一个request的参数,用于require的导入;
// 该函数提供了三个属性,可以通过svgRequire.keys()获取所有的svg图标;
// 遍历图标,把图标作为request参数传入到svgRequire导入函数中,完成本地svg图标的导入;

svgRequire.keys().forEach((icon) => {
  svgRequire(icon)
})

export default (app) => {
  app.component('svg-icon', SvgIcon)
}

在main.js中导入;

main.js 复制代码
// 导入svgIcon
import installIcons from '@/icons'

installIcons(app)

使用svg-sprite-loader处理svg图标

svg-sprite-loader是webpack中专门用来处理svg图标的一个loader,详情🔎; 我们需要做两件事情:

1.下载该loader,执行

js 复制代码
npm i svg-sprite-loader@6.0.9 --save

2.创建vue.config.js文件,新增如下配置,详情🔎

vue.config.js 复制代码
const path = require('path')
function resolve(dir) {
  return path.join(__dirname, dir)
}

module.exports = {
  chainWebapack: (config) => {
    // 内置的svg处理排除执行目录下的文件
    config.module.rule('svg').exclude.add(resolve('src/icons')).end()
    config.module
      .rule('svg-sprite-loader')
      .test(/\.svg$/)
      .include.add(resolve('src/icons'))
      .end()
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'icon-[name]'
      })
      .end()
  }
}

接着去login页面引入图标组件:

js 复制代码
<span class="svg-container">
  <SvgIcon icon="user"></SvgIcon>
</span>

图标可以正常显示了!

相关推荐
时清云28 分钟前
【算法】合并两个有序链表
前端·算法·面试
小爱丨同学36 分钟前
宏队列和微队列
前端·javascript
持久的棒棒君1 小时前
ElementUI 2.x 输入框回车后在调用接口进行远程搜索功能
前端·javascript·elementui
2401_857297911 小时前
秋招内推2025-招联金融
java·前端·算法·金融·求职招聘
一 乐1 小时前
租拼车平台|小区租拼车管理|基于java的小区租拼车管理信息系统小程序设计与实现(源码+数据库+文档)
java·数据库·vue.js·微信·notepad++·拼车
undefined&&懒洋洋2 小时前
Web和UE5像素流送、通信教程
前端·ue5
大前端爱好者4 小时前
React 19 新特性详解
前端
小程xy4 小时前
react 知识点汇总(非常全面)
前端·javascript·react.js
随云6324 小时前
WebGL编程指南之着色器语言GLSL ES(入门GLSL ES这篇就够了)
前端·webgl
随云6324 小时前
WebGL编程指南之进入三维世界
前端·webgl