You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

336 lines
9.8 KiB

3 years ago
  1. <template>
  2. <view :style="[customStyle]" class="u-icon" @tap="click" :class="['u-icon--' + labelPos]">
  3. <image class="u-icon__img" v-if="isImg" :src="name" :mode="imgMode" :style="[imgStyle]"></image>
  4. <text v-else class="u-icon__icon" :class="customClass" :style="[iconStyle]" :hover-class="hoverClass"
  5. @touchstart="touchstart">
  6. <text v-if="showDecimalIcon" :style="[decimalIconStyle]" :class="decimalIconClass" :hover-class="hoverClass"
  7. class="u-icon__decimal">
  8. </text>
  9. </text>
  10. <!-- 这里进行空字符串判断如果仅仅是v-if="label"可能会出现传递0的时候结果也无法显示 -->
  11. <text v-if="label !== ''" class="u-icon__label" :style="{
  12. color: labelColor,
  13. fontSize: $u.addUnit(labelSize),
  14. marginLeft: labelPos == 'right' ? $u.addUnit(marginLeft) : 0,
  15. marginTop: labelPos == 'bottom' ? $u.addUnit(marginTop) : 0,
  16. marginRight: labelPos == 'left' ? $u.addUnit(marginRight) : 0,
  17. marginBottom: labelPos == 'top' ? $u.addUnit(marginBottom) : 0,
  18. }">{{ label }}
  19. </text>
  20. </view>
  21. </template>
  22. <script>
  23. /**
  24. * icon 图标
  25. * @description 基于字体的图标集包含了大多数常见场景的图标
  26. * @tutorial https://www.uviewui.com/components/icon.html
  27. * @property {String} name 图标名称见示例图标集
  28. * @property {String} color 图标颜色默认inherit
  29. * @property {String | Number} size 图标字体大小单位rpx默认32
  30. * @property {String | Number} label-size label字体大小单位rpx默认28
  31. * @property {String} label 图标右侧的label文字默认28
  32. * @property {String} label-pos label文字相对于图标的位置只能right或bottom默认right
  33. * @property {String} label-color label字体颜色默认#606266
  34. * @property {Object} custom-style icon的样式对象形式
  35. * @property {String} custom-prefix 自定义字体图标库时需要写上此值
  36. * @property {String | Number} margin-left label在右侧时与图标的距离单位rpx默认6
  37. * @property {String | Number} margin-top label在下方时与图标的距离单位rpx默认6
  38. * @property {String | Number} margin-bottom label在上方时与图标的距离单位rpx默认6
  39. * @property {String | Number} margin-right label在左侧时与图标的距离单位rpx默认6
  40. * @property {String} label-pos label相对于图标的位置只能right或bottom默认right
  41. * @property {String} index 一个用于区分多个图标的值点击图标时通过click事件传出
  42. * @property {String} hover-class 图标按下去的样式类用法同uni的view组件的hover-class参数详情见官网
  43. * @property {String} width 显示图片小图标时的宽度
  44. * @property {String} height 显示图片小图标时的高度
  45. * @property {String} top 图标在垂直方向上的定位
  46. * @property {String} top 图标在垂直方向上的定位
  47. * @property {String} top 图标在垂直方向上的定位
  48. * @property {Boolean} show-decimal-icon 是否为DecimalIcon
  49. * @property {String} inactive-color 背景颜色可接受主题色仅Decimal时有效
  50. * @property {String | Number} percent 显示的百分比仅Decimal时有效
  51. * @event {Function} click 点击图标时触发
  52. * @example <u-icon name="photo" color="#2979ff" size="28"></u-icon>
  53. */
  54. export default {
  55. name: 'u-icon',
  56. props: {
  57. // 图标类名
  58. name: {
  59. type: String,
  60. default: ''
  61. },
  62. // 图标颜色,可接受主题色
  63. color: {
  64. type: String,
  65. default: ''
  66. },
  67. // 字体大小,单位rpx
  68. size: {
  69. type: [Number, String],
  70. default: 'inherit'
  71. },
  72. // 是否显示粗体
  73. bold: {
  74. type: Boolean,
  75. default: false
  76. },
  77. // 点击图标的时候传递事件出去的index(用于区分点击了哪一个)
  78. index: {
  79. type: [Number, String],
  80. default: ''
  81. },
  82. // 触摸图标时的类名
  83. hoverClass: {
  84. type: String,
  85. default: ''
  86. },
  87. // 自定义扩展前缀,方便用户扩展自己的图标库
  88. customPrefix: {
  89. type: String,
  90. default: 'uicon'
  91. },
  92. // 图标右边或者下面的文字
  93. label: {
  94. type: [String, Number],
  95. default: ''
  96. },
  97. // label的位置,只能右边或者下边
  98. labelPos: {
  99. type: String,
  100. default: 'right'
  101. },
  102. // label的大小
  103. labelSize: {
  104. type: [String, Number],
  105. default: '28'
  106. },
  107. // label的颜色
  108. labelColor: {
  109. type: String,
  110. default: '#606266'
  111. },
  112. // label与图标的距离(横向排列)
  113. marginLeft: {
  114. type: [String, Number],
  115. default: '6'
  116. },
  117. // label与图标的距离(竖向排列)
  118. marginTop: {
  119. type: [String, Number],
  120. default: '6'
  121. },
  122. // label与图标的距离(竖向排列)
  123. marginRight: {
  124. type: [String, Number],
  125. default: '6'
  126. },
  127. // label与图标的距离(竖向排列)
  128. marginBottom: {
  129. type: [String, Number],
  130. default: '6'
  131. },
  132. // 图片的mode
  133. imgMode: {
  134. type: String,
  135. default: 'widthFix'
  136. },
  137. // 自定义样式
  138. customStyle: {
  139. type: Object,
  140. default() {
  141. return {}
  142. }
  143. },
  144. // 用于显示图片小图标时,图片的宽度
  145. width: {
  146. type: [String, Number],
  147. default: ''
  148. },
  149. // 用于显示图片小图标时,图片的高度
  150. height: {
  151. type: [String, Number],
  152. default: ''
  153. },
  154. // 用于解决某些情况下,让图标垂直居中的用途
  155. top: {
  156. type: [String, Number],
  157. default: 0
  158. },
  159. // 是否为DecimalIcon
  160. showDecimalIcon: {
  161. type: Boolean,
  162. default: false
  163. },
  164. // 背景颜色,可接受主题色,仅Decimal时有效
  165. inactiveColor: {
  166. type: String,
  167. default: '#ececec'
  168. },
  169. // 显示的百分比,仅Decimal时有效
  170. percent: {
  171. type: [Number, String],
  172. default: '50'
  173. }
  174. },
  175. computed: {
  176. customClass() {
  177. let classes = []
  178. classes.push(this.customPrefix + '-' + this.name)
  179. // uView的自定义图标类名为u-iconfont
  180. if (this.customPrefix == 'uicon') {
  181. classes.push('u-iconfont')
  182. } else {
  183. classes.push(this.customPrefix)
  184. }
  185. // 主题色,通过类配置
  186. if (this.showDecimalIcon && this.inactiveColor && this.$u.config.type.includes(this.inactiveColor)) {
  187. classes.push('u-icon__icon--' + this.inactiveColor)
  188. } else if (this.color && this.$u.config.type.includes(this.color)) classes.push('u-icon__icon--' + this.color)
  189. // 阿里,头条,百度小程序通过数组绑定类名时,无法直接使用[a, b, c]的形式,否则无法识别
  190. // 故需将其拆成一个字符串的形式,通过空格隔开各个类名
  191. //#ifdef MP-ALIPAY || MP-TOUTIAO || MP-BAIDU
  192. classes = classes.join(' ')
  193. //#endif
  194. return classes
  195. },
  196. iconStyle() {
  197. let style = {}
  198. style = {
  199. fontSize: this.size == 'inherit' ? 'inherit' : this.$u.addUnit(this.size),
  200. fontWeight: this.bold ? 'bold' : 'normal',
  201. // 某些特殊情况需要设置一个到顶部的距离,才能更好的垂直居中
  202. top: this.$u.addUnit(this.top)
  203. }
  204. // 非主题色值时,才当作颜色值
  205. if (this.showDecimalIcon && this.inactiveColor && !this.$u.config.type.includes(this.inactiveColor)) {
  206. style.color = this.inactiveColor
  207. } else if (this.color && !this.$u.config.type.includes(this.color)) style.color = this.color
  208. return style
  209. },
  210. // 判断传入的name属性,是否图片路径,只要带有"/"均认为是图片形式
  211. isImg() {
  212. return this.name.indexOf('/') !== -1
  213. },
  214. imgStyle() {
  215. let style = {}
  216. // 如果设置width和height属性,则优先使用,否则使用size属性
  217. style.width = this.width ? this.$u.addUnit(this.width) : this.$u.addUnit(this.size)
  218. style.height = this.height ? this.$u.addUnit(this.height) : this.$u.addUnit(this.size)
  219. return style
  220. },
  221. decimalIconStyle() {
  222. let style = {}
  223. style = {
  224. fontSize: this.size == 'inherit' ? 'inherit' : this.$u.addUnit(this.size),
  225. fontWeight: this.bold ? 'bold' : 'normal',
  226. // 某些特殊情况需要设置一个到顶部的距离,才能更好的垂直居中
  227. top: this.$u.addUnit(this.top),
  228. width: this.percent + '%'
  229. }
  230. // 非主题色值时,才当作颜色值
  231. if (this.color && !this.$u.config.type.includes(this.color)) style.color = this.color
  232. return style
  233. },
  234. decimalIconClass() {
  235. let classes = []
  236. classes.push(this.customPrefix + '-' + this.name)
  237. // uView的自定义图标类名为u-iconfont
  238. if (this.customPrefix == 'uicon') {
  239. classes.push('u-iconfont')
  240. } else {
  241. classes.push(this.customPrefix)
  242. }
  243. // 主题色,通过类配置
  244. if (this.color && this.$u.config.type.includes(this.color)) classes.push('u-icon__icon--' + this.color)
  245. else classes.push('u-icon__icon--primary')
  246. // 阿里,头条,百度小程序通过数组绑定类名时,无法直接使用[a, b, c]的形式,否则无法识别
  247. // 故需将其拆成一个字符串的形式,通过空格隔开各个类名
  248. //#ifdef MP-ALIPAY || MP-TOUTIAO || MP-BAIDU
  249. classes = classes.join(' ')
  250. //#endif
  251. return classes
  252. }
  253. },
  254. methods: {
  255. click() {
  256. this.$emit('click', this.index)
  257. },
  258. touchstart() {
  259. this.$emit('touchstart', this.index)
  260. }
  261. }
  262. }
  263. </script>
  264. <style scoped lang="scss">
  265. @import "../../libs/css/style.components.scss";
  266. @import '../../iconfont.css';
  267. .u-icon {
  268. display: inline-flex;
  269. align-items: center;
  270. &--left {
  271. flex-direction: row-reverse;
  272. align-items: center;
  273. }
  274. &--right {
  275. flex-direction: row;
  276. align-items: center;
  277. }
  278. &--top {
  279. flex-direction: column-reverse;
  280. justify-content: center;
  281. }
  282. &--bottom {
  283. flex-direction: column;
  284. justify-content: center;
  285. }
  286. &__icon {
  287. position: relative;
  288. &--primary {
  289. color: $u-type-primary;
  290. }
  291. &--success {
  292. color: $u-type-success;
  293. }
  294. &--error {
  295. color: $u-type-error;
  296. }
  297. &--warning {
  298. color: $u-type-warning;
  299. }
  300. &--info {
  301. color: $u-type-info;
  302. }
  303. }
  304. &__decimal {
  305. position: absolute;
  306. top: 0;
  307. left: 0;
  308. display: inline-block;
  309. overflow: hidden;
  310. }
  311. &__img {
  312. height: auto;
  313. will-change: transform;
  314. }
  315. &__label {
  316. line-height: 1;
  317. }
  318. }
  319. </style>