需求简介
如题,iconfont的symbol引用 结合Quasar组件Svg-icons 实现动态加载字体库。
详细的说,就是做左侧菜单的图标选择,图标库使用iconfont,采用symbol引用,而且要做到动态的读取阿里字体库文件的图标,加载到项目内。动态读取图标库的好处是用户可以自己做一套他自己的图标,配置在项目内的字典项中,然后代码无需修改,灵活性更高,也更方便用户实现个性化的网站。
代码实现大致思路就是:阿里图标会生成symbol在线链接,有了这个生成的symbol链接,能看到这是一个js文件,通过接口请求的方式读取js文件内容(会跨域,在项目做由运维帮忙配置即可),再匹配内容中的symbol id="来获取每个图标的类名,从而获取到所有文件的图标的类名集合,然后动态加载项目内即可。
具体的代码实现接下来一步一步讲解。
具体实现
iconfont的symbol引用
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文件,那这也没办法了,因为图标库一旦改变,字典项就要重设,每次都重新加载,才能保证字体文件是最新的正确图标文件。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。