u-row-notice.vue 6.4 KB

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