bug
jiangping
2023-11-07 64b432916af9c9218ab3f3eca614e26c542142ae
minipro_standard/uni_modules/uview-ui/components/u-grid-item/u-grid-item.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,209 @@
<template>
   <!-- #ifndef APP-NVUE -->
   <view
       class="u-grid-item"
       hover-class="u-grid-item--hover-class"
       :hover-stay-time="200"
       @tap="clickHandler"
       :class="classes"
       :style="[itemStyle]"
   >
      <slot />
   </view>
   <!-- #endif -->
   <!-- #ifdef APP-NVUE -->
   <view
       class="u-grid-item"
       :hover-stay-time="200"
       @tap="clickHandler"
       :class="classes"
       :style="[itemStyle]"
   >
      <slot />
   </view>
   <!-- #endif -->
</template>
<script>
   import props from './props.js';
   /**
    * gridItem æç¤º
    * @description å®«æ ¼ç»„件一般用于同时展示多个同类项目的场景,可以给宫格的项目设置徽标组件(badge),或者图标等,也可以扩展为左右滑动的轮播形式。搭配u-grid使用
    * @tutorial https://www.uviewui.com/components/grid.html
    * @property {String | Number}   name      å®«æ ¼çš„name ( é»˜è®¤ null )
    * @property {String}         bgColor      å®«æ ¼çš„背景颜色 ï¼ˆé»˜è®¤ 'transparent' ï¼‰
    * @property {Object}         customStyle   è‡ªå®šä¹‰æ ·å¼ï¼Œå¯¹è±¡å½¢å¼
    * @event {Function} click ç‚¹å‡»å®«æ ¼è§¦å‘
    * @example <u-grid-item></u-grid-item>
    */
   export default {
      name: "u-grid-item",
      mixins: [uni.$u.mpMixin, uni.$u.mixin,props],
      data() {
         return {
            parentData: {
               col: 3, // çˆ¶ç»„件划分的宫格数
               border: true, // æ˜¯å¦æ˜¾ç¤ºè¾¹æ¡†ï¼Œæ ¹æ®çˆ¶ç»„件决定
            },
            // #ifdef APP-NVUE
            width: 0, // nvue下才这么计算,vue下放到computed中,否则会因为延时造成闪烁
            // #endif
            classes: [], // ç±»åé›†åˆï¼Œç”¨äºŽåˆ¤æ–­æ˜¯å¦æ˜¾ç¤ºå³è¾¹å’Œä¸‹è¾¹æ¡†
         };
      },
      mounted() {
         this.init()
      },
      computed: {
         // #ifndef APP-NVUE
         // vue下放到computed中,否则会因为延时造成闪烁
         width() {
            return 100 / Number(this.parentData.col) + '%'
         },
         // #endif
         itemStyle() {
            const style = {
               background: this.bgColor,
               width: this.width
            }
            return uni.$u.deepMerge(style, uni.$u.addStyle(this.customStyle))
         }
      },
      methods: {
         init() {
            // ç”¨äºŽåœ¨çˆ¶ç»„ä»¶u-grid的children中被添加入子组件时,
            // é‡æ–°è®¡ç®—item的边框
            uni.$on('$uGridItem', () => {
               this.gridItemClasses()
            })
            // çˆ¶ç»„件的实例
            this.updateParentData()
            // #ifdef APP-NVUE
            // èŽ·å–å…ƒç´ è¯¥æœ‰çš„é•¿åº¦ï¼Œnvue下要延时才准确
            this.$nextTick(function(){
               this.getItemWidth()
            })
            // #endif
            // å‘出事件,通知所有的grid-item都重新计算自己的边框
            uni.$emit('$uGridItem')
            this.gridItemClasses()
         },
         // èŽ·å–çˆ¶ç»„ä»¶çš„å‚æ•°
         updateParentData() {
            // æ­¤æ–¹æ³•写在mixin中
            this.getParentData('u-grid');
         },
         clickHandler() {
            let name = this.name
            // å¦‚果没有设置name属性,历遍父组件的children数组,判断当前的元素是否和本实例this相等,找出当前组件的索引
            const children = this.parent?.children
            if(children && this.name === null) {
               name = children.findIndex(child => child === this)
            }
            // è°ƒç”¨çˆ¶ç»„件方法,发出事件
            this.parent && this.parent.childClick(name)
            this.$emit('click', name)
         },
         async getItemWidth() {
            // å¦‚果是nvue,不能使用百分比,只能使用固定宽度
            let width = 0
            if(this.parent) {
               // èŽ·å–çˆ¶ç»„ä»¶å®½åº¦åŽï¼Œé™¤ä»¥æ …æ ¼æ•°ï¼Œå¾—å‡ºæ¯ä¸ªitem的宽度
               const parentWidth = await this.getParentWidth()
               width = parentWidth / Number(this.parentData.col) + 'px'
            }
            this.width = width
         },
         // èŽ·å–çˆ¶å…ƒç´ çš„å°ºå¯¸
         getParentWidth() {
            // #ifdef APP-NVUE
            // è¿”回一个promise,让调用者可以用await同步获取
            const dom = uni.requireNativePlugin('dom')
            return new Promise(resolve => {
               // è°ƒç”¨çˆ¶ç»„ä»¶çš„ref
               dom.getComponentRect(this.parent.$refs['u-grid'], res => {
                  resolve(res.size.width)
               })
            })
            // #endif
         },
         gridItemClasses() {
            if(this.parentData.border) {
               const classes = []
               this.parent.children.map((child, index) =>{
                  if(this === child) {
                     const len = this.parent.children.length
                     // è´´è¿‘右边屏幕边沿的child,并且最后一个(比如只有横向2个的时候),无需右边框
                     if((index + 1) % this.parentData.col !== 0 && index + 1 !== len) {
                        classes.push('u-border-right')
                     }
                     // æ€»çš„宫格数量对列数取余的值
                     // å¦‚果取余后,值为0,则意味着要将最后一排的宫格,都不需要下边框
                     const lessNum = len % this.parentData.col === 0 ? this.parentData.col : len % this.parentData.col
                     // æœ€ä¸‹é¢çš„一排child,无需下边框
                     if(index < len - lessNum) {
                        classes.push('u-border-bottom')
                     }
                  }
               })
               // æ”¯ä»˜å®ï¼Œå¤´æ¡å°ç¨‹åºæ— æ³•动态绑定一个数组类名,否则解析出来的结果会带有",",而导致失效
               // #ifdef MP-ALIPAY || MP-TOUTIAO
               classes = classes.join(' ')
               // #endif
               this.classes = classes
            }
         }
      },
      beforeDestroy() {
         // ç§»é™¤äº‹ä»¶ç›‘听,释放性能
         uni.$off('$uGridItem')
      }
   };
</script>
<style lang="scss" scoped>
   @import "../../libs/css/components.scss";
      $u-grid-item-hover-class-opcatiy:.5 !default;
      $u-grid-item-margin-top:1rpx !default;
      $u-grid-item-border-right-width:0.5px !default;
      $u-grid-item-border-bottom-width:0.5px !default;
      $u-grid-item-border-right-color:$u-border-color !default;
      $u-grid-item-border-bottom-color:$u-border-color !default;
   .u-grid-item {
      align-items: center;
      justify-content: center;
      position: relative;
      flex-direction: column;
      /* #ifndef APP-NVUE */
      box-sizing: border-box;
      display: flex;
      /* #endif */
      /* #ifdef MP */
      position: relative;
      float: left;
      /* #endif */
      /* #ifdef MP-WEIXIN */
      margin-top:$u-grid-item-margin-top;
      /* #endif */
      &--hover-class {
         opacity:$u-grid-item-hover-class-opcatiy;
      }
   }
   /* #ifdef APP-NVUE */
   // ç”±äºŽnvue不支持组件内引入app.vue中再引入的样式,所以需要写在这里
   .u-border-right {
      border-right-width:$u-grid-item-border-right-width;
      border-color: $u-grid-item-border-right-color;
   }
   .u-border-bottom {
      border-bottom-width:$u-grid-item-border-bottom-width;
      border-color:$u-grid-item-border-bottom-color;
   }
   /* #endif */
</style>