【web】2、集成插件

1、element-plus

官网地址:设计 | Element Plus

安装 plus 及 icon 图标库

1.1 官网提供plus安装方法:

1.2 官网提供 icon 安装方法

1.3 安装

bash 复制代码
pnpm install element-plus @element-plus/icons-vue

main.ts全局安装element-plus,element-plus默认支持语言英语设置为中文

javascript 复制代码
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css'
//@ts-ignore忽略当前文件ts类型的检测否则有红色提示(打包会失败)
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
app.use(ElementPlus, {
    locale: zhCn
})

1.4 图标全局配置

javascript 复制代码
// main.ts

// 如果您正在使用CDN引入,请删除下面一行。
import * as ElementPlusIconsVue from '@element-plus/icons-vue'

const app = createApp(App)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
  app.component(key, component)
}

2、SVG图标配置

在开发项目的时候经常会用到svg矢量图,而且我们使用SVG以后,页面上加载的不再是图片资源,

这对页面性能来说是个很大的提升,而且我们SVG文件比img要小的很多,放在项目中几乎不占用资源。

官网地址:iconfont-阿里巴巴矢量图标库

2.1 安装svg图标库

bash 复制代码
pnpm install vite-plugin-svg-icons -D

2.2 vite.config.ts 中配置插件

javascript 复制代码
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import path from 'path'
export default () => {
  return {
    plugins: [
      createSvgIconsPlugin({
        // Specify the icon folder to be cached
        iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],
        // Specify symbolId format
        symbolId: 'icon-[dir]-[name]',
      }),
    ],
  }
}

2.3 main.ts中导入插件

javascript 复制代码
import 'virtual:svg-icons-register'

3、集成sass

我们目前在组件内部已经可以使用scss样式,因为在配置styleLint工具的时候,项目当中已经安装过sass sass-loader,因此我们再组件内可以使用scss语法!!!需要加上lang="scss"

html 复制代码
<style scoped lang="scss"></style>

3.1 引入全局样式

新建目录 :src/styles

reset.scss

在styles下 创建reset.scss 文件

css 复制代码
html {
  -webkit-text-size-adjust: 100%
}

html:focus-within {
  scroll-behavior: smooth
}

body {
  -webkit-text-size-adjust: 100%;
  -moz-text-size-adjust: 100%;
  text-size-adjust: 100%;
  -moz-osx-font-smoothing: grayscale;
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
  position: relative;
  text-rendering: optimizeSpeed;
  width: 100%
}

*, :after, :before {
  box-sizing: border-box
}

a:not([class]) {
  -webkit-text-decoration-skip: ink;
  text-decoration-skip-ink: auto
}

a, abbr, acronym, address, applet, article, aside, audio, b, big, blockquote, body, canvas, caption, center, cite, code, dd, del, details, dfn, div, dl, dt, em, embed, fieldset, figcaption, figure, footer, form, h1, h2, h3, h4, h5, h6, header, hgroup, html, i, iframe, img, ins, kbd, label, legend, li, mark, menu, nav, object, ol, output, p, pre, q, ruby, s, samp, section, small, span, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, time, tr, tt, u, ul, var, video {
  border: 0;
  font-size: 100%;
  font: inherit;
  margin: 0;
  padding: 0;
  vertical-align: baseline
}

:focus {
  outline: 0
}

article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section {
  display: block
}

ol, ul {
  list-style: none
}

blockquote, q {
  quotes: none
}

blockquote:after, blockquote:before, q:after, q:before {
  content: "";
  content: none
}

input, input:required {
  box-shadow: none
}

input:-webkit-autofill, input:-webkit-autofill:active, input:-webkit-autofill:focus, input:-webkit-autofill:hover {
  -webkit-box-shadow: inset 0 0 0 30px #fff
}

input[type=search]::-webkit-search-cancel-button, input[type=search]::-webkit-search-decoration, input[type=search]::-webkit-search-results-button, input[type=search]::-webkit-search-results-decoration {
  -webkit-appearance: none;
  -moz-appearance: none
}

input[type=search] {
  -webkit-appearance: none;
  -moz-appearance: none
}

input:focus {
  outline: none
}

audio, canvas, video {
  display: inline-block;
  max-width: 100%
}

audio:not([controls]) {
  display: none;
  height: 0
}

[hidden] {
  display: none
}

a:active, a:hover {
  outline: none
}

img {
  height: auto;
  max-width: 100%;
  vertical-align: middle
}

img, picture {
  display: inline-block
}

button, input {
  line-height: normal
}

button, html input[type=button], input[type=reset], input[type=submit] {
  -webkit-appearance: button;
  background: transparent;
  border: 0;
  cursor: pointer
}

button[disabled], html input[disabled] {
  cursor: default
}

[disabled] {
  pointer-events: none
}

input[type=checkbox], input[type=radio] {
  padding: 0
}

input[type=search] {
  -webkit-appearance: textfield;
  box-sizing: content-box
}

input[type=search]::-webkit-search-cancel-button, input[type=search]::-webkit-search-decoration {
  -webkit-appearance: none
}

button::-moz-focus-inner, input::-moz-focus-inner {
  border: 0;
  padding: 0
}

button {
  background: transparent;
  border: 0
}

textarea {
  overflow: auto;
  resize: vertical;
  vertical-align: top
}

table {
  border-collapse: collapse;
  border-spacing: 0;
  text-indent: 0
}

hr {
  background: #000;
  border: 0;
  box-sizing: content-box;
  height: 1px;
  line-height: 0;
  margin: 0;
  overflow: visible;
  padding: 0;
  page-break-after: always;
  width: 100%
}

pre {
  font-family: monospace, monospace;
  font-size: 100%
}

a {
  background-color: transparent
}

abbr[title] {
  border-bottom: none;
  text-decoration: none
}

code, kbd, pre, samp {
  font-family: monospace, monospace
}

small, sub, sup {
  font-size: 75%
}

sub, sup {
  line-height: 0;
  position: relative;
  vertical-align: baseline
}

sub {
  bottom: -5px
}

sup {
  top: -5px
}

button, input, optgroup, select, textarea {
  font-family: inherit;
  font-size: 100%;
  line-height: 1;
  margin: 0;
  padding: 0
}

button, input {
  overflow: visible
}

button, select {
  text-transform: none
}

[type=button], [type=reset], [type=submit], button {
  -webkit-appearance: button
}

[type=button]::-moz-focus-inner, [type=reset]::-moz-focus-inner, [type=submit]::-moz-focus-inner, button::-moz-focus-inner {
  border-style: none;
  outline: 0;
  padding: 0
}

legend {
  border: 0;
  color: inherit;
  display: block;
  max-width: 100%;
  white-space: normal;
  width: 100%
}

fieldset {
  min-width: 0
}

body:not(:-moz-handler-blocked) fieldset {
  display: block
}

progress {
  vertical-align: baseline
}

[type=number]::-webkit-inner-spin-button, [type=number]::-webkit-outer-spin-button {
  height: auto
}

[type=search] {
  -webkit-appearance: textfield;
  outline-offset: -2px
}

[type=search]::-webkit-search-decoration {
  -webkit-appearance: none
}

::-webkit-file-upload-button {
  -webkit-appearance: button;
  font: inherit
}

summary {
  display: list-item
}

template {
  display: none
}

index.scss

在styles下新建index.scss

css 复制代码
@import "./reset.scss";

在main.ts中引入 index.scss

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

global.scss

在styles下新建global.scss

css 复制代码
//项目提供scss全局变量

将global.scss配置为全局样式组件

在vite.config.ts文件配置如下:

javascript 复制代码
export default defineConfig((config) => {
	css: {
      preprocessorOptions: {
        scss: {
          javascriptEnabled: true,
          additionalData: '@import "./src/styles/global.scss";',
        },
      },
    },
}

@import "./src/styles/variable.less";后面的;不要忘记,不然会报错!

4、封装全局组件

4.1配置全局组件引入

4.1.1 创建index.ts

src/components 下新建index.ts文件

TypeScript 复制代码
export default {
  install(app: any) {

  },
}

4.1.2 main.ts中引入

TypeScript 复制代码
import globalComponent from '@/components'

//引入全局组件
app.use(globalComponent)

4.2 将element-plus/icon-vue 配置为全局引入

index.ts中加入icon-vue的全局处理代码片段

TypeScript 复制代码
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import type { App, Component } from 'vue';

export default {
  install(app: any) {

    for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
      app.component(key, component)
    }

  },
}

4.2 配置全局SvgIcon

4.2.1编写SvgIcon自定义组件

src/components/SvgIcon/index.vue

html 复制代码
<template>
  <!-- svg:图标外层容器节点,内部需要与use标签结合使用 -->
  <svg :style="{ width, height }">
    <!-- xlink:href执行用哪一个图标,属性值务必#icon-图标名字 -->
    <!-- use标签fill属性可以设置图标的颜色 -->
    <use :xlink:href="prefix + name" :fill="color"></use>
  </svg>
</template>

<script setup lang="ts" name="SvgIcon">
//接受父组件传递过来的参数
defineProps({
  //xlink:href属性值前缀
  prefix: {
    type: String,
    default: '#icon-',
  },
  //提供使用的图标名字
  name: String,
  //接受父组件传递颜色
  color: {
    type: String,
    default: '',
  },
  //接受父组件传递过来的图标的宽度
  width: {
    type: String,
    default: '16px',
  },
  //接受父组件传递过来的图标的高度
  height: {
    type: String,
    default: '16px',
  },
})
</script>

<style scoped></style>

4.2.2 引入到全局组件中

TypeScript 复制代码
import SvgIcon from '@/components/SvgIcon/index.vue'
const allGlobalComponents: any = {
  SvgIcon,
}

export default {
  install(app: any) {
    Object.keys(allGlobalComponents).forEach((key) => {
      app.component(key, allGlobalComponents[key])
    })
  },
}

4.2.3 引用

html 复制代码
<SvgIcon name="full" color="#fff" width="100%" height="100%"></SvgIcon>

4.3配置全局三级下拉选项

4.3.1 编写 Category组件

src/components/Category/index.vue

html 复制代码
<template>
  <el-card class="select-container">
    <el-form inline>
      <el-form-item label="一级分类">
        <el-select
          v-model="category.c1Id"
          @change="changeC1"
          :disabled="scene == 1"
        >
          <el-option
            v-for="item in category.c1List"
            :key="item.id"
            :label="item.name"
            :value="item.id"
          ></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="二级分类">
        <el-select
          v-model="category.c2Id"
          @change="changeC2"
          :disabled="scene == 1"
        >
          <el-option
            v-for="item in category.c2List"
            :key="item.id"
            :label="item.name"
            :value="item.id"
          ></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="三级分类">
        <el-select
          v-model="category.c3Id"
          @change="
            props.setIds({
              c1Id: category.c1Id,
              c2Id: category.c2Id,
              c3Id: category.c3Id,
            })
          "
          :disabled="scene == 1"
        >
          <el-option
            v-for="item in category.c3List"
            :key="item.id"
            :label="item.name"
            :value="item.id"
          ></el-option>
        </el-select>
      </el-form-item>
    </el-form>
  </el-card>
</template>

<script setup lang="ts">
import { onMounted, reactive } from 'vue'

const props = defineProps(['getCategory', 'setIds', 'scene'])
let category = reactive<any>({
  c1List: [],
  c2List: [],
  c3List: [],
  c1Id: '',
  c2Id: '',
  c3Id: '',
})

const changeC1 = async () => {
  category.c2Id = ''
  category.c3Id = ''
  props.setIds({
    c1Id: '',
    c2Id: '',
    c3Id: '',
  })
  let res = await props.getCategory(2, category.c1Id)
  if (res.length > 0) {
    category.c2List = res
  }
}

const changeC2 = async () => {
  category.c3Id = ''
  props.setIds({
    c1Id: '',
    c2Id: '',
    c3Id: '',
  })
  let res = await props.getCategory(3, category.c2Id)
  if (res.length > 0) {
    category.c3List = res
  }
}

onMounted(async () => {
  let res = await props.getCategory(1, 0)
  if (res.length > 0) {
    category.c1List = res
  }
})
</script>
<script lang="ts">
export default {
  name: 'Category',
}
</script>

<style scoped lang="scss">
.el-form-item {
  .el-select {
    width: 200px;
  }
}
</style>

4.3.2 引入到全局组件中

TypeScript 复制代码
import Category from '@/components/category/index.vue'

const allGlobalComponents: any = {
  Category,
}

export default {
  install(app: any) {
    Object.keys(allGlobalComponents).forEach((key) => {
      app.component(key, allGlobalComponents[key])
    })
    
  },
}

4.3.3 stores存储属性值

TypeScript 复制代码
import { defineStore } from 'pinia'
import { reqCategoryList } from '@/api/product/attr'
import { ElMessage } from 'element-plus'

export const useProductAttrStore = defineStore('ProductAttr', () => {
  const getCategory = async (type: number, categoryId: number) => {
    const result = await reqCategoryList(type, categoryId)
    if (result.code == 200) {
      return result.data
    } else {
      ElMessage({
        message: '查询分类失败',
        type: 'error',
      })
      return []
    }
  }
  return { getCategory }
})

4.3.4 引用

html 复制代码
<Category
      :getCategory="attrStore.getCategory"
      :setIds="setIds"
      :scene="scene"
    />
<script setup lang="ts">
import { useProductAttrStore } from '@/stores/models/product/attr'
import { reactive, ref } from 'vue'

let scene = ref(0)
let attrValueList = ref([])

const attrStore = useProductAttrStore()

const attrParams = reactive({
  attrName: '',
  attrValueList: [],
  categoryId: '',
  categoryLevel: 3,
})

const ids = reactive({
  c1Id: '',
  c2Id: '',
  c3Id: '',
})

const setIds = async (idData: any) => {
  Object.assign(ids, idData)
  await getAttrValueList()
}
const getAttrValueList = async () => {
  if (ids.c3Id != '') {
    scene.value = 0
    let result = await reqAttrInfoList(ids.c1Id, ids.c2Id, ids.c3Id)
    if (result.code === 200) {
      attrParams.categoryId = ids.c3Id
      attrValueList.value = result.data
    }
  } else {
    attrValueList.value = []
  }
}

</script>

4.4 分页pagination

4.4.1 编写分页组件

html 复制代码
<template>
  <el-pagination
    v-model:current-page="page_attr.currentPage"
    v-model:page-size="page_attr.pageSize"
    :page-sizes="[1, 2, 3, 4, 5]"
    background
    layout="prev, pager, next, -> ,total, sizes"
    :total="page_attr.total"
    @size-change="handleSizeChange"
    @current-change="handleCurrentChange"
  />
</template>

<script setup lang="ts">
import { onMounted, reactive } from 'vue'

const props = defineProps(['select'])

//分页器
const page_attr = reactive({
  currentPage: 1,
  pageSize: 2,
  total: 10,
})

const handleSizeChange = (val: number) => {
  page_attr.pageSize = val
  page_attr.currentPage = 1
  handleCurrentChange()
}
const handleCurrentChange = async () => {
  page_attr.total = await props.select(
    page_attr.currentPage,
    page_attr.pageSize,
  )
}

onMounted(async () => {
  await handleCurrentChange()
})
</script>
<script lang="ts">
export default {
  name: 'Pagination',
}
</script>

<style scoped lang="scss"></style>

4.4.2 引入到全局组件中

html 复制代码
import Pagination from '@/components/pagination/index.vue'

const allGlobalComponents: any = {
  Pagination,
}

export default {
  install(app: any) {
    Object.keys(allGlobalComponents).forEach((key) => {
      app.component(key, allGlobalComponents[key])
    })
  },
}

4.4.3 引用

html 复制代码
<Pagination :select="select" />

<script setup lang="ts">

let tradeMarkList = ref()

//分页
const select = async (currentPage: number, pageSize: number) => {
  //下面为具体型业务逻辑
  let result = await reqTradeMarkList(currentPage, pageSize)
  tradeMarkList.value = result.data.records
  return result.data.total
}
</script>
相关推荐
To_OC5 小时前
别再串行写 await 了,Promise.all 才是并行请求的正确打开方式
前端·javascript·promise
To_OC6 小时前
LC 17 电话号码的字母组合:我的回溯算法,就是从这道题开窍的
javascript·算法·leetcode
vipbic6 小时前
中后台越做越乱后,我用插件化把它救回来了
前端·vue.js
Hyyy6 小时前
Computer Use 适合做什么,不适合做什么——一次真实使用后的思考
前端
小和尚同志6 小时前
前端 AI 单元测试思考与落地
前端·人工智能·aigc
invicinble8 小时前
c端系统,其实更像一个信息展示平台
前端
你怎么知道我是队长8 小时前
JavaScript的变量和数据类型介绍
开发语言·javascript·ecmascript
李姆斯8 小时前
管理是否可以被完全量化
前端·产品经理·团队管理
名字还没想好☜9 小时前
Next.js 中间件实战:鉴权、重定向与 A/B 分流
开发语言·前端·javascript·中间件·react·next.js
广州灵眸科技有限公司9 小时前
瑞芯微RV1126B开发板(EASY-EAI-PI2) INI文件操作
java·前端·javascript·网络·人工智能