When UI gives multiple SVG ICONS, the front end needs to render different ICONS according to different conditions, and the color of ICONS should be consistent with the color of the surrounding text. For example, in hover state, the color of ICONS and fonts is changed from black to Red. How to achieve this requirement?
About encapsulating SVG icon base components
Typically, you can copy the contents of an SVG file directly into the template and then change the color of its fill.
But here we need to encapsulate the SVG and write an iconbase. vue file as follows (abstract the component according to the SVG format, keep the < SVG > tag, abstract the path part, encapsulate the component, and introduce it dynamically).
encapsulationIconBase
component
The encapsulated IconBase component supports passing in:
- The name of the
iconName
- The width of the
width
- highly
height
- color
iconColor
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
:width="width"
:height="height"
viewBox="0 0 1024 1024"
:aria-labelledby="iconName"
role="presentation"
>
<title :id="iconName" lang="en">{{iconName}} icon</title>
<g :fill="iconColor"> <! --> <component v-bind:is="currentIcon" />
</g>
</svg>
</template>
<script>
import Vue from 'vue'
export default {
props: {
iconName: {
type: String,
default: 'box'
},
width: {
type: [Number, String],
default: 18
},
height: {
type: [Number, String],
default: 18
},
iconColor: {
type: String,
default: 'currentColor'}},data () {
return {
currentIcon: ' '}},created () {
this.getSvgIcon()
},
methods: {
getSvgIcon() { try { this.registerComponent(this.iconName).then(component => { this.currentIcon = component }) } catch (error) { // console.log(error)}}, /** *@desc registerComponent (name) {const files = require.context(); // console.log(error)}}, /** *@desc'@/components/icons/'.false, /\.vue$/)
if (files.keys().includes(`./${name}.vue`)) {
return import('@/components/icons/' + name).then(component => { //eslint-disable-line
return Vue.extend(component.default)
})
} else {
console.log('Icon component not found')
}
}
}
}
</script>
<style scoped>
svg {
display: inline-block;
vertical-align: baseline;
margin-bottom: -2px; /* yes, I'm that particular about formatting */
}
</style>
Copy the code
The method of dynamically loading component resources is explained here in Part 2. Let’s begin by explaining what a component is when it’s abstracted as a dynamic component.
What exactly are components introduced and abstracted dynamically?
Since the iconbase. vue file is introduced as a dynamic component, the SVG file needs to be processed and referenced as a vue component. Each SVG file needs to be encapsulated in the following structure:
<template>
<path
d="M484.266667 272.021333l6.634666 6.72c5.973333 5.973333 13.013333 12.842667 21.098667 20.629334l9.194667-8.917334c7.253333-7.04 13.44-13.184 18.56-18.432a193.28 193.28 0 0 1 277.44 0c75.904 77.525333 76.629333 202.794667 2.133333 281.194667L512 853.333333 204.672 553.237333c-74.474667-78.421333-73.770667-203.690667 2.133333-281.216a193.28 193.28 0 0 1 277.44 0z"
/ >
</template>
Copy the code
It is also important to note that it is best to keep all the SVG encapsulated vue files in one directory for require.context() to use.
How to useIconBase
Components?
After the package is complete, use the following method, where IconLike is an icon file name.
<template>
<div id="app">
<icon-base icon-name="IconLike"></icon-base>111
</div>
</template>
Copy the code
When the hover style is added, the icon color changes with the text color:
<style lang="stylus" scoped>
#app
&:hover
color red
</style>
Copy the code
A description of dynamically loading component resources
In the example above, we used dynamic loading of components. Here’s how to load components dynamically:
Here we use another demo, which was used in the previous visualization large screen configuration project. When you select title, a configuration title component of Echarts, the form component that encapsulates all the configuration items contained in title is dynamically displayed below.
Let’s start with the reasons for using dynamically loaded components
How to do the function shown in the figure? The first thing that comes to mind might be v-if, V-else-if, v-else, but when you have too many conditions you get too redundant, and the page looks complicated. So, in order to simplify the code and reduce the number of steps to manually import components, we use dynamic loading components.
Use dynamic loading components
How to display the corresponding component information according to the selected configuration item? Vue provides the vue.extend() method and the use of is.
is
Expected to receiveString | Object (component Object of options)
. whencurrentView
As you change, the components change. Click on theIs website introductionLook at it.
<template>
<component v-bind:is="currentView"></component>
</template>
Copy the code
- At the same time we need
Vue.extend(component.default)
To implement load registered component resources. In order to optimize the function, there is also an error handling mechanism for not found files to prevent failureimport
Processing on success:
/ / handleChangeApi (value) {try {this.registerComponent(value).then(Component => {this.currentView = component})} catch (error) {// Not found the corresponding file}}Copy the code
userequire.context()
To reduce the manualimport
Here, require.context() is used, so you can see how to use it, which is useful if you need to import a large number of files.
/** *@desc */ registerComponent (name) {const files = require.context(); /** *@desc'./form'.false, /\.vue$/)
if (files.keys().includes(`./${name}.vue`)) {
return import('./form/' + name).then(component => {
return Vue.extend(component.default)
})
} else {
this.$message.error('Configuration item not currently supported')}}Copy the code
That’s how dynamic components are used in VUE.
The above steps illustrate the dynamic use of SVG ICONS in Vue. Finally, insert a little lesson about how a vUE parent passes a picture variable to a child.
Other alternatives
Other tools to help you manage SVG ICONS are:
vue-svg-icon
svg-sprite-loader
svgo-loader
How does a vUE parent pass an image variable to a child?
Usually we use the following code to dynamically import images in vUE:
<img :src="require('.. /.. /assets/happy.png')" />
Copy the code
So if we want to pass variables in require? The answer is no.
Because require’s argument values must be strings.
require
methods
The parent component requires the image transfer directly. Note: the path must not be @/assets, otherwise it will also report an error.
// Parent component <template> <child :icon="require('.. /.. /assets/happy.png')" />
</template>
<script>
import child from './child'
export default {
components: {
child
}
}
</script>
Copy the code
import
methods
The parent component needs to import the image first, and then pass it as an argument to the child component. The advantage of this method is that it can be written as @/assets/happy.png:
// Parent component <template> <child :icon="happy" />
</template>
<script>
import child from './child'
import happy from '@/assets/happy.png'
export default {
components: {
child
},
data () {
return {
happy
}
}
}
</script>
Copy the code
In both scenarios, the child component is written in the same way. The SRC attribute of img is written directly to the variable:
// Child component <template> <img: SRC ="icon" alt />
</template>
<script>
export default {
props: {
icon: {
type: String,
default: ' '
}
},
}
</script>
Copy the code
element-ui
User stamp here: combinedicon
和 img
Compatibility writing method:
If you are a user of elementUI, you may be worried that if an icon is displayed as either el-icon-Edit or img, do we pass the two arguments separately?
Of course not. To make the child components more compatible, it is recommended that the parent pass only one parameter.
Img <child :icon="happy"/ > <! -- import happy from'@/assets/happy.png'--> icon <child :icon="el-icon-eleme"/ > <! -- const el-icon-eleme ='el-icon-eleme' -->
Copy the code
Because through a parameter passing, so need to use a regular in the child components/(. *) \. (PNG | JPG | jpeg | | GIF BMP) $/ and / ^ data: image \ / [a-z] +; Base64 / Determine the type:
// Subcomponent <template> <div> < I v-if="isIcon" :class="icon"></i>
<img v-else :src="icon"/> </div> </template> <script> const IMG_REG = /(.*)\.(png|jpg|jpeg|gif|bmp)$/ const SIMPLE_IMG_BASE_64_REG = /^data:image\/[a-z]+; base64/export default {
props: {
icon: {
type: String,
default: ' '
}
},
computed: {
isIcon () {
return! IMG_REG.test(this.icon) && ! SIMPLE_IMG_BASE_64_REG.test(this.icon) } } } </script>Copy the code