blob: f4683f1e6716f81ca592e9cd87941fbf06b040f8 [file] [log] [blame]
guangchao.xu070005a2020-12-07 09:56:40 +08001<template>
2 <view
3 v-if="show"
4 class="u-notice-bar"
5 :style="{
6 background: computeBgColor,
7 padding: padding
8 }"
9 :class="[
10 type ? `u-type-${type}-light-bg` : ''
11 ]"
12 >
13 <view class="u-direction-row">
14 <view class="u-icon-wrap">
15 <u-icon class="u-left-icon" v-if="volumeIcon" name="volume-fill" :size="volumeSize" :color="computeColor"></u-icon>
16 </view>
17 <view class="u-notice-box" id="u-notice-box">
18 <view
19 class="u-notice-content"
20 id="u-notice-content"
21 :style="{
22 animationDuration: animationDuration,
23 animationPlayState: animationPlayState,
24 }"
25 >
26 <text class="u-notice-text" @tap="click" :style="[textStyle]"
27 :class="['u-type-' + type]">{{showText}}</text>
28 </view>
29 </view>
30 <view class="u-icon-wrap">
31 <u-icon @click="getMore" class="u-right-icon" v-if="moreIcon" name="arrow-right" :size="26" :color="computeColor"></u-icon>
32 <u-icon @click="close" class="u-right-icon" v-if="closeIcon" name="close" :size="24" :color="computeColor"></u-icon>
33 </view>
34 </view>
35 </view>
36</template>
37<script>
38export default {
39 props: {
40 // 显示的内容,数组
41 list: {
42 type: Array,
43 default() {
44 return [];
45 }
46 },
47 // 显示的主题,success|error|primary|info|warning|none
48 // none主题默认为透明背景,黑色(contentColor)字体
49 type: {
50 type: String,
51 default: 'warning'
52 },
53 // 是否显示左侧的音量图标
54 volumeIcon: {
55 type: Boolean,
56 default: true
57 },
58 // 是否显示右侧的右箭头图标
59 moreIcon: {
60 type: Boolean,
61 default: false
62 },
63 // 是否显示右侧的关闭图标
64 closeIcon: {
65 type: Boolean,
66 default: false
67 },
68 // 是否自动播放
69 autoplay: {
70 type: Boolean,
71 default: true
72 },
73 // 文字颜色,各图标也会使用文字颜色
74 color: {
75 type: String,
76 default: ''
77 },
78 // 背景颜色
79 bgColor: {
80 type: String,
81 default: ''
82 },
83 // 是否显示
84 show: {
85 type: Boolean,
86 default: true
87 },
88 // 字体大小,单位rpx
89 fontSize: {
90 type: [Number, String],
91 default: 26
92 },
93 // 音量喇叭的大小
94 volumeSize: {
95 type: [Number, String],
96 default: 34
97 },
98 // 水平滚动时的滚动速度,即每秒滚动多少rpx,这有利于控制文字无论多少时,都能有一个恒定的速度
99 speed: {
100 type: [Number, String],
101 default: 160
102 },
103 // 播放状态,play-播放,paused-暂停
104 playState: {
105 type: String,
106 default: 'play'
107 },
108 // 通知的边距
109 padding: {
110 type: [Number, String],
111 default: '18rpx 24rpx'
112 }
113 },
114 data() {
115 return {
116 textWidth: 0, // 滚动的文字宽度
117 boxWidth: 0, // 供文字滚动的父盒子的宽度,和前者一起为了计算滚动速度
118 animationDuration: '10s', // 动画执行时间
119 animationPlayState: 'paused', // 动画的开始和结束执行
120 showText: '' // 显示的文本
121 };
122 },
123 watch: {
124 list: {
125 immediate: true,
126 handler(val) {
127 this.showText = val.join(',');
128 this.$nextTick(() => {
129 this.initSize();
130 });
131 }
132 },
133 playState(val) {
134 if(val == 'play') this.animationPlayState = 'running';
135 else this.animationPlayState = 'paused';
136 },
137 speed(val) {
138 this.initSize();
139 }
140 },
141 computed: {
142 // 计算字体颜色,如果没有自定义的,就用uview主题颜色
143 computeColor() {
144 if (this.color) return this.color;
145 // 如果是无主题,就默认使用content-color
146 else if(this.type == 'none') return '#606266';
147 else return this.type;
148 },
149 // 文字内容的样式
150 textStyle() {
151 let style = {};
152 if (this.color) style.color = this.color;
153 else if(this.type == 'none') style.color = '#606266';
154 style.fontSize = this.fontSize + 'rpx';
155 return style;
156 },
157 // 计算背景颜色
158 computeBgColor() {
159 if (this.bgColor) return this.bgColor;
160 else if(this.type == 'none') return 'transparent';
161 }
162 },
163 mounted() {
164 this.$nextTick(() => {
165 this.initSize();
166 });
167 },
168 methods: {
169 initSize() {
170 let query = [],
171 boxWidth = 0,
172 textWidth = 0;
173 let textQuery = new Promise((resolve, reject) => {
174 uni.createSelectorQuery()
175 .in(this)
176 .select(`#u-notice-content`)
177 .boundingClientRect()
178 .exec(ret => {
179 this.textWidth = ret[0].width;
180 resolve();
181 });
182 });
183 query.push(textQuery);
184 Promise.all(query).then(() => {
185 // 根据t=s/v(时间=路程/速度),这里为何不需要加上#u-notice-box的宽度,因为中设置了.u-notice-content样式中设置了padding-left: 100%
186 // 恰巧计算出来的结果中已经包含了#u-notice-box的宽度
187 this.animationDuration = `${this.textWidth / uni.upx2px(this.speed)}s`;
188 // 这里必须这样开始动画,否则在APP上动画速度不会改变(HX版本2.4.6,IOS13)
189 this.animationPlayState = 'paused';
190 setTimeout(() => {
191 if(this.playState == 'play' && this.autoplay) this.animationPlayState = 'running';
192 }, 10);
193 });
194 },
195 // 点击通告栏
196 click(index) {
197 this.$emit('click');
198 },
199 // 点击关闭按钮
200 close() {
201 this.$emit('close');
202 },
203 // 点击更多箭头按钮
204 getMore() {
205 this.$emit('getMore');
206 }
207 }
208};
209</script>
210
211<style lang="scss" scoped>
212@import "../../libs/css/style.components.scss";
213
214.u-notice-bar {
215 padding: 18rpx 24rpx;
216 overflow: hidden;
217}
218
219.u-direction-row {
220 @include vue-flex;
221 align-items: center;
222 justify-content: space-between;
223}
224
225.u-left-icon {
226 /* #ifndef APP-NVUE */
227 display: inline-flex;
228 /* #endif */
229 align-items: center;
230}
231
232.u-notice-box {
233 flex: 1;
234 @include vue-flex;
235 overflow: hidden;
236 margin-left: 12rpx;
237}
238
239.u-right-icon {
240 margin-left: 12rpx;
241 display: inline-flex;
242 align-items: center;
243}
244
245.u-notice-content {
246 animation: u-loop-animation 10s linear infinite both;
247 text-align: right;
248 // 这一句很重要,为了能让滚动左右连接起来
249 padding-left: 100%;
250 @include vue-flex;
251 flex-wrap: nowrap;
252}
253
254.u-notice-text {
255 font-size: 26rpx;
256 word-break: keep-all;
257 white-space: nowrap
258}
259
260@keyframes u-loop-animation {
261 0% {
262 transform: translate3d(0, 0, 0);
263 }
264
265 100% {
266 transform: translate3d(-100%, 0, 0);
267 }
268}
269</style>