tn-avatar.vue 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. <template>
  2. <view
  3. class="tn-avatar-class tn-avatar"
  4. :class="[backgroundColorClass,avatarClass]"
  5. :style="[avatarStyle]"
  6. @tap="click"
  7. >
  8. <image
  9. v-if="showImg"
  10. class="tn-avatar__img"
  11. :class="[imgClass]"
  12. :src="src"
  13. :mode="imgMode || 'aspectFill'"
  14. @error="loadImageError"
  15. ></image>
  16. <view v-else class="tn-avatar__text" >
  17. <view v-if="text">{{ text }}</view>
  18. <view v-else :class="[`tn-icon-${icon}`]"></view>
  19. </view>
  20. <!-- 角标 -->
  21. <tn-badge
  22. v-if="badge && (badgeIcon || badgeText)"
  23. :radius="badgeSize"
  24. :backgroundColor="badgeBgColor"
  25. :fontColor="badgeColor"
  26. :fontSize="badgeSize - 8"
  27. :absolute="true"
  28. :top="badgePosition[0]"
  29. :right="badgePosition[1]"
  30. >
  31. <view v-if="badgeIcon && badgeText === ''">
  32. <view :class="[`tn-icon-${badgeIcon}`]"></view>
  33. </view>
  34. <view v-else>
  35. {{ badgeText }}
  36. </view>
  37. </tn-badge>
  38. </view>
  39. </template>
  40. <script>
  41. import componentsColorMixin from '../../libs/mixin/components_color.js'
  42. export default {
  43. mixins: [componentsColorMixin],
  44. name: 'tn-avatar',
  45. props: {
  46. // 序号
  47. index: {
  48. type: [Number, String],
  49. default: 0
  50. },
  51. // 头像类型
  52. // square 带圆角正方形 circle 圆形
  53. shape: {
  54. type: String,
  55. default: 'circle'
  56. },
  57. // 大小
  58. // sm 小头像 lg 大头像 xl 加大头像
  59. // 如果为其他则认为是直接设置大小
  60. size: {
  61. type: [Number, String],
  62. default: ''
  63. },
  64. // 是否显示阴影
  65. shadow: {
  66. type: Boolean,
  67. default: false
  68. },
  69. // 是否显示边框
  70. border: {
  71. type: Boolean,
  72. default: false
  73. },
  74. // 边框颜色
  75. borderColor: {
  76. type: String,
  77. default: 'rgba(0, 0, 0, 0.1)'
  78. },
  79. // 边框大小, rpx
  80. borderSize: {
  81. type: Number,
  82. default: 2
  83. },
  84. // 头像路径
  85. src: {
  86. type: String,
  87. default: ''
  88. },
  89. // 文字
  90. text: {
  91. type: String,
  92. default: ''
  93. },
  94. // 图标
  95. icon: {
  96. type: String,
  97. default: ''
  98. },
  99. // 当设置为显示头像信息时,
  100. // 图片的裁剪模式
  101. imgMode: {
  102. type: String,
  103. default: 'aspectFill'
  104. },
  105. // 是否显示角标
  106. badge: {
  107. type: Boolean,
  108. default: false
  109. },
  110. // 设置显示角标后,角标大小
  111. badgeSize: {
  112. type: Number,
  113. default: 0
  114. },
  115. // 角标背景颜色
  116. badgeBgColor: {
  117. type: String,
  118. default: '#AAAAAA'
  119. },
  120. // 角标字体颜色
  121. badgeColor: {
  122. type: String,
  123. default: '#FFFFFF'
  124. },
  125. // 角标图标
  126. badgeIcon: {
  127. type: String,
  128. default: ''
  129. },
  130. // 角标文字,优先级比icon高
  131. badgeText: {
  132. type: String,
  133. default: ''
  134. },
  135. // 角标坐标
  136. // [top, right]
  137. badgePosition: {
  138. type: Array,
  139. default() {
  140. return [0, 0]
  141. }
  142. }
  143. },
  144. data() {
  145. return {
  146. // 图片显示是否发生错误
  147. imgLoadError: false
  148. }
  149. },
  150. computed: {
  151. showImg() {
  152. // 如果设置了图片地址,则为显示图片,否则为显示文本
  153. return this.text === '' && this.icon === ''
  154. },
  155. avatarClass() {
  156. let clazz = ''
  157. clazz += ` tn-avatar--${this.shape}`
  158. if (this._checkSizeIsInline()) {
  159. clazz += ` tn-avatar--${this.size}`
  160. }
  161. if (this.shadow) {
  162. clazz += ' tn-avatar--shadow'
  163. }
  164. return clazz
  165. },
  166. avatarStyle() {
  167. let style = {}
  168. if (this.backgroundColorStyle) {
  169. style.background = this.backgroundColorStyle
  170. } else if (this.shadow && this.showImg) {
  171. style.backgroundImage = `url(${this.src})`
  172. }
  173. if (this.border) {
  174. style.border = `${this.borderSize}rpx solid ${this.borderColor}`
  175. }
  176. if (!this._checkSizeIsInline()) {
  177. style.width = this.size
  178. style.height = this.size
  179. }
  180. return style
  181. },
  182. imgClass() {
  183. let clazz = ''
  184. clazz += ` tn-avatar__img--${this.shape}`
  185. return clazz
  186. }
  187. },
  188. methods: {
  189. // 加载图片失败
  190. loadImageError() {
  191. this.imgLoadError = true
  192. },
  193. // 点击事件
  194. click() {
  195. this.$emit("click", this.index)
  196. },
  197. // 检查是否使用内置的大小进行设置
  198. _checkSizeIsInline() {
  199. if (/^(xs|sm|md|lg|xl|xxl)$/.test(this.size)) return true
  200. else return false
  201. }
  202. }
  203. }
  204. </script>
  205. <style lang="scss" scoped>
  206. .tn-avatar {
  207. /* #ifndef APP-NVUE */
  208. display: inline-flex;
  209. /* #endif */
  210. margin: 0;
  211. padding: 0;
  212. text-align: center;
  213. align-items: center;
  214. justify-content: center;
  215. background-color: $tn-font-holder-color;
  216. // color: #FFFFFF;
  217. white-space: nowrap;
  218. position: relative;
  219. width: 64rpx;
  220. height: 64rpx;
  221. z-index: 1;
  222. &--sm {
  223. width: 48rpx;
  224. height: 48rpx;
  225. }
  226. &--lg {
  227. width: 96rpx;
  228. height: 96rpx;
  229. }
  230. &--xl {
  231. width: 128rpx;
  232. height: 128rpx;
  233. }
  234. &--square {
  235. border-radius: 10rpx;
  236. }
  237. &--circle {
  238. border-radius: 5000rpx;
  239. }
  240. &--shadow {
  241. position: relative;
  242. &::after {
  243. content: " ";
  244. display: block;
  245. background: inherit;
  246. filter: blur(10rpx);
  247. position: absolute;
  248. width: 100%;
  249. height: 100%;
  250. top: 10rpx;
  251. left: 10rpx;
  252. z-index: -1;
  253. opacity: 0.4;
  254. transform-origin: 0 0;
  255. border-radius: inherit;
  256. transform: scale(1, 1);
  257. }
  258. }
  259. &__img {
  260. width: 100%;
  261. height: 100%;
  262. &--square {
  263. border-radius: 10rpx;
  264. }
  265. &--circle {
  266. border-radius: 5000rpx;
  267. }
  268. }
  269. &__text {
  270. display: flex;
  271. flex-direction: row;
  272. align-items: center;
  273. justify-content: center;
  274. }
  275. }
  276. </style>