我正在参加「掘金·启航计划」
亲爱的UI设计师,在设计页面样式(看着好像一样但又不一样😂),组件总有结构一样,颜色总不一样。你能怎么办?
每次都添加新的png到文件中?
这个不可能啊!!!!,这种东西还是不要再添加新的png文件了。
都现在了,都来感受一下svg组件的魅力吧。
为什么要使用svg组件?
答:因为svg很方便、很快乐,它能大能小不模糊,它能红能绿也能黄,那么多优点,让我去选择svg,可是如果每一个svg都需要去引入重写,岂不是很麻烦,所以封成组件进行展示,才是优选。
svg简介
SVG 是一种基于 XML 语法的图像格式,全称是可缩放矢量图(Scalable Vector Graphics)。
SVG 则是属于对图像的形状描述,所以它本质上是文本文件,体积较小,且不管放大多少倍都不会失真。
svg在webpack中使用
用开源的前端打包工具webpack,去使用svg。
npm包
安装:svg-sprite-loader
作用:使个体的svg,去构建一个类似大型的svg雪碧图。
安装:svgo-loader
。
作用:去除svg 自带的 fill 属性给清除掉。
配置
如何配置就不多说,网上还是有很多关于在webpack中的使用方法,这篇文章主要讲述svg在vite中的使用。
为大家找到了一些相关配置文章地址:
1、使用 svg-sprite-loader、svgo-loader
就算是webpack的配置,下面的组件化svg还是对你有点用的,耐心向下看看。
svg在vite中使用
用新型的前端构建工具vite,去使用svg。
npm包
安装:vite-plugin-svg-icons
作用:去构建生成 svg 画面映射(雪碧图)。
tips:如果需要请先看一下文档:GitHub - vbenjs/vite-plugin-svg-icons: Vite Plugin for fast creating SVG sprites.,文档将使用方法说的很清楚,我这边也就拿来做一些必要处理。
安装:___暂无____
作用:自动去除svg中属性fill(先占位)。
tips:可惜的是我没能找到,像webpack插件那样自动化消除掉项目文件下的svg中fill属性的方法,目前我还是使用手动去删除掉svg的fill属性。
怎么个手动法?
引入svg文件,在VScode等编辑器中打开,使用ctrl+F
搜索fill
直接把fill="#CCC"
删除,效果如下
// ... 是我省略的数据
<svg ... ><path d="..." p-id="2526" fill="#1afa29"></path></svg>
删除fill属性
// ... 是我省略的数据
<svg ... ><path d="..." p-id="2526"></path></svg>
嗯,放在文件下即可了,到时候我们传什么颜色,他就是什么颜色。
配置
在vite中配置
import { createSvgIconsPlugin } from "vite-plugin-svg-icons";
defineConfig({
plugins: [
createSvgIconsPlugin({
// 指定需要缓存的图标文件夹
iconDirs: [resolve(process.cwd(), "./src/assets/svgs")],
// 指定symbolID的格式
symbolId: "icon-[name]"
})
],
})
使用
都差不多啊,这里使用的是vue3,改一下vue2也能用的。
创建组件
<script setup>
import { computed, toRefs } from "vue";
const props = defineProps({
name: {
type: String,
required: true
},
color: {
type: String,
default: ""
}
});
const { name, color } = toRefs(props);
const iconName = computed(() => {
return `#icon-${name.value}`;
});
const svgClass = computed(() => {
if (name.value) return `svg-icon icon-${name.value}`;
return "svg-icon";
});
</script>
<template>
<svg :class="svgClass" aria-hidden="true">
<use :xlink:href="iconName" :fill="color"/>
</svg>
</template>
<style scoped>
.svg-icon {
width: 1em;
height: 1em;
vertical-align: middle;
fill: currentColor;
object-fit: contain;
}
</style>
解析:
为什么使用em
的单位?
em
:相对长度单位规定相对于另一个长度属性的长度。相对长度单位在不同渲染介质之间缩放表现得更好,而且因为1em可以很好与组件font-size大小相照应,em是看父级的font-size大小,这不就刚刚好就控制住了svg的width与height大小。
也就是说,在引入组件,给予font-size就可以修改svg的高与宽了。
全局使用
// 使用svg组件
import "virtual:svg-icons-register";
import SvgIcon from "@/components/Icon/SvgIcon.vue";
const app = createApp(App);
app.component("svg-icon", SvgIcon);
解析:
为什么使用:virtual:svg-icons-register
?
virtual:XXX
:在vite中的称为虚拟模块的引入。
详情看:插件 API | Vite 官方中文文档 (vitejs.dev),点击传送到相关位置。
使用
<svg-icon class="icon" name="xingxing" color="#7bd57b"/>
解析:
svg-icon
组件为什么不将font-size
写行内标签中?
移动端的自动适配不会将行内px
转为rem
,写在css中可以实现转化。
name
:该属性是svg的名字。
color
:该属性是svg颜色,传递进去到fill属性中。
展示一下svg列表
为什么展示一下?
不展示一下,你怎么知道用什么那个svg,最好还是能点击可以复制的(强行自己添加需求)。
vant的插件?
这个项目是移动端,所以引入的有vant插件,去布局排版,也就有了我上面提醒的font-size
问题。
<script setup>
import { Col as vanCol, Row as vanRow } from "vant";
import { clickCopy } from "./index.js";
import { ref, computed } from "vue";
const requireContextSvg = import.meta.globEager("../../../assets/svgs/*.svg");
const svgIconList = Object.keys(requireContextSvg).map(fileName => {
fileName = fileName.replace(/[^]+[/]/, "").replace(/.svg/g, "");
return fileName;
});
const svgIconListCopyToForList = computed(() => {
let newList = [];
let vantRowSize = svgIconList.length / 4;
for (let index = 0; index < vantRowSize; index++) {
newList.push(svgIconList.slice(4 * index, 4 * (index + 1)));
}
return newList;
});
</script>
<template>
<vanRow v-for="(itemRow,indexRow) in svgIconListCopyToForList" align="center" class="svg-van-row" :key="indexRow">
<vanCol class="svg-van-col" span="6" v-for="(itemCol, indexCol) in itemRow" :key="indexCol">
<div class="svg-van-icon" @click="clickCopy(`<svg-icon name='${itemCol}'/>`)">
<svg-icon class="icon" :name="itemCol" color="#7bd57b"/>
<p class="name">{{itemCol}}</p>
</div>
</vanCol>
</vanRow>
</template>
<style lang="scss" scoped>
.icon-container{
.svg-van-row{
// text-align: center;
.svg-van-col{
padding: 15px;
.svg-van-icon{
display: flex;
flex-direction: column;
align-items: center;
}
}
}
.icon{
font-size: 46px;
}
.name{
font-size: 14px;
margin: 8px 0 0 0;
height: 28px;
text-align: center;
}
}
</style>
解析:
import.meta.globEager
:vite提供的批量导入某些文件,实现项目的模块化的函数。
来看一下import.meta - JavaScript | MDN (mozilla.org),里面写了用法。
import.meta.globEager("../../../assets/svgs/*.svg")
中*代表一个目录下的文件,**就表示是一个目录下的文件与文件夹(可以拿到该文件夹下面全部的该类型的文件)。
svgIconListCopyToForList
:这个就是自己对数组的重新构建,下面template需要的循环格式。
复制代码
下面是复制代码的代码段,不适合部分手机端使用,是会出现兼容问题的,浏览器上开发使用时绰绰有余。 注意:如果想在手机端H5页面使用复制,请去关注一下其他方法,该方法可能不太够用。
import { Toast } from "vant";
// 能简单复制,不设计兼容
export function clickCopy(htmlValue) {
let isCopySuccess = true;
if (!htmlValue) isCopySuccess = false;
let copyText = isCopySuccess ? "复制成功:" : "复制失败:";
if (navigator.clipboard && window.isSecureContext) {
Toast(copyText + htmlValue);
return navigator.clipboard.writeText(htmlValue);
} else {
const textArea = document.createElement("textarea");
textArea.value = htmlValue;
// 使text area不在vieport中,同时不可见
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
Toast(copyText + htmlValue);
document.execCommand("copy");
textArea.remove();
return true;
}
};
总结
1、设计师发送png图片,你可以上传到阿里适量库中,再选择svg复制下来,不就是纯洁的svg代码了。
2、svg封成组件自己团队用还是很爽的。
3、祝你我好运