美文网首页
easymesh-ui avatar

easymesh-ui avatar

作者: EasyNetCN | 来源:发表于2021-12-28 11:13 被阅读0次

easymesh-ui(https://github.com/easynet-cn/easymesh-ui)是基于vite,vue3,typescript,view design样式的组件库,目标是构建一套k8s,istio的管理平台,目前正在开发中。

Avatar是其中的头像组件,针对vue3初学者有一些借鉴的意义。比如生命周期函数,组合方法,slot的使用等等。

<template>
  <span :class="classes" :style="styles">
    <img :src="src" v-if="src" @error="handleError" />
    <Icon :type="icon" :custom="customIcon" v-else-if="icon || customIcon"></Icon>
    <span ref="children" :class="[prefixCls + '-string']" :style="childrenStyle" v-else>
      <slot></slot>
    </span>
  </span>
</template>
<script lang="ts">
import { computed, defineComponent, getCurrentInstance, onBeforeMount, onMounted, onUpdated, PropType, ref, toRefs, watch } from 'vue'
import Icon from '../icon/'

const prefixClass = 'ivu-avatar'

const sizeList = ['small', 'large', 'default']

export default defineComponent({
  name: 'Avatar',
  components: { Icon },
  props: {
    shape: {
      type: String as PropType<'circle' | 'square'>,
      default: 'circle'
    },
    size: {
      type: [String, Number],
      default: 'default'
    },
    src: {
      type: String
    },
    icon: {
      type: String
    },
    customIcon: {
      type: String,
      default: ''
    }
  },
  setup(props, ctx) {
    const { shape, size, src, icon, customIcon } = toRefs(props)

    const prefixCls = ref(prefixClass)
    const scale = ref(1)
    const childrenWidth = ref(0)
    const isSlotShow = ref(false)
    const slotTemp = ref()

    const children = ref(null)

    const classes = computed(() => {
      return [
        `${prefixCls.value}`,
        `${prefixCls.value}-${shape.value}`,
        {
          [`${prefixCls.value}-image`]: !!src?.value,
          [`${prefixCls.value}-icon`]: !!icon?.value || !!customIcon.value,
          [`${prefixCls.value}-${size.value}`]: size.value
        }
      ]
    })
    const styles = computed(() => {
      return typeof size.value === 'number' ? {
        width: `${size.value}px`,
        height: `${size.value}px`,
        lineHeight: `${size.value}px`,
        fontSize: `${size.value / 2}px`
      } : {}
    })
    const childrenStyle = computed(() => {
      let style = {}

      if (isSlotShow.value) {
        style = {
          msTransform: `scale(${scale.value})`,
          WebkitTransform: `scale(${scale.value})`,
          transform: `scale(${scale.value})`,
          position: 'absolute',
          display: 'inline-block',
          left: `calc(50% - ${Math.round(childrenWidth.value / 2)}px)`
        }
      }
      return style
    })

    const setScale = () => {
      isSlotShow.value = !src?.value && !icon?.value

      if (children.value) {
        const ins = getCurrentInstance()

        // set children width again to make slot centered
        childrenWidth.value = (children.value! as HTMLElement).offsetWidth
        const avatarWidth = (ins.ctx.$el! as HTMLElement).getBoundingClientRect().width
        // add 4px gap for each side to get better performance
        if (avatarWidth - 8 < childrenWidth.value) {
          scale.value = (avatarWidth - 8) / childrenWidth.value
        } else {
          scale.value = 1
        }
      }
    }
    const handleError = (e: any) => {
      ctx.emit('on-error', e)
    }

    watch(size, (val, oldVal) => {
      if (val !== oldVal) setScale()
    })

    onBeforeMount(() => {
      slotTemp.value = ctx.slots.default ? ctx.slots.default() : null
    })

    onMounted(() => {
      setScale()
    })

    onUpdated(() => {
      if (ctx.slots.default && ctx.slots.default() !== slotTemp.value) {
        slotTemp.value = ctx.slots.default()

        setScale()
      }
    })

    return {
      prefixCls,
      scale,
      childrenWidth,
      isSlotShow,
      slotTemp,
      children,
      classes,
      styles,
      childrenStyle,
      setScale,
      handleError
    }
  }
})
</script>

相关文章

网友评论

      本文标题:easymesh-ui avatar

      本文链接:https://www.haomeiwen.com/subject/pmksqrtx.html