bklLiudl
2025-04-07 4e8f58cb41c7b6d570fd1979d80f74ab8a4d00c2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
<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>
    import Icon from '../icon';
    import { oneOf } from '../../utils/assist';
 
    const prefixCls = 'ivu-avatar';
 
    const sizeList = ['small', 'large', 'default'];
 
    export default {
        name: 'Avatar',
        components: { Icon },
        props: {
            shape: {
                validator (value) {
                    return oneOf(value, ['circle', 'square']);
                },
                default: 'circle'
            },
            size: {
                type: [String, Number],
                default () {
                    return !this.$IVIEW || this.$IVIEW.size === '' ? 'default' : this.$IVIEW.size;
                }
            },
            src: {
                type: String
            },
            icon: {
                type: String
            },
            customIcon: {
                type: String,
                default: ''
            },
        },
        data () {
            return {
                prefixCls: prefixCls,
                scale: 1,
                childrenWidth: 0,
                isSlotShow: false,
                slotTemp: null
            };
        },
        computed: {
            classes () {
                return [
                    `${prefixCls}`,
                    `${prefixCls}-${this.shape}`,
                    {
                        [`${prefixCls}-image`]: !!this.src,
                        [`${prefixCls}-icon`]: !!this.icon || !!this.customIcon,
                        [`${prefixCls}-${this.size}`]: oneOf(this.size, sizeList)
                    }
                ];
            },
            styles () {
                let style = {};
                if (this.size && !oneOf(this.size, sizeList)) {
                    style.width = `${this.size}px`;
                    style.height = `${this.size}px`;
                    style.lineHeight = `${this.size}px`;
                    style.fontSize = `${this.size/2}px`;
                }
                return style;
            },
            childrenStyle () {
                let style = {};
                if (this.isSlotShow) {
                    style = {
                        msTransform: `scale(${this.scale})`,
                        WebkitTransform: `scale(${this.scale})`,
                        transform: `scale(${this.scale})`,
                        position: 'absolute',
                        display: 'inline-block',
                        left: `calc(50% - ${Math.round(this.childrenWidth / 2)}px)`
                    };
                }
                return style;
            }
        },
        watch: {
            size (val, oldVal) {
                if (val !== oldVal) this.setScale();
            }
        },
        methods: {
            setScale () {
                this.isSlotShow = !this.src && !this.icon;
                if (this.$refs.children) {
                    // set children width again to make slot centered
                    this.childrenWidth = this.$refs.children.offsetWidth;
                    const avatarWidth = this.$el.getBoundingClientRect().width;
                    // add 4px gap for each side to get better performance
                    if (avatarWidth - 8 < this.childrenWidth) {
                        this.scale = (avatarWidth - 8) / this.childrenWidth;
                    } else {
                        this.scale = 1;
                    }
                }
            },
            handleError (e) {
                this.$emit('on-error', e);
            }
        },
        beforeCreate () {
            this.slotTemp = this.$slots.default;
        },
        mounted () {
            this.setScale();
        },
        updated () {
            if (this.$slots.default !== this.slotTemp) {
                this.slotTemp = this.$slots.default;
                this.setScale();
            }
        }
    };
</script>