If you’ve only heard of this icon library from ByteDance, you may have turned this article off, but if you’ve already used it, I’m sure this article will answer one of your questions.

Code word is not easy, click a “like” and then go, the recent two articles are collected than the “like” is how to return the matter =_=!

What is Icon Park

IconPark, a byteDance icon library, is similar to Alibaba’s IconFont.

IconPark icon library is an icon library product driven by technology vector icon style. It can transform a variety of themes according to a single SVG source file, with rich classification, lighter code and more flexible use scenarios. It is committed to building high-quality, unified and definable icon resources, so that most designers can choose their own style ICONS. It also supports exporting icon source files into component codes in various forms such as React, Vue2, Vue3 and SVG, opening up the Design to Code link. To achieve one-stop docking of products, RESEARCH and development, designers, more efficient use, with a patent for invention.

Yes, IconPark is not only a standardised set of SVG icon materials, but also a Npm package for it that ADAPTS to major front-end frameworks. It can be easily imported into your project using import statements and used directly as a component.

Vue3, for example, uses the big hump of the icon name as the component name, and binds some props to the template:

<template>
    <Home theme="filled"/>
</template>
<script>
import {Home} from '@icon-park/vue-next';

export default {
    components: {
        Home
    }
}
</script>
Copy the code

Some of the supported Props, as you can see, are almost entirely properties of the SVG element:

The attribute name introduce type The default value
theme Icon theme ‘outline’ | ‘filled’ | ‘two-tone’ | ‘multi-color’ ‘outline’
size ICONS of the same size, width and height number | string ‘1em’
spin Add a rotation effect to the icon boolean false
fill Icon color, no more than 4 colors, default to the current color string | string[] ‘currentColor’
strokeLinecap The stroke-linecap attribute of an SVG element ‘butt’ | ’round’ | ‘square’ ’round’
strokeLinejoin The stroke-linejoin attribute of an SVG element ‘miter’ | ’round’ | ‘bevel’ ’round’
strokeWidth The stroke-width property of an SVG element number 4

For example,
is a list of users, so it might look like a table or list. The content should contain some user information, and the actions might include new/edit/delete. And self-closing means there is no design slot function.


might confuse me with a Home page component, but the meaning of the tag should tell developers: I’m a little icon, I have one property that controls what I display, another property that controls color/size, etc. That makes sense.

Fortunately, Icon Park provides this reference:

<template>
    <IconPark type="AddText" theme="filled"/>
    <IconPark type="add-text" theme="filled"/>
</template>
<script>
import { IconPark } from '@icon-park/vue-next/es/all';

export default {
    components: {
        IconPark
    }
}
</script>
Copy the code

The type attribute accepts a valid Icon name, which can be either a bar name or a big camel name. Icon Park internally converts the bar to a big camel name.

For more information about IconPark, please visit the official website of IconPark to learn by yourself.

Overhand Icon Park

The biggest value of IconPark is that it has up to 2,437 ICONS in the same style (as of 2022.03.05), which is too friendly for some companies or individual developers without UI designers. Finally, they don’t have to worry about finding some ICONS from different icon libraries that meet their needs but are obviously different in style to cover their business needs.

So, bring in the project.

, for the sake of unity project style icon of line thicknesses style/color/size/theme, should be almost the same, this means that the strokeWidth/size/fill/theme these prop values should be the same. IconPark uses vue3’s provide method to implement global configuration, but why not encapsulate a component for later use?

Open dry.

Create a new vue file and write it using setup syntax sugar and typescript.

  • The DOM structure should be very simple, with a SPAN tag as a container, allowing IconPark to fill in SVG tags;
  • In terms of props, we mapped some commonly used Icon Park properties. Most of the properties should have default values set according to the project style, such as color/size/theme, to perform type verification.
  • Remember to import the CSS files required by IconPark;
<template>
  <IconPark v-bind="{... $props,... $attrs}"></IconPark>
</template>
<script lang="ts" setup>
  import { IconPark } from '@icon-park/vue-next/es/all';
  import { IconThemeEnum } from '/@/enums/appEnum';
  import { computed, toRefs, ref, watch, render, createVNode, nextTick, onMounted } from 'vue';
  import { propTypes } from '/@/utils/propTypes';import '@icon-park/vue-next/styles/index.css';

  const props = defineProps({
    icon: propTypes.string.isRequired,
    theme: propTypes.oneOf(Object.values(IconThemeEnum)).def(IconThemeEnum.MULLTI),
    size: propTypes.oneOfType([propTypes.string, propTypes.number]).def(20),
    spin: propTypes.bool.def(false),
    color: propTypes
      .oneOfType([propTypes.arrayOf(propTypes.string), propTypes.string])
      .def(['#309cf6'.'#118EF8'.'#FFF'.'#13f19c']),
    park: propTypes.bool.def(false)});</script>
<style lang="less"></style>
Copy the code

Here, we achieve global style unity with the default values for props, but we can modify these properties in different situations.

Is this it?

Of course not, you’ll notice a problem when your icon name changes:

  • You changed the code manually during the development phase, but the icon did not change after the hot update of Vite (webpack never tried);
  • Business will program to modify the icon name, icon did not change;

Responsive update

Yes, it doesn’t follow the reactive variation of vUE.

There are 2400 + code files containing SVG information. Each file outputs a VNode with an SVG tag. Then there is an IconWrapper method that creates a SPAN tag. Add the SVG VNode inside the span, and return a new VNode.

The exact reason for this is unclear (too bad, but a solution is beginning to form in my mind.

Using the Watch method, listen for prop changes, then create a new VNode to add to the container and re-render. Basically rewrote the IconPark rendering logic.

First, I looked at the source code and found that all the ICONS of VNode were mapped in a map file, so I introduced it:

import * as IconMap from '@icon-park/vue-next/es/map';
Copy the code

CreateVNode is used to render functions to VNode, and render is used to render functions to VNode. The render method converts VNode to a DOM and renders it to a container. Here we use ref to capture a DOM node as a container.

const params = {
      theme: props.theme,
      size: props.size,
      fill: isArray(props.color) ? props.color : [props.color],
      spin: props.spin,
    };
const type = toPascalCase(props.icon);
render(createVNode(IconMap[type], params), elRef.value);
Copy the code

Then put it into the watch method callback and execute it.

<template>
  <span ref="elRef" :class="$attrs.class"></span>
</template>
<script lang="ts" setup>
  import * as IconMap from '@icon-park/vue-next/es/map';
  import { IconThemeEnum } from '/@/enums/appEnum';
  import { computed, ref, watch, render, createVNode, onMounted } from 'vue';
  import { propTypes } from '/@/utils/propTypes';
  import { isArray } from '/@/utils/is';
  import '@icon-park/vue-next/styles/index.css';

  const props = defineProps({
    icon: propTypes.string.isRequired,
    theme: propTypes.oneOf(Object.values(IconThemeEnum)).def(IconThemeEnum.MULLTI),
    size: propTypes.oneOfType([propTypes.string, propTypes.number]).def(16),
    spin: propTypes.bool.def(false),
    color: propTypes
      .oneOfType([propTypes.arrayOf(propTypes.string), propTypes.string])
      .def(['#309cf6'.'#118EF8'.'#FFF'.'#13f19c']),
    park: propTypes.bool.def(false)});const color = computed(() = > (isArray(props.color) ? props.color[0] : props.color));
  const elRef = ref<Element>();
  function toPascalCase(val:string) {
    return val.replace(/(^\w|-\w)/g.function (c) {
      return c.slice(-1).toUpperCase();
    });
  }
  // In a Button of type primary, the default color is white instead of theme
  function setStyle() {
    constparent = elRef.value! .parentElement! .className;const inPrimaryBtn = /-btn-primary/i.test(parent);
    if (inPrimaryBtn) {
      return {
        fill: '#fff'.theme: IconThemeEnum.OUTLINE,
        size: 16.class: 'mr-2px'}; }const inDefaultBtn = /-btn/i.test(parent);
    if (inDefaultBtn) {
      return {
        theme: IconThemeEnum.OUTLINE,
        size: 16.class: 'mr-2px'}; }// Other special default styles can do the same
    return {};
  }
  async function update() {
    const params = {
      theme: props.theme,
      size: props.size,
      fill: isArray(props.color) ? props.color : [props.color],
      spin: props.spin, ... setStyle(), };const type = toPascalCase(props.icon);
    if(! (typein IconMap)) {
      throw new Error(' '.concat(type, ' is not a valid icon type name')); } render(createVNode(IconMap[type], params), elRef.value!) ; } watch(() = > props, update, { flush: 'post' });

  onMounted(update);
</script>
<style lang="less"></style>
Copy the code

Code word is not easy, click a “like” and then go, the recent two articles are collected than the “like” is how to return the matter =_=!