前言
首先了解一下前端 icon 的发展史。
在前端刚发展起来时,大部分图标都是用 img 来实现的。渐渐发现一个页面的请求资源中图片 img 占了大部分,所以为了优化有了image sprite
就是所谓的雪碧图,就是将多个图片合成一个图片,然后利用 css 的 background-position
定位显示不同的 icon
图标。但这个也有一个很大的痛点,维护困难。每新增一个图标,都需要改动原始图片,还可能不小心出错影响到前面定位好的图片,而且一修改雪碧图,图片缓存就失效了,久而久之你不知道该怎么维护了。
font 库
后来渐渐地一个项目里几乎不会使用任何本地的图片了,而使用一些 font
库来实现页面图标。常见的如 Font Awesome
iconfont
。
iconfont 图标及使用姿势可以参考iconfont使用
创建Icon组件
我们有了icon图标,接下来就是在的项目创建一个icon
组件。
没有封装前,使用icon
大概长这样
<text class="crab crab-gou" style="font-size: 28rpx; color: #333;">
复制代码
我们最后封装组件,大概长这样
<ca-icon name="crab-gou" />
复制代码
实现的大概的思路
- 引入
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" />
复制代码
如图所示