如题,iconfont的symbol引用 结合Quasar组件Svg-icons 实现动态加载字体库。
详细的说,就是做左侧菜单的图标选择,图标库使用iconfont,采用symbol引用,而且要做到动态的读取阿里字体库文件的图标,加载到项目内。动态读取图标库的好处是用户可以自己做一套他自己的图标,配置在项目内的字典项中,然后代码无需修改,灵活性更高,也更方便用户实现个性化的网站。
代码实现大致思路就是:阿里图标会生成symbol在线链接,有了这个生成的symbol链接,能看到这是一个js文件,通过接口请求的方式读取js文件内容(会跨域,在项目做由运维帮忙配置即可),再匹配内容中的symbol id="来获取每个图标的类名,从而获取到所有文件的图标的类名集合,然后动态加载项目内即可。
具体的代码实现接下来一步一步讲解。
iconfont的symbol引用
参考上面的symbol引用的使用步骤,应用到项目中,这里因为项目是使用Quasar框架的,所以结合Quasar组件Svg-icons 来实现。
因为我们是要做动态加载库,所以不用拷贝链接写死在项目内。直接从第二步开始,二三步骤的内容可以放置在一个组件内:
代码如下:
<template> <q-icon> <svg :class="svgClass" aria-hidden="true" v-on="$listeners" > <use :xlink:href="iconName" /> </svg> </q-icon> </template> <script> // doc: https://quasar.dev/vue-components/icon#Inlined-svg export default { name: 'IconSvg', props: { iconClass: { type: String, default: '' } }, computed: { iconName () { return `#${this.iconClass}` }, svgClass () { return 'icon-svg' } } } </script> <style scoped> .icon-svg { width: 1em; height: 1em; vertical-align: -0.15em; fill: currentColor; overflow: hidden; } </style>
现在图标使用的阿里云图标库是这个,这里上传或者修改图标后,会重新生成图标库的在线链接。每次图标发生变动,需要在项目中更改新的字体图标库的链接,在字典iconfont里修改数据值。字典项可添加一个或者多个阿里图标库的链接。
先准备接口请求api:
// 菜单iconfont字典项 export function getMenuIcon () { return request({ url: '/xxx/dict/type/iconfont', // 字典项接口 method: 'get' }) } // 读取阿里云图标库文件 export function getIconSymbol (url) { return request({ baseURL: process.env.ICON_URL, // 运维帮忙配置的代理服务器 url: url, // 只需要js文件的名字 method: 'get' }) }
然后,在菜单管理页面,加载选择图标下拉框数据:
getIconList () { getMenuIcon().then(async ({ data }) => { if (data.code === 0) { const iconfontList = data.data.map(_ => _.value) let allSymbol = [] // 读取 阿里云字体库 文件 for (let index = 0; index < iconfontList.length; index++) { const ele = iconfontList[index] loadScript(ele) const url = ele.replace('//at.alicdn.com/t', '') // 只需要获取js文件名字即可 const response = await getIconSymbol(url) // eslint-disable-next-line no-useless-escape const symbol = [...response.data.matchAll(/symbol id=\"((\w|\-)+)/g)].map(_ => _[1]) allSymbol = allSymbol.concat(symbol) } // console.log('所有文件的图标集合:' + allSymbol) this.stringOptions = allSymbol this.iconOptions = extend(true, this.stringOptions, this.iconOptions) } }) },
先获取到文件的路径,然后通过接口请求的方式读取js文件内容,再匹配内容中的symbol id="来获取每个图标的类名,最终获取到所有文件的图标的类名集合,同时,动态加载js文件。
其中,动态插入script如下:
// 动态插入script export function loadScript (src) { const s = document.createElement('script') s.type = 'text/javascript' s.src = src document.body.appendChild(s) }
下拉框是Quasar select组件实现:
<q-select class="xxx-select" outlined use-input input-debounce="0" v-model="form.icon" :options="iconOptions" @filter="filterFn" clearable > <template v-slot:option="scope"> <q-item v-bind="scope.itemProps" v-on="scope.itemEvents" > <q-item-section avatar> <icon-svg :icon-class="scope.opt"></icon-svg> </q-item-section> <q-item-section> <q-item-label v-html="scope.opt" /> </q-item-section> </q-item> </template> </q-select>
filterFn (val, update) { if (val === '') { update(() => { this.iconOptions = this.stringOptions }) return } update(() => { const needle = val.toString().toLowerCase() this.iconOptions = this.stringOptions.filter(v => v.toLowerCase().indexOf(needle) > -1) }) }
效果如下:
菜单管理中配置好的图标,会相应的显示在左侧菜单中,这里需要全局的一个加载图标库:
actions:
// 获取字体库 GetFontList ({ commit }) { return new Promise((resolve, reject) => { getMenuIcon().then(({ data }) => { if (data.code === 0) { const iconfontList = data.data.map(_ => _.value) // 动态加载阿里云字体库 iconfontList.forEach(ele => { loadScript(ele) }) } resolve() }).catch(e => { reject(e) }) }) }
左侧菜单组件内同样使用IconSvg组件显示图标:
created () { this.$store.dispatch('app/GetFontList') },
如果这里获取不到图标库,那么,图标可能显示不出来。
最大的问题就是可能会出现很多重复加载的字体库js文件,那这也没办法了,因为图标库一旦改变,字典项就要重设,每次都重新加载,才能保证字体文件是最新的正确图标文件。