当前位置: 首页 > 后端技术 > Node.js

使用SVG前言构建您自己的图标库

时间:2023-04-04 01:09:55 Node.js

嗨,我是杰伊。在项目开发过程中,很多时候设计师会给你一个SVG图标,让你在项目中作为字体图标使用。也许您现有项目中的某个人已经构建了这个系统。你可以直接把这个文件放到某个文件夹下,然后运行一个命令就可以使用,非常方便。例如,呈现一个图标。那么如果你现在一无所有,让你自己搭建这样一个系统,你会怎么做?一起往下看吧。以下图标素材都是我在网上找的。它们在这里仅用于学习目的。入侵与删除~实操首先使用vite搭建一个项目:npminit生成一个package.json文件,内容如下:{"name":"font","version":"1.0.0","description":"fontproject","main":"index.js","scripts":{"dev":"vite"},"author":"jayliang","license":"ISC",}npmivite-D安装vite,在vite根目录下新建index.html和index.js,在index.html中导入index.js,如下:首先,我们在根目录下创建一个assets文件夹,用来存放SVG文件。然后看下面的代码://index.jsconstapp=document.querySelector('#app')app.innerHTML=render()functionrender(){return`

HelloSVG

${renderIcon('search',{color:'red',fontSize:30})}
`}functionrenderIcon(name,options={color:'black',fontSize:16}){return''}在主要的渲染逻辑中,我们真正需要实现的是renderIcon方法。看上面的姿势,好像renderIcon是要直接返回SVG对应的HTML片段。我们现在手里只有一批SVG文件,怎么能让他返回代码片段呢?虽然在浏览器环境下开发可以动态导入文件,但是读取文件的原文还是有一定的难度。毕竟没有fs.readFile这样的API。这里我们可以写一个简单的预处理脚本,先读出SVG文件的内容,在根目录下创建一个icons文件夹,用来存放脚本处理的结果。这个预处理脚本要处理的事情如下:读取SVG文件的所有内容,转成字符串导出,提取宽高的字符串,填入SVG文件,然后传入as参数。生成一个入口文件以公开所有SVG文件。icons文件夹大概是这样的:index.js//入口文件script.js//生成文件脚本home.js//home.svg生成的文件search.js//search.svg生成的文件脚本实现下面的Take看一下script.js脚本的实现.resolve(__dirname,'../assets')//存放SVG文件的目录constassets=fs.readdirSync(assetsDirPath)constcurrentPath=path.resolve(__dirname,'./')//当前目录,即图标目录资产。forEach(asset=>{constassetPath=`${assetsDirPath}/${asset}`letres=fs.readFileSync(assetPath,{encoding:'utf8'})constreg=/[\s\S]*<\/svg>///过滤掉SVG标签letsvg=reg.exec(res)[0]constdom=newJSDOM(`${svg}
`)//方便操作节点对象constdocument=dom.window.document;constcontainer=document.querySelector('#container');constsvgDom=container.querySelector('svg')svgDom.setAttribute('width','${fontSize}')//宽度和黑度正确的属性处理svgDom.setAttribute('height','${fontSize}')constpaths=svgDom.querySelectorAll('path')for(leti=0;i{constfileName=asset.split('.')[0]importStr+=`import${fileName}from'./${fileName}';\n`exportStr+=`${fileName},\n`})constcontent=`${importStr}exportdefault{${exportStr}}`fs.writeFileSync(currentPath+'/index.js',content)arbitrary处理SVG文件后的JS文件内容是这样的://home.jsexportdefaultfunction({color,fontSize}){return``}最后生成的入口文件index.js的内容是这样的:importhomefrom'./home';importsearchfrom'./search';importsetfrom'./set';exportdefault{home,search,set,}renderIcon实现图标文件和入口脚本经过上面的预处理后,图标的渲染函数就很简单了,实现如下:importiconfrom'./icons'functionrenderIcon(name,options={color:'black',fontSize:16}){consticonRenderFunc=icon[name]if(!iconRenderFunc||typeoficonRenderFunc!=='function'){thrownewError(`icon:${name}isnotfound`)}constres=iconRenderFunc(options)returnres}尝试渲染效果是否如预期:`${renderIcon('search',{col或:'red',fontSize:30})}${renderIcon('home',{color:'pink',fontSize:50})}${renderIcon('set',{color:'black',fontSize:16})}`从上图可以看出渲染基本没问题,我们还需要做一件事render渲染后的SVG标签暴露一个选择器并为其添加鼠标悬停效果修改renderIcon方法如下:functionrenderIcon(name,options={color:'black',fontSize:16},mouseEnterOptions={}){//......constid=genId()svg.id=idsvg.classList+=`icon-${name}`if(Object.keys(mouseEnterOptions).length>0){setTimeout(()=>{constdom=document.querySelector(`#${id}`)const{颜色,fontSize}=mouseEnterOptionsconst{color:originColor,fontSize:originFontsize}=optionsletresetPathColor=nullletresetFontSize=nulldom.addEventListener('mouseenter',()=>{if(color){setPathColor(dom,color)resetPathColor=setPathColor}if(fontSize){setSvgFontsize(dom,fontSize)resetFontSize=setSvgFontsize}})dom.addEventListener('鼠标离开',()=>{resetPathColor&&resetPathColor(dom,originColor)resetFontSize&&resetFontSize(dom,originFontsize)})},0)}}函数setSvgFontsize(svg,fontSize){svg.setAttribute('width',fontSize)svg.setAttribute('height'fontSize)}functionsetPathColor(svg,color){constpaths=svg.querySelectorAll('路径');[...paths].forEach(path=>{path.setAttribute('fill',color)})}增加一个mouseEnterOptions参数定义鼠标移入的参数,然后监听mouseenter和mouseleave事件。当然,你可以使用框架封装使用的形式会更优雅。字体图标库我们使用node.js预处理SVG文件+渲染逻辑,基本实现了一个可以满足大部分业务场景的图标库。所以业界比较通行的做法是用SVG作为字体,也就是我开头说的,也许你渲染一个图标只要就可以了,咱们一起去看看它是怎么做到的。我们会用到一个非常牛逼的字体操作库——font-carrier,这是一个在GitHub上有1.5kstar的star第三方包,可以很方便的使用SVG生成字体。先安装npmifont-carrier-D,然后在根目录下新建一个fonts目录,在该目录下新建script.js,写入内容如下:constfontCarrier=require('font-carrier')constpath=require('path')constfs=require('fs')constassetsDirPath=path.resolve(__dirname,'../assets')constassets=fs.readdirSync(assetsDirPath)constfont=fontCarrier.create()letinitValue=0xe000for(leti=0;i上面的伪类我们直接使用如果指定字体对应的unicode编码,也可以使用CSS伪类形式,这也是业界使用最多的形式。基于以上,再生成一个icon.css来记录这些伪类信息即可。代码如下:consticonMap={}for(leti=0;i{constname=key.replace('.svg','')constvalue=iconMap[key]content+=`.icon-${name}::before{content:'${value}'}`})fs.writeFileSync('./icon.css',content)生成icon.css内容如下:.icon-home::before{content:'\E001'}.icon-search::before{content:'\E002'}.icon-set::before{content:'\E003'}我们可以通过以这种方式使用图标。最后,以上就是本文的全部内容。在平时的项目开发过程中如何使用这样的图标库呢?欢迎留言讨论。如果觉得有趣或者对你有帮助,请点个赞~