1、element-plus
官网地址:设计 | Element Plus
安装 plus 及 icon 图标库
1.1 官网提供plus安装方法:
1.2 官网提供 icon 安装方法
1.3 安装
pnpm install element-plus @element-plus/icons-vue
main.ts全局安装element-plus,element-plus默认支持语言英语设置为中文
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 图标全局配置
// 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图标库
pnpm install vite-plugin-svg-icons -D
2.2 vite.config.ts
中配置插件
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import path from 'path'
export default () => {return {plugins: [createSvgIconsPlugin({// Specify the icon folder to be cachediconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],// Specify symbolId formatsymbolId: 'icon-[dir]-[name]',}),],}
}
2.3 main.ts中导入插件
import 'virtual:svg-icons-register'
3、集成sass
我们目前在组件内部已经可以使用scss样式,因为在配置styleLint工具的时候,项目当中已经安装过sass sass-loader,因此我们再组件内可以使用scss语法!!!需要加上lang="scss"
<style scoped lang="scss"></style>
3.1 引入全局样式
新建目录 :src/styles
reset.scss
在styles下 创建reset.scss 文件
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
@import "./reset.scss";
在main.ts中引入 index.scss
import '@/styles'
global.scss
在styles下新建global.scss
//项目提供scss全局变量
将global.scss配置为全局样式组件
在vite.config.ts文件配置如下:
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文件
export default {install(app: any) {},
}
4.1.2 main.ts中引入
import globalComponent from '@/components'//引入全局组件
app.use(globalComponent)
4.2 将element-plus/icon-vue 配置为全局引入
index.ts中加入icon-vue的全局处理代码片段
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
<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 引入到全局组件中
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 引用
<SvgIcon name="full" color="#fff" width="100%" height="100%"></SvgIcon>
4.3配置全局三级下拉选项
4.3.1 编写 Category组件
src/components/Category/index.vue
<template><el-card class="select-container"><el-form inline><el-form-item label="一级分类"><el-selectv-model="category.c1Id"@change="changeC1":disabled="scene == 1"><el-optionv-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-selectv-model="category.c2Id"@change="changeC2":disabled="scene == 1"><el-optionv-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-selectv-model="category.c3Id"@change="props.setIds({c1Id: category.c1Id,c2Id: category.c2Id,c3Id: category.c3Id,})":disabled="scene == 1"><el-optionv-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 引入到全局组件中
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存储属性值
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 引用
<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 = 0let result = await reqAttrInfoList(ids.c1Id, ids.c2Id, ids.c3Id)if (result.code === 200) {attrParams.categoryId = ids.c3IdattrValueList.value = result.data}} else {attrValueList.value = []}
}</script>
4.4 分页pagination
4.4.1 编写分页组件
<template><el-paginationv-model:current-page="page_attr.currentPage"v-model:page-size="page_attr.pageSize":page-sizes="[1, 2, 3, 4, 5]"backgroundlayout="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 = valpage_attr.currentPage = 1handleCurrentChange()
}
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 引入到全局组件中
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 引用
<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.recordsreturn result.data.total
}
</script>