<template> 
 | 
  <view 
 | 
    v-if="show" 
 | 
    class="tn-row-notice-class tn-row-notice" 
 | 
    :class="[backgroundColorClass]" 
 | 
    :style="[noticeStyle]" 
 | 
  > 
 | 
    <view class="tn-row-notice__wrap"> 
 | 
      <!-- 左图标 --> 
 | 
      <view class="tn-row-notice__icon"> 
 | 
        <view 
 | 
          v-if="leftIcon" 
 | 
          class="tn-row-notice__icon--left"  
 | 
          :class="[`tn-icon-${leftIconName}`,fontColorClass]" 
 | 
          :style="[fontStyle('leftIcon')]" 
 | 
          @tap="clickLeftIcon"></view> 
 | 
      </view> 
 | 
       
 | 
      <!-- 消息体 --> 
 | 
      <view class="tn-row-notice__content-box" id="tn-row-notice__content-box"> 
 | 
        <view 
 | 
          class="tn-row-notice__content" 
 | 
          id="tn-row-notice__content" 
 | 
          :style="{ 
 | 
            animationDuration: animationDuration, 
 | 
            animationPlayState: animationPlayState 
 | 
          }" 
 | 
        > 
 | 
          <text 
 | 
            class="tn-row-notice__content--text" 
 | 
            :class="[fontColorClass]" 
 | 
            :style="[fontStyle()]" 
 | 
            @tap="click" 
 | 
          >{{ showText }}</text> 
 | 
        </view> 
 | 
      </view> 
 | 
       
 | 
      <!-- 右图标 --> 
 | 
      <view class="tn-row-notice__icon"> 
 | 
        <view 
 | 
          v-if="rightIcon" 
 | 
          class="tn-row-notice__icon--right"  
 | 
          :class="[`tn-icon-${rightIconName}`,fontColorClass]" 
 | 
          :style="[fontStyle('rightIcon')]" 
 | 
          @tap="clickRightIcon"></view> 
 | 
        <view 
 | 
          v-if="closeBtn" 
 | 
          class="tn-row-notice__icon--right"  
 | 
          :class="[`tn-icon-close`,fontColorClass]" 
 | 
          :style="[fontStyle('close')]" 
 | 
          @tap="close"></view> 
 | 
      </view> 
 | 
    </view> 
 | 
  </view> 
 | 
</template> 
 | 
  
 | 
<script> 
 | 
  import componentsColorMixin from '../../libs/mixin/components_color.js' 
 | 
  export default { 
 | 
    name: 'tn-row-notice', 
 | 
    mixins: [componentsColorMixin], 
 | 
    props: { 
 | 
      // 显示的内容 
 | 
      list: { 
 | 
        type: Array, 
 | 
        default() { 
 | 
          return [] 
 | 
        } 
 | 
      }, 
 | 
      // 是否显示 
 | 
      show: { 
 | 
        type: Boolean, 
 | 
        default: true 
 | 
      }, 
 | 
      // 播放状态 
 | 
      // play -> 播放 paused -> 暂停 
 | 
      playStatus: { 
 | 
        type: String, 
 | 
        default: 'play' 
 | 
      }, 
 | 
      // 是否显示左边图标 
 | 
      leftIcon: { 
 | 
        type: Boolean, 
 | 
        default: true 
 | 
      }, 
 | 
      // 左边图标的名称 
 | 
      leftIconName: { 
 | 
        type: String, 
 | 
        default: 'sound' 
 | 
      }, 
 | 
      // 左边图标的大小 
 | 
      leftIconSize: { 
 | 
        type: Number, 
 | 
        default: 34 
 | 
      }, 
 | 
      // 是否显示右边的图标 
 | 
      rightIcon: { 
 | 
        type: Boolean, 
 | 
        default: false 
 | 
      }, 
 | 
      // 右边图标的名称 
 | 
      rightIconName: { 
 | 
        type: String, 
 | 
        default: 'right' 
 | 
      }, 
 | 
      // 右边图标的大小 
 | 
      rightIconSize: { 
 | 
        type: Number, 
 | 
        default: 26 
 | 
      }, 
 | 
      // 是否显示关闭按钮 
 | 
      closeBtn: { 
 | 
        type: Boolean, 
 | 
        default: false 
 | 
      }, 
 | 
      // 圆角 
 | 
      radius: { 
 | 
        type: Number, 
 | 
        default: 0 
 | 
      }, 
 | 
      // 内边距 
 | 
      padding: { 
 | 
        type: String, 
 | 
        default: '18rpx 24rpx' 
 | 
      }, 
 | 
      // 自动播放 
 | 
      autoplay: { 
 | 
        type: Boolean, 
 | 
        default: true 
 | 
      }, 
 | 
      // 水平滚动时的速度,即每秒滚动多少rpx 
 | 
      speed: { 
 | 
        type: Number, 
 | 
        default: 160 
 | 
      } 
 | 
    }, 
 | 
    computed: { 
 | 
      fontStyle() { 
 | 
        return (type) => { 
 | 
          let style = {} 
 | 
          style.color = this.fontColorStyle ? this.fontColorStyle : '' 
 | 
          style.fontSize = this.fontSizeStyle ? this.fontSizeStyle : '' 
 | 
          if (type === 'leftIcon' && this.leftIconSize) { 
 | 
            style.fontSize = this.leftIconSize + 'rpx' 
 | 
          } 
 | 
          if (type === 'rightIcon' && this.rightIconSize) { 
 | 
            style.fontSize = this.rightIconSize + 'rpx' 
 | 
          } 
 | 
          if (type === 'close') { 
 | 
            style.fontSize = '24rpx' 
 | 
          } 
 | 
           
 | 
          return style 
 | 
        } 
 | 
      }, 
 | 
      noticeStyle() { 
 | 
        let style = {} 
 | 
        style.backgroundColor = this.backgroundColorStyle ? this.backgroundColorStyle : 'transparent' 
 | 
        if (this.padding) style.padding = this.padding 
 | 
        return style 
 | 
      } 
 | 
    }, 
 | 
    data() { 
 | 
      return { 
 | 
        // 滚动文字的宽度 
 | 
        textWidth: 0, 
 | 
        // 存放滚动文字的盒子的宽度 
 | 
        textBoxWidth: 0, 
 | 
        // 动画执行的时间 
 | 
        animationDuration: '10s', 
 | 
        // 动画执行状态 
 | 
        animationPlayState: 'paused', 
 | 
        // 当前显示的文本 
 | 
        showText: '' 
 | 
      } 
 | 
    }, 
 | 
    watch: { 
 | 
      list: { 
 | 
        handler(value) { 
 | 
          this.showText = value.join(',') 
 | 
          this.$nextTick(() => { 
 | 
            this.initNotice() 
 | 
          }) 
 | 
        }, 
 | 
        immediate: true 
 | 
      }, 
 | 
      playStatus(value) { 
 | 
        if (value === 'play') this.animationPlayState = 'running' 
 | 
        else this.animationPlayState = 'paused' 
 | 
      }, 
 | 
      speed(value) { 
 | 
        this.initNotice() 
 | 
      } 
 | 
    }, 
 | 
    methods: { 
 | 
      // 初始化通知栏 
 | 
      initNotice() { 
 | 
        let query = [], 
 | 
          textBoxWidth = 0, 
 | 
          textWidth = 0; 
 | 
        let textQuery = new Promise((resolve, reject) => { 
 | 
          uni.createSelectorQuery() 
 | 
            .in(this) 
 | 
            .select(`#tn-row-notice__content`) 
 | 
            .boundingClientRect() 
 | 
            .exec(ret => { 
 | 
              this.textWidth = ret[0].width 
 | 
              resolve() 
 | 
            }) 
 | 
        }) 
 | 
        query.push(textQuery) 
 | 
         
 | 
        Promise.all(query).then(() => { 
 | 
          // 根据t=s/v(时间=路程/速度),这里为何不需要加上#tn-row-notice__content-box的宽度,因为设置了.tn-row-notice__content样式中设置了padding-left: 100% 
 | 
          this.animationDuration = `${this.textWidth / uni.upx2px(this.speed)}s` 
 | 
          // 这里必须这样开始动画,否则在APP上动画速度不会改变(HX版本2.4.6,IOS13) 
 | 
          this.animationPlayState = 'paused' 
 | 
          setTimeout(() => { 
 | 
            if (this.autoplay && this.playStatus === 'play') this.animationPlayState = 'running' 
 | 
          }, 10) 
 | 
        }) 
 | 
      }, 
 | 
      // 点击了通知栏 
 | 
      click() { 
 | 
        this.$emit('click') 
 | 
      }, 
 | 
      // 点击了关闭按钮 
 | 
      close() { 
 | 
        this.$emit('close') 
 | 
      }, 
 | 
      // 点击了左边图标 
 | 
      clickLeftIcon() { 
 | 
        this.$emit('clickLeft') 
 | 
      }, 
 | 
      // 点击了右边图标 
 | 
      clickRightIcon() { 
 | 
        this.$emit('clickRight') 
 | 
      } 
 | 
    } 
 | 
  } 
 | 
</script> 
 | 
  
 | 
<style lang="scss" scoped> 
 | 
   
 | 
  .tn-row-notice { 
 | 
    width: 100%; 
 | 
    overflow: hidden; 
 | 
     
 | 
    &__wrap { 
 | 
      display: flex; 
 | 
      flex-direction: row; 
 | 
      align-items: center; 
 | 
      justify-content: space-between; 
 | 
    } 
 | 
     
 | 
    &__content { 
 | 
      &-box { 
 | 
        flex: 1; 
 | 
        display: flex; 
 | 
        flex-direction: row; 
 | 
        overflow: hidden; 
 | 
        margin-left: 12rpx; 
 | 
      } 
 | 
       
 | 
      display: flex; 
 | 
      flex-direction: row; 
 | 
      flex-wrap: nowrap; 
 | 
      text-align: right; 
 | 
      // 为了能滚动起来 
 | 
      padding-left: 100%; 
 | 
      animation: tn-notice-loop-animation 10s linear infinite both; 
 | 
       
 | 
      &--text { 
 | 
        word-break: keep-all; 
 | 
        white-space: nowrap; 
 | 
      } 
 | 
    } 
 | 
     
 | 
    &__icon { 
 | 
      &--left { 
 | 
        display: inline-flex; 
 | 
        align-items: center; 
 | 
      } 
 | 
       
 | 
      &--right { 
 | 
        margin-left: 12rpx; 
 | 
        display: inline-flex; 
 | 
        align-items: center; 
 | 
      } 
 | 
    } 
 | 
  } 
 | 
   
 | 
  @keyframes tn-notice-loop-animation { 
 | 
    0% { 
 | 
      transform: translateX(0); 
 | 
    } 
 | 
    100% { 
 | 
      transform: translateX(-100%); 
 | 
    } 
 | 
  } 
 | 
</style> 
 |