cl-noticebar.vue 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. <template>
  2. <view
  3. class="cl-noticebar"
  4. :class="[classList]"
  5. :style="{
  6. color,
  7. backgroundColor,
  8. }"
  9. v-if="visible"
  10. >
  11. <view class="cl-noticebar__close" @tap="close" v-if="closeable">
  12. <cl-icon name="cl-icon-close-border" :size="36"></cl-icon>
  13. </view>
  14. <view class="cl-noticebar__icon" v-if="$slots.icon || icon">
  15. <slot v-if="$slots.icon" name="icon"></slot>
  16. <cl-icon v-else :name="icon" :size="36"></cl-icon>
  17. </view>
  18. <view class="cl-noticebar__box">
  19. <view
  20. class="cl-noticebar__scroller"
  21. :class="[`is-${direction}`]"
  22. :style="{
  23. top: scroll.top + 'px',
  24. left: scroll.left + 'px',
  25. transition,
  26. transform: `translateX(-${scroll.translateX}px)`,
  27. }"
  28. >
  29. <text class="cl-noticebar__text" v-for="(item, index) in list" :key="index">{{
  30. item
  31. }}</text>
  32. </view>
  33. </view>
  34. <view class="cl-noticebar__more"></view>
  35. </view>
  36. </template>
  37. <script>
  38. import { isArray } from "../../utils";
  39. /**
  40. * noticebar 通知栏
  41. * @description 支持水平垂直方式滚动
  42. * @tutorial https://docs.cool-js.com/uni/components/view/noticebar.html
  43. * @property {String, Array} text 文本内容
  44. * @property {String} direction 方向 horizontal | vertical,默认horizontal
  45. * @property {String} color 字体颜色
  46. * @property {String} backgroundColor 背景颜色
  47. * @property {String} type 通知类型
  48. * @property {Boolean} scrollable 能否滚动
  49. * @property {Boolean} closeable 能否关闭
  50. * @property {String} icon 图标
  51. * @property {Number} duration 滑动时长(秒),默认6
  52. * @example <cl-noticebar text="云想衣裳花想容,春风拂槛露华浓。"></cl-noticebar>
  53. */
  54. export default {
  55. name: "cl-noticebar",
  56. props: {
  57. // 文本内容
  58. text: {
  59. type: [String, Array],
  60. default: "",
  61. required: true,
  62. },
  63. // 方向 horizontal | vertical
  64. direction: {
  65. type: String,
  66. default: "horizontal",
  67. },
  68. // 字体颜色
  69. color: {
  70. type: String,
  71. default: "#444",
  72. },
  73. // 背景颜色
  74. backgroundColor: {
  75. type: String,
  76. default: "#fff",
  77. },
  78. // 通知类型
  79. type: {
  80. type: String,
  81. default: "default",
  82. },
  83. // 能否滚动
  84. scrollable: Boolean,
  85. // 能否关闭
  86. closeable: Boolean,
  87. // 图标
  88. icon: String,
  89. // 滑动时长(秒),默认6
  90. duration: {
  91. type: Number,
  92. default: 6,
  93. },
  94. },
  95. data() {
  96. return {
  97. scroll: {
  98. left: 0,
  99. top: 0,
  100. translateX: 0,
  101. duration: 0,
  102. },
  103. timer: null,
  104. visible: true,
  105. };
  106. },
  107. computed: {
  108. list() {
  109. return isArray(this.text) ? this.text : [this.text];
  110. },
  111. classList() {
  112. let list = [];
  113. if (this.scrollable) {
  114. list.push("cl-noticebar--scrollable");
  115. }
  116. return list.join(" ");
  117. },
  118. transition() {
  119. if (this.direction == "horizontal") {
  120. return `transform ${this.scroll.duration}s linear`;
  121. } else {
  122. return `top 0.3s`;
  123. }
  124. },
  125. },
  126. mounted() {
  127. this.refresh();
  128. },
  129. destroyed() {
  130. this.clear();
  131. this.timer = null;
  132. },
  133. methods: {
  134. close() {
  135. this.visible = false;
  136. },
  137. clear() {
  138. clearInterval(this.timer);
  139. clearTimeout(this.timer);
  140. },
  141. refresh() {
  142. if (this.scrollable) {
  143. // 清除定时器
  144. this.clear();
  145. // 获取盒子大小
  146. uni.createSelectorQuery()
  147. .in(this)
  148. .select(`.cl-noticebar__box`)
  149. .boundingClientRect((box) => {
  150. // 获取文本大小
  151. uni.createSelectorQuery()
  152. .in(this)
  153. .select(`.cl-noticebar__text`)
  154. .boundingClientRect((text) => {
  155. let duration = this.duration * 1000;
  156. // 水平滑动
  157. if (this.direction == "horizontal") {
  158. const fn = () => {
  159. this.scroll.duration = this.duration;
  160. this.scroll.left = box.width;
  161. this.scroll.translateX = text.width + this.scroll.left;
  162. this.timer = setTimeout(() => {
  163. this.scroll.translateX = 0;
  164. this.scroll.duration = 0;
  165. setTimeout(fn, 500);
  166. }, duration);
  167. };
  168. fn();
  169. }
  170. // 垂直滑动
  171. else {
  172. this.timer = setInterval(() => {
  173. if (
  174. Math.abs(this.scroll.top) >=
  175. box.height * (this.list.length - 1)
  176. ) {
  177. this.scroll.top = 0;
  178. } else {
  179. this.scroll.top -= box.height;
  180. }
  181. }, duration);
  182. }
  183. })
  184. .exec();
  185. })
  186. .exec();
  187. }
  188. },
  189. },
  190. };
  191. </script>