Vue3 造轮子系列:封装Icon 组件

1,780 阅读1分钟

前言

项目开发环境uni-app,H5可以更换<text><i>即可。

iconfont 图标及入门姿势可以参考这篇文章iconfont+

创建Icon组件

我们有自己iconfont图标后,接下来就可以在的项目创建一个icon组件使用这些iconfont图标了。

没有封装前,使用icon大概长这样

<text class="crab crab-gou" style="font-size: 28rpx; color: #333;">

显然太过于麻烦,封装组件后,大概长这样,遇到需要动态修改的地方更加方便。

<ca-icon name="crab-gou" size="28" color:"#333" />

大概的思路

  • 引入iconfont图标样式
  • 在传入大小名称和样式
<template>
  <text
    @tap.stop="handleClick"
    class="ca-icon"
    :class="[classPrefix_, name]"
    :style="[iconStyle_]"
  ></text>
</template>
<script>
import { defineComponent, toRefs, computed } from 'vue'

export default defineComponent({
  props: {
    name: {
      type: String,
      default: '',
    },
    size: {
      type: [String, Number],
      default: '28',
    },
    color: {
      type: [String, Boolean],
      default: 'inherit',
    },
    size: {
      type: [Number, String],
      default: 28,
    },
  },
  setup(props, { emit }) {
    const handleClick = (e) => {
      emit('click', e)
    }
    const iconStyle_ = computed(() => {
      // 组件样式
      const obj = {
        fontSize: String(props.size).indexOf('px') !== -1 ? props.size : uni.upx2px(props.size) + 'px',
      }
      // icon名称
    const classPrefix_ = computed(() => {
      const prevName = props.name.split('-')[0]
      const name = prevName === 'icon' ? 'iconfont' : prevName
      return name
    })
      String(props.color) !== 'false' && (obj['color'] = props.color)
      return obj
    })

    return {
      iconStyle_,
      classPrefix_,
      handleClick,
      ...toRefs(props),
    }
  },
})
</script>
<style lang="scss" scoped>
@import './font.css';
.ca-icon {
  font-size: 0;
  @include tst(transform);
  vertical-align: middle;
  position: relative;
  display: inline-block;
  font-size: inherit;
  // 浏览器渲染引擎如何渲染字体。浏览器会在速度、清晰度、几何精度之间进行权衡。
  text-rendering: auto;
  -webkit-font-smoothing: antialiased;
}
</style>

嗯 一个简单的icon 组件封装好了。

Vant中功能都有了,除了小点点,不想写,就是玩,觉得用处不大。

进一步改造

阿就这,就这样完了嘛?

在实际的项目开发中,一起开发的同事有提了新的需求。

  • 要是图标可以旋转,一直转圈,转圈速度自己调节。
  • 要是图标可以旋转一定的角度。

就更好了,行吧,安排

于是乎在原来的基础上添加几行代码,如下

<template>
  <text
    @tap.stop="handleClick"
    class="ca-icon"
    :class="[classPrefix_, name]"
    :style="[iconStyle_]"
  ></text>
</template>
<script >
import { defineComponent, toRefs, computed } from 'vue'

export default defineComponent({
  props: {
    name: {
      type: String,
      default: '',
    },
    size: {
      type: [String, Number],
      default: '28',
    },
    color: {
      type: [String, Boolean],
      default: 'inherit',
    },
    size: {
      type: [Number, String],
      default: 28,
    },
    spin: {
      type: Boolean,
      default: false,
    },
    spinGap: {
      type: [Number, String],
      default: 1.5,
    },
    rotate: {
      type: [Number, String, Boolean],
      default: false,
    },
  },
  setup(props, { emit }) {
    const handleClick = (e) => {
      emit('click', e)
    }
    const rotate_ = computed(() => {
      return String(props.rotate) === 'false' ? false : props.rotate
    })
    // class-prefix
    const classPrefix_ = computed(() => {
      const prevName = props.name.split('-')[0]
      const name = prevName === 'icon' ? 'iconfont' : prevName
      return name
    })

    const iconStyle_ = computed(() => {
      // 组件样式
      const obj = {
        fontSize:
          String(props.size).indexOf('px') !== -1
            ? props.size
            : uni.upx2px(props.size) + 'px',
      }
      String(props.color) !== 'false' && (obj['color'] = props.color)
      // 组件动画
      rotate_.value &&
        (obj.transform = isNaN(props.rotate)
          ? `rotate(${props.rotate})`
          : `rotate(${props.rotate}deg)`)
      if (props.spin) {
        obj.animation = `ca-spin ${props.spinGap}s linear infinite`
      }
      return obj
    })

    return {
      iconStyle_,
      classPrefix_,
      handleClick,
      ...toRefs(props),
    }
  },
})
</script>
<style lang="scss" scoped>
@import './font.css';

.ca-icon {
  font-size: 0;
  @include tst(transform);
  vertical-align: middle;
  position: relative;
  display: inline-block;
  font-size: inherit;
  // 浏览器渲染引擎如何渲染字体。浏览器会在速度、清晰度、几何精度之间进行权衡。
  text-rendering: auto;
  -webkit-font-smoothing: antialiased;
}
</style>

scss 动画

// 旋转动画
@keyframes ca-spin {
    from {
        transform: rotate(0deg);
    }
    to {
        transform: rotate(360deg);
    }
}

效果

    // 在代码中使用
    <view class="p-30"> icon </view>
    <ca-icon name="crab-gou" />
    <ca-icon name="crab-modal" color="#888" />
    <ca-icon name="crab-shijian1" size="60" />
    <ca-icon name="crab-aixin1" rotate="45" />
    <ca-icon name="crab-shoucang1" spin />
    <ca-icon name="crab-shoucang1" spin spinGap="5" />

如图所示

Untitled

参考