u-row-notice.vue 6.6 KB

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