474 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Vue
		
	
	
			
		
		
	
	
			474 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Vue
		
	
	
<!-- 公告栏组件 -->
 | 
						||
<template>
 | 
						||
  <view
 | 
						||
    v-if="show"
 | 
						||
    class="uni-noticebar"
 | 
						||
    :style="{ backgroundColor: backgroundColor }"
 | 
						||
    @click="onClick"
 | 
						||
  >
 | 
						||
    <slot name="icon">
 | 
						||
      <uni-icons
 | 
						||
        v-if="showIcon === true || showIcon === 'true'"
 | 
						||
        class="uni-noticebar-icon"
 | 
						||
        type="sound"
 | 
						||
        :color="color"
 | 
						||
        size="22"
 | 
						||
      />
 | 
						||
    </slot>
 | 
						||
    <view
 | 
						||
      ref="textBox"
 | 
						||
      class="uni-noticebar__content-wrapper"
 | 
						||
      :class="{
 | 
						||
        'uni-noticebar__content-wrapper--scrollable': scrollable,
 | 
						||
        'uni-noticebar__content-wrapper--single': !scrollable && (single || moreText),
 | 
						||
      }"
 | 
						||
    >
 | 
						||
      <view
 | 
						||
        :id="elIdBox"
 | 
						||
        class="uni-noticebar__content"
 | 
						||
        :class="{
 | 
						||
          'uni-noticebar__content--scrollable': scrollable,
 | 
						||
          'uni-noticebar__content--single': !scrollable && (single || moreText),
 | 
						||
        }"
 | 
						||
      >
 | 
						||
        <text
 | 
						||
          :id="elId"
 | 
						||
          ref="animationEle"
 | 
						||
          class="uni-noticebar__content-text"
 | 
						||
          :class="{
 | 
						||
            'uni-noticebar__content-text--scrollable': scrollable,
 | 
						||
            'uni-noticebar__content-text--single': !scrollable && (single || showGetMore),
 | 
						||
          }"
 | 
						||
          :style="{
 | 
						||
            color: color,
 | 
						||
            width: wrapWidth + 'px',
 | 
						||
            animationDuration: animationDuration,
 | 
						||
            '-webkit-animationDuration': animationDuration,
 | 
						||
            animationPlayState: webviewHide ? 'paused' : animationPlayState,
 | 
						||
            '-webkit-animationPlayState': webviewHide ? 'paused' : animationPlayState,
 | 
						||
            animationDelay: animationDelay,
 | 
						||
            '-webkit-animationDelay': animationDelay,
 | 
						||
          }"
 | 
						||
        >
 | 
						||
          {{ text }}
 | 
						||
        </text>
 | 
						||
      </view>
 | 
						||
    </view>
 | 
						||
    <view
 | 
						||
      v-if="showGetMore === true || showGetMore === 'true'"
 | 
						||
      class="uni-noticebar__more uni-cursor-point"
 | 
						||
      @click="clickMore"
 | 
						||
    >
 | 
						||
      <text
 | 
						||
        v-if="moreText.length > 0"
 | 
						||
        :style="{ color: moreColor }"
 | 
						||
        class="uni-noticebar__more-text"
 | 
						||
      >
 | 
						||
        {{ moreText }}
 | 
						||
      </text>
 | 
						||
      <uni-icons v-else type="right" :color="moreColor" size="16" />
 | 
						||
    </view>
 | 
						||
    <view
 | 
						||
      class="uni-noticebar-close uni-cursor-point"
 | 
						||
      v-if="
 | 
						||
        (showClose === true || showClose === 'true') &&
 | 
						||
        (showGetMore === false || showGetMore === 'false')
 | 
						||
      "
 | 
						||
    >
 | 
						||
      <view @click="close">
 | 
						||
        <slot name="close">
 | 
						||
          <uni-icons type="closeempty" :color="color" size="16" />
 | 
						||
        </slot>
 | 
						||
      </view>
 | 
						||
    </view>
 | 
						||
  </view>
 | 
						||
</template>
 | 
						||
 | 
						||
<script>
 | 
						||
  import sheep from '@/sheep';
 | 
						||
  // #ifdef APP-NVUE
 | 
						||
  const dom = weex.requireModule('dom');
 | 
						||
  const animation = weex.requireModule('animation');
 | 
						||
  // #endif
 | 
						||
 | 
						||
  /**
 | 
						||
   * NoticeBar 自定义导航栏
 | 
						||
   * @description 通告栏组件
 | 
						||
   * @tutorial https://ext.dcloud.net.cn/plugin?id=30
 | 
						||
   * @property {Number} speed 文字滚动的速度,默认100px/秒
 | 
						||
   * @property {String} text 显示文字
 | 
						||
   * @property {String} backgroundColor 背景颜色
 | 
						||
   * @property {String} color 文字颜色
 | 
						||
   * @property {String} moreColor 查看更多文字的颜色
 | 
						||
   * @property {String} moreText 设置“查看更多”的文本
 | 
						||
   * @property {Boolean} single = [true|false] 是否单行
 | 
						||
   * @property {Boolean} scrollable = [true|false] 是否滚动,为true时,NoticeBar为单行
 | 
						||
   * @property {Boolean} showIcon = [true|false] 是否显示左侧喇叭图标
 | 
						||
   * @property {Boolean} showClose = [true|false] 是否显示左侧关闭按钮
 | 
						||
   * @property {Boolean} showGetMore = [true|false] 是否显示右侧查看更多图标,为true时,NoticeBar为单行
 | 
						||
   * @event {Function} click 点击 NoticeBar 触发事件
 | 
						||
   * @event {Function} close 关闭 NoticeBar 触发事件
 | 
						||
   * @event {Function} getmore 点击”查看更多“时触发事件
 | 
						||
   */
 | 
						||
 | 
						||
  export default {
 | 
						||
    name: 'UniNoticeBar',
 | 
						||
    emits: ['click', 'getmore', 'close'],
 | 
						||
    props: {
 | 
						||
      text: {
 | 
						||
        type: String,
 | 
						||
        default: '',
 | 
						||
      },
 | 
						||
      moreText: {
 | 
						||
        type: String,
 | 
						||
        default: '',
 | 
						||
      },
 | 
						||
      backgroundColor: {
 | 
						||
        type: String,
 | 
						||
        default: '',
 | 
						||
      },
 | 
						||
      speed: {
 | 
						||
        // 默认1s滚动100px
 | 
						||
        type: Number,
 | 
						||
        default: 100,
 | 
						||
      },
 | 
						||
      color: {
 | 
						||
        type: String,
 | 
						||
        default: 'var(--ui-BG-Main)',
 | 
						||
      },
 | 
						||
      moreColor: {
 | 
						||
        type: String,
 | 
						||
        default: '#FF9A43',
 | 
						||
      },
 | 
						||
      single: {
 | 
						||
        // 是否单行
 | 
						||
        type: [Boolean, String],
 | 
						||
        default: false,
 | 
						||
      },
 | 
						||
      scrollable: {
 | 
						||
        // 是否滚动,添加后控制单行效果取消
 | 
						||
        type: [Boolean, String],
 | 
						||
        default: false,
 | 
						||
      },
 | 
						||
      showIcon: {
 | 
						||
        // 是否显示左侧icon
 | 
						||
        type: [Boolean, String],
 | 
						||
        default: false,
 | 
						||
      },
 | 
						||
      showGetMore: {
 | 
						||
        // 是否显示右侧查看更多
 | 
						||
        type: [Boolean, String],
 | 
						||
        default: false,
 | 
						||
      },
 | 
						||
      showClose: {
 | 
						||
        // 是否显示左侧关闭按钮
 | 
						||
        type: [Boolean, String],
 | 
						||
        default: false,
 | 
						||
      },
 | 
						||
    },
 | 
						||
    data() {
 | 
						||
      const elId = `Uni_${Math.ceil(Math.random() * 10e5).toString(36)}`;
 | 
						||
      const elIdBox = `Uni_${Math.ceil(Math.random() * 10e5).toString(36)}`;
 | 
						||
      return {
 | 
						||
        textWidth: 0,
 | 
						||
        boxWidth: 0,
 | 
						||
        wrapWidth: '',
 | 
						||
        webviewHide: false,
 | 
						||
        // #ifdef APP-NVUE
 | 
						||
        stopAnimation: false,
 | 
						||
        // #endif
 | 
						||
        elId: elId,
 | 
						||
        elIdBox: elIdBox,
 | 
						||
        show: true,
 | 
						||
        animationDuration: 'none',
 | 
						||
        animationPlayState: 'paused',
 | 
						||
        animationDelay: '0s',
 | 
						||
      };
 | 
						||
    },
 | 
						||
    mounted() {
 | 
						||
      // #ifdef APP-PLUS
 | 
						||
      var pages = getCurrentPages();
 | 
						||
      var page = pages[pages.length - 1];
 | 
						||
      var currentWebview = page.$getAppWebview();
 | 
						||
      currentWebview.addEventListener('hide', () => {
 | 
						||
        this.webviewHide = true;
 | 
						||
      });
 | 
						||
      currentWebview.addEventListener('show', () => {
 | 
						||
        this.webviewHide = false;
 | 
						||
      });
 | 
						||
      // #endif
 | 
						||
      this.$nextTick(() => {
 | 
						||
        this.initSize();
 | 
						||
      });
 | 
						||
    },
 | 
						||
    // #ifdef APP-NVUE
 | 
						||
    beforeDestroy() {
 | 
						||
      this.stopAnimation = true;
 | 
						||
    },
 | 
						||
    // #endif
 | 
						||
    methods: {
 | 
						||
      initSize() {
 | 
						||
        if (this.scrollable) {
 | 
						||
          // #ifndef APP-NVUE
 | 
						||
          let query = [],
 | 
						||
            boxWidth = 0,
 | 
						||
            textWidth = 0;
 | 
						||
          let textQuery = new Promise((resolve, reject) => {
 | 
						||
            uni.createSelectorQuery()
 | 
						||
              // #ifndef MP-ALIPAY
 | 
						||
              .in(this)
 | 
						||
              // #endif
 | 
						||
              .select(`#${this.elId}`)
 | 
						||
              .boundingClientRect()
 | 
						||
              .exec((ret) => {
 | 
						||
                this.textWidth = ret[0].width;
 | 
						||
                resolve();
 | 
						||
              });
 | 
						||
          });
 | 
						||
          let boxQuery = new Promise((resolve, reject) => {
 | 
						||
            uni.createSelectorQuery()
 | 
						||
              // #ifndef MP-ALIPAY
 | 
						||
              .in(this)
 | 
						||
              // #endif
 | 
						||
              .select(`#${this.elIdBox}`)
 | 
						||
              .boundingClientRect()
 | 
						||
              .exec((ret) => {
 | 
						||
                this.boxWidth = ret[0].width;
 | 
						||
                resolve();
 | 
						||
              });
 | 
						||
          });
 | 
						||
          query.push(textQuery);
 | 
						||
          query.push(boxQuery);
 | 
						||
          Promise.all(query).then(() => {
 | 
						||
            this.animationDuration = `${this.textWidth / this.speed}s`;
 | 
						||
            this.animationDelay = `-${this.boxWidth / this.speed}s`;
 | 
						||
            setTimeout(() => {
 | 
						||
              this.animationPlayState = 'running';
 | 
						||
            }, 1000);
 | 
						||
          });
 | 
						||
          // #endif
 | 
						||
          // #ifdef APP-NVUE
 | 
						||
          dom.getComponentRect(this.$refs['animationEle'], (res) => {
 | 
						||
            let winWidth = sheep.$platform.device.windowWidth;
 | 
						||
            this.textWidth = res.size.width;
 | 
						||
            animation.transition(
 | 
						||
              this.$refs['animationEle'],
 | 
						||
              {
 | 
						||
                styles: {
 | 
						||
                  transform: `translateX(-${winWidth}px)`,
 | 
						||
                },
 | 
						||
                duration: 0,
 | 
						||
                timingFunction: 'linear',
 | 
						||
                delay: 0,
 | 
						||
              },
 | 
						||
              () => {
 | 
						||
                if (!this.stopAnimation) {
 | 
						||
                  animation.transition(
 | 
						||
                    this.$refs['animationEle'],
 | 
						||
                    {
 | 
						||
                      styles: {
 | 
						||
                        transform: `translateX(-${this.textWidth}px)`,
 | 
						||
                      },
 | 
						||
                      timingFunction: 'linear',
 | 
						||
                      duration: ((this.textWidth - winWidth) / this.speed) * 1000,
 | 
						||
                      delay: 1000,
 | 
						||
                    },
 | 
						||
                    () => {
 | 
						||
                      if (!this.stopAnimation) {
 | 
						||
                        this.loopAnimation();
 | 
						||
                      }
 | 
						||
                    },
 | 
						||
                  );
 | 
						||
                }
 | 
						||
              },
 | 
						||
            );
 | 
						||
          });
 | 
						||
          // #endif
 | 
						||
        }
 | 
						||
        // #ifdef APP-NVUE
 | 
						||
        if (!this.scrollable && (this.single || this.moreText)) {
 | 
						||
          dom.getComponentRect(this.$refs['textBox'], (res) => {
 | 
						||
            this.wrapWidth = res.size.width;
 | 
						||
          });
 | 
						||
        }
 | 
						||
        // #endif
 | 
						||
      },
 | 
						||
      loopAnimation() {
 | 
						||
        // #ifdef APP-NVUE
 | 
						||
        animation.transition(
 | 
						||
          this.$refs['animationEle'],
 | 
						||
          {
 | 
						||
            styles: {
 | 
						||
              transform: `translateX(0px)`,
 | 
						||
            },
 | 
						||
            duration: 0,
 | 
						||
          },
 | 
						||
          () => {
 | 
						||
            if (!this.stopAnimation) {
 | 
						||
              animation.transition(
 | 
						||
                this.$refs['animationEle'],
 | 
						||
                {
 | 
						||
                  styles: {
 | 
						||
                    transform: `translateX(-${this.textWidth}px)`,
 | 
						||
                  },
 | 
						||
                  duration: (this.textWidth / this.speed) * 1000,
 | 
						||
                  timingFunction: 'linear',
 | 
						||
                  delay: 0,
 | 
						||
                },
 | 
						||
                () => {
 | 
						||
                  if (!this.stopAnimation) {
 | 
						||
                    this.loopAnimation();
 | 
						||
                  }
 | 
						||
                },
 | 
						||
              );
 | 
						||
            }
 | 
						||
          },
 | 
						||
        );
 | 
						||
        // #endif
 | 
						||
      },
 | 
						||
      clickMore() {
 | 
						||
        this.$emit('getmore');
 | 
						||
      },
 | 
						||
      close() {
 | 
						||
        this.show = false;
 | 
						||
        this.$emit('close');
 | 
						||
      },
 | 
						||
      onClick() {
 | 
						||
        this.$emit('click');
 | 
						||
      },
 | 
						||
    },
 | 
						||
  };
 | 
						||
</script>
 | 
						||
 | 
						||
<style lang="scss" scoped>
 | 
						||
  .uni-noticebar {
 | 
						||
    /* #ifndef APP-NVUE */
 | 
						||
    display: flex;
 | 
						||
    width: 100%;
 | 
						||
    box-sizing: border-box;
 | 
						||
    /* #endif */
 | 
						||
    flex-direction: row;
 | 
						||
    align-items: center;
 | 
						||
    padding: 10px 12px;
 | 
						||
    // margin-bottom: 10px;
 | 
						||
  }
 | 
						||
 | 
						||
  .uni-cursor-point {
 | 
						||
    /* #ifdef H5 */
 | 
						||
    cursor: pointer;
 | 
						||
    /* #endif */
 | 
						||
  }
 | 
						||
 | 
						||
  .uni-noticebar-close {
 | 
						||
    margin-left: 8px;
 | 
						||
    margin-right: 5px;
 | 
						||
  }
 | 
						||
 | 
						||
  .uni-noticebar-icon {
 | 
						||
    margin-right: 5px;
 | 
						||
  }
 | 
						||
 | 
						||
  .uni-noticebar__content-wrapper {
 | 
						||
    flex: 1;
 | 
						||
    flex-direction: column;
 | 
						||
    overflow: hidden;
 | 
						||
  }
 | 
						||
 | 
						||
  .uni-noticebar__content-wrapper--single {
 | 
						||
    /* #ifndef APP-NVUE */
 | 
						||
    line-height: 18px;
 | 
						||
    /* #endif */
 | 
						||
  }
 | 
						||
 | 
						||
  .uni-noticebar__content-wrapper--single,
 | 
						||
  .uni-noticebar__content-wrapper--scrollable {
 | 
						||
    flex-direction: row;
 | 
						||
  }
 | 
						||
 | 
						||
  /* #ifndef APP-NVUE */
 | 
						||
  .uni-noticebar__content-wrapper--scrollable {
 | 
						||
    position: relative;
 | 
						||
    height: 18px;
 | 
						||
  }
 | 
						||
 | 
						||
  /* #endif */
 | 
						||
 | 
						||
  .uni-noticebar__content--scrollable {
 | 
						||
    /* #ifdef APP-NVUE */
 | 
						||
    flex: 0;
 | 
						||
    /* #endif */
 | 
						||
    /* #ifndef APP-NVUE */
 | 
						||
    flex: 1;
 | 
						||
    display: block;
 | 
						||
    overflow: hidden;
 | 
						||
    /* #endif */
 | 
						||
  }
 | 
						||
 | 
						||
  .uni-noticebar__content--single {
 | 
						||
    /* #ifndef APP-NVUE */
 | 
						||
    display: flex;
 | 
						||
    flex: none;
 | 
						||
    width: 100%;
 | 
						||
    justify-content: center;
 | 
						||
    /* #endif */
 | 
						||
  }
 | 
						||
 | 
						||
  .uni-noticebar__content-text {
 | 
						||
    font-size: 14px;
 | 
						||
    line-height: 18px;
 | 
						||
    /* #ifndef APP-NVUE */
 | 
						||
    word-break: break-all;
 | 
						||
    /* #endif */
 | 
						||
  }
 | 
						||
 | 
						||
  .uni-noticebar__content-text--single {
 | 
						||
    /* #ifdef APP-NVUE */
 | 
						||
    lines: 1;
 | 
						||
    /* #endif */
 | 
						||
    /* #ifndef APP-NVUE */
 | 
						||
    display: block;
 | 
						||
    width: 100%;
 | 
						||
    white-space: nowrap;
 | 
						||
    /* #endif */
 | 
						||
    overflow: hidden;
 | 
						||
    text-overflow: ellipsis;
 | 
						||
  }
 | 
						||
 | 
						||
  .uni-noticebar__content-text--scrollable {
 | 
						||
    /* #ifdef APP-NVUE */
 | 
						||
    lines: 1;
 | 
						||
    padding-left: 750rpx;
 | 
						||
    /* #endif */
 | 
						||
    /* #ifndef APP-NVUE */
 | 
						||
    position: absolute;
 | 
						||
    display: block;
 | 
						||
    height: 18px;
 | 
						||
    line-height: 18px;
 | 
						||
    white-space: nowrap;
 | 
						||
    padding-left: 100%;
 | 
						||
    animation: notice 10s 0s linear infinite both;
 | 
						||
    animation-play-state: paused;
 | 
						||
    /* #endif */
 | 
						||
  }
 | 
						||
 | 
						||
  .uni-noticebar__more {
 | 
						||
    /* #ifndef APP-NVUE */
 | 
						||
    display: inline-flex;
 | 
						||
    /* #endif */
 | 
						||
    flex-direction: row;
 | 
						||
    flex-wrap: nowrap;
 | 
						||
    align-items: center;
 | 
						||
    padding-left: 5px;
 | 
						||
  }
 | 
						||
 | 
						||
  .uni-noticebar__more-text {
 | 
						||
    font-size: 14px;
 | 
						||
  }
 | 
						||
 | 
						||
  @keyframes notice {
 | 
						||
    100% {
 | 
						||
      transform: translate3d(-100%, 0, 0);
 | 
						||
    }
 | 
						||
  }
 | 
						||
</style>
 |