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>
 |