bug
jiangping
2023-11-07 64b432916af9c9218ab3f3eca614e26c542142ae
minipro_standard/uni_modules/uview-ui/components/u-image/u-image.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,232 @@
<template>
   <u-transition
      mode="fade"
      :show="show"
      :duration="fade ? 1000 : 0"
   >
      <view
         class="u-image"
         @tap="onClick"
         :style="[wrapStyle, backgroundStyle]"
      >
         <image
            v-if="!isError"
            :src="src"
            :mode="mode"
            @error="onErrorHandler"
            @load="onLoadHandler"
            :show-menu-by-longpress="showMenuByLongpress"
            :lazy-load="lazyLoad"
            class="u-image__image"
            :style="{
               borderRadius: shape == 'circle' ? '10000px' : $u.addUnit(radius),
               width: $u.addUnit(width),
               height: $u.addUnit(height)
            }"
         ></image>
         <view
            v-if="showLoading && loading"
            class="u-image__loading"
            :style="{
               borderRadius: shape == 'circle' ? '50%' : $u.addUnit(radius),
               backgroundColor: this.bgColor,
               width: $u.addUnit(width),
               height: $u.addUnit(height)
            }"
         >
            <slot name="loading">
               <u-icon
                  :name="loadingIcon"
                  :width="width"
                  :height="height"
               ></u-icon>
            </slot>
         </view>
         <view
            v-if="showError && isError && !loading"
            class="u-image__error"
            :style="{
               borderRadius: shape == 'circle' ? '50%' : $u.addUnit(radius),
               width: $u.addUnit(width),
               height: $u.addUnit(height)
            }"
         >
            <slot name="error">
               <u-icon
                  :name="errorIcon"
                  :width="width"
                  :height="height"
               ></u-icon>
            </slot>
         </view>
      </view>
   </u-transition>
</template>
<script>
   import props from './props.js';
   /**
    * Image å›¾ç‰‡
    * @description æ­¤ç»„件为uni-app的image组件的加强版,在继承了原有功能外,还支持淡入动画、加载中、加载失败提示、圆角值和形状等。
    * @tutorial https://uviewui.com/components/image.html
    * @property {String}         src             å›¾ç‰‡åœ°å€
    * @property {String}         mode             è£å‰ªæ¨¡å¼ï¼Œè§å®˜ç½‘说明 ï¼ˆé»˜è®¤ 'aspectFill' ï¼‰
    * @property {String | Number}   width             å®½åº¦ï¼Œå•位任意,如果为数值,则为px单位 ï¼ˆé»˜è®¤ '300' ï¼‰
    * @property {String | Number}   height             é«˜åº¦ï¼Œå•位任意,如果为数值,则为px单位 ï¼ˆé»˜è®¤ '225' ï¼‰
    * @property {String}         shape             å›¾ç‰‡å½¢çŠ¶ï¼Œcircle-圆形,square-方形 ï¼ˆé»˜è®¤ 'square' ï¼‰
    * @property {String | Number}   radius             åœ†è§’值,单位任意,如果为数值,则为px单位 ï¼ˆé»˜è®¤ 0 ï¼‰
    * @property {Boolean}         lazyLoad         æ˜¯å¦æ‡’加载,仅微信小程序、App、百度小程序、字节跳动小程序有效 ï¼ˆé»˜è®¤ true ï¼‰
    * @property {Boolean}         showMenuByLongpress   æ˜¯å¦å¼€å¯é•¿æŒ‰å›¾ç‰‡æ˜¾ç¤ºè¯†åˆ«å°ç¨‹åºç èœå•,仅微信小程序有效 ï¼ˆé»˜è®¤ true ï¼‰
    * @property {String}         loadingIcon       åŠ è½½ä¸­çš„å›¾æ ‡ï¼Œæˆ–è€…å°å›¾ç‰‡ ï¼ˆé»˜è®¤ 'photo' ï¼‰
    * @property {String}         errorIcon          åŠ è½½å¤±è´¥çš„å›¾æ ‡ï¼Œæˆ–è€…å°å›¾ç‰‡ ï¼ˆé»˜è®¤ 'error-circle' ï¼‰
    * @property {Boolean}         showLoading       æ˜¯å¦æ˜¾ç¤ºåŠ è½½ä¸­çš„å›¾æ ‡æˆ–è€…è‡ªå®šä¹‰çš„slot ï¼ˆé»˜è®¤ true ï¼‰
    * @property {Boolean}         showError          æ˜¯å¦æ˜¾ç¤ºåŠ è½½é”™è¯¯çš„å›¾æ ‡æˆ–è€…è‡ªå®šä¹‰çš„slot ï¼ˆé»˜è®¤ true ï¼‰
    * @property {Boolean}         fade             æ˜¯å¦éœ€è¦æ·¡å…¥æ•ˆæžœ ï¼ˆé»˜è®¤ true ï¼‰
    * @property {Boolean}         webp             åªæ”¯æŒç½‘络资源,只对微信小程序有效 ï¼ˆé»˜è®¤ false ï¼‰
    * @property {String | Number}   duration          æ­é…fade参数的过渡时间,单位ms ï¼ˆé»˜è®¤ 500 ï¼‰
    * @property {String}         bgColor          èƒŒæ™¯é¢œè‰²ï¼Œç”¨äºŽæ·±è‰²é¡µé¢åŠ è½½å›¾ç‰‡æ—¶ï¼Œä¸ºäº†å’ŒèƒŒæ™¯è‰²èžåˆ  (默认 '#f3f4f6' )
    * @property {Object}         customStyle        å®šä¹‰éœ€è¦ç”¨åˆ°çš„外部样式
    * @event {Function}   click   ç‚¹å‡»å›¾ç‰‡æ—¶è§¦å‘
    * @event {Function}   error   å›¾ç‰‡åŠ è½½å¤±è´¥æ—¶è§¦å‘
    * @event {Function} load å›¾ç‰‡åŠ è½½æˆåŠŸæ—¶è§¦å‘
    * @example <u-image width="100%" height="300px" :src="src"></u-image>
    */
   export default {
      name: 'u-image',
      mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
      data() {
         return {
            // å›¾ç‰‡æ˜¯å¦åŠ è½½é”™è¯¯ï¼Œå¦‚æžœæ˜¯ï¼Œåˆ™æ˜¾ç¤ºé”™è¯¯å ä½å›¾
            isError: false,
            // åˆå§‹åŒ–组件时,默认为加载中状态
            loading: true,
            // ä¸é€æ˜Žåº¦ï¼Œä¸ºäº†å®žçŽ°æ·¡å…¥æ·¡å‡ºçš„æ•ˆæžœ
            opacity: 1,
            // è¿‡æ¸¡æ—¶é—´ï¼Œå› ä¸ºprops的值无法修改,故需要一个中间值
            durationTime: this.duration,
            // å›¾ç‰‡åŠ è½½å®Œæˆæ—¶ï¼ŒåŽ»æŽ‰èƒŒæ™¯é¢œè‰²ï¼Œå› ä¸ºå¦‚æžœæ˜¯png图片,就会显示灰色的背景
            backgroundStyle: {},
            // ç”¨äºŽfade模式的控制组件显示与否
            show: false
         };
      },
      watch: {
         src: {
            immediate: true,
            handler(n) {
               if (!n) {
                  // å¦‚果传入null或者'',或者false,或者undefined,标记为错误状态
                  this.isError = true
               } else {
                  this.isError = false;
                  this.loading = true;
               }
            }
         }
      },
      computed: {
         wrapStyle() {
            let style = {};
            // é€šè¿‡è°ƒç”¨addUnit()方法,如果有单位,如百分比,px单位等,直接返回,如果是纯粹的数值,则加上rpx单位
            style.width = this.$u.addUnit(this.width);
            style.height = this.$u.addUnit(this.height);
            // å¦‚果是显示圆形,设置一个很多的半径值即可
            style.borderRadius = this.shape == 'circle' ? '10000px' : uni.$u.addUnit(this.radius)
            // å¦‚果设置圆角,必须要有hidden,否则可能圆角无效
            style.overflow = this.borderRadius > 0 ? 'hidden' : 'visible'
            // if (this.fade) {
            //    style.opacity = this.opacity
            //    // nvue下,这几个属性必须要分开写
            //    style.transitionDuration = `${this.durationTime}ms`
            //    style.transitionTimingFunction = 'ease-in-out'
            //    style.transitionProperty = 'opacity'
            // }
            return uni.$u.deepMerge(style, uni.$u.addStyle(this.customStyle));
         }
      },
      mounted() {
         this.show = true
      },
      methods: {
         // ç‚¹å‡»å›¾ç‰‡
         onClick() {
            this.$emit('click')
         },
         // å›¾ç‰‡åŠ è½½å¤±è´¥
         onErrorHandler(err) {
            this.loading = false
            this.isError = true
            this.$emit('error', err)
         },
         // å›¾ç‰‡åŠ è½½å®Œæˆï¼Œæ ‡è®°loading结束
         onLoadHandler(event) {
            this.loading = false
            this.isError = false
            this.$emit('load', event)
            this.removeBgColor()
            // å¦‚果不需要动画效果,就不执行下方代码,同时移除加载时的背景颜色
            // å¦åˆ™æ— éœ€fade效果时,png图片依然能看到下方的背景色
            // if (!this.fade) return this.removeBgColor();
            // // åŽŸæ¥opacity为1(不透明,是为了显示占位图),改成0(透明,意味着该元素显示的是背景颜色,默认的灰色),再改成1,是为了获得过渡效果
            // this.opacity = 0;
            // // è¿™é‡Œè®¾ç½®ä¸º0,是为了图片展示到背景全透明这个过程时间为0,延时之后延时之后重新设置为duration,是为了获得背景透明(灰色)
            // // åˆ°å›¾ç‰‡å±•示的过程中的淡入效果
            // this.durationTime = 0;
            // // å»¶æ—¶50ms,否则在浏览器H5,过渡效果无效
            // setTimeout(() => {
            //    this.durationTime = this.duration;
            //    this.opacity = 1;
            //    setTimeout(() => {
            //       this.removeBgColor();
            //    }, this.durationTime);
            // }, 50);
         },
         // ç§»é™¤å›¾ç‰‡çš„背景色
         removeBgColor() {
            // æ·¡å…¥åŠ¨ç”»è¿‡æ¸¡å®ŒæˆåŽï¼Œå°†èƒŒæ™¯è®¾ç½®ä¸ºé€æ˜Žè‰²ï¼Œå¦åˆ™png图片会看到灰色的背景
            this.backgroundStyle = {
               backgroundColor: 'transparent'
            };
         }
      }
   };
</script>
<style lang="scss" scoped>
   @import '../../libs/css/components.scss';
   $u-image-error-top:0px !default;
   $u-image-error-left:0px !default;
   $u-image-error-width:100% !default;
   $u-image-error-hight:100% !default;
   $u-image-error-background-color:$u-bg-color !default;
   $u-image-error-color:$u-tips-color !default;
   $u-image-error-font-size: 46rpx !default;
   .u-image {
      position: relative;
      transition: opacity 0.5s ease-in-out;
      &__image {
         width: 100%;
         height: 100%;
      }
      &__loading,
      &__error {
         position: absolute;
         top: $u-image-error-top;
         left: $u-image-error-left;
         width: $u-image-error-width;
         height: $u-image-error-hight;
         @include flex;
         align-items: center;
         justify-content: center;
         background-color: $u-image-error-background-color;
         color: $u-image-error-color;
         font-size: $u-image-error-font-size;
      }
   }
</style>