<!-- 公告栏组件 --> <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>