NoticeBar.mjs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. import { withDirectives as _withDirectives, vShow as _vShow, createVNode as _createVNode } from "vue";
  2. import { ref, watch, reactive, defineComponent } from "vue";
  3. import { isDef, createNamespace, makeNumericProp } from "../utils/index.mjs";
  4. import { raf, useRect, doubleRaf, useEventListener, onMountedOrActivated } from "@vant/use";
  5. import { useExpose } from "../composables/use-expose.mjs";
  6. import { onPopupReopen } from "../composables/on-popup-reopen.mjs";
  7. import { Icon } from "../icon/index.mjs";
  8. const [name, bem] = createNamespace("notice-bar");
  9. const noticeBarProps = {
  10. text: String,
  11. mode: String,
  12. color: String,
  13. delay: makeNumericProp(1),
  14. speed: makeNumericProp(60),
  15. leftIcon: String,
  16. wrapable: Boolean,
  17. background: String,
  18. scrollable: {
  19. type: Boolean,
  20. default: null
  21. }
  22. };
  23. var stdin_default = defineComponent({
  24. name,
  25. props: noticeBarProps,
  26. emits: ["close", "replay"],
  27. setup(props, {
  28. emit,
  29. slots
  30. }) {
  31. let wrapWidth = 0;
  32. let contentWidth = 0;
  33. let startTimer;
  34. const wrapRef = ref();
  35. const contentRef = ref();
  36. const state = reactive({
  37. show: true,
  38. offset: 0,
  39. duration: 0
  40. });
  41. const renderLeftIcon = () => {
  42. if (slots["left-icon"]) {
  43. return slots["left-icon"]();
  44. }
  45. if (props.leftIcon) {
  46. return _createVNode(Icon, {
  47. "class": bem("left-icon"),
  48. "name": props.leftIcon
  49. }, null);
  50. }
  51. };
  52. const getRightIconName = () => {
  53. if (props.mode === "closeable") {
  54. return "cross";
  55. }
  56. if (props.mode === "link") {
  57. return "arrow";
  58. }
  59. };
  60. const onClickRightIcon = (event) => {
  61. if (props.mode === "closeable") {
  62. state.show = false;
  63. emit("close", event);
  64. }
  65. };
  66. const renderRightIcon = () => {
  67. if (slots["right-icon"]) {
  68. return slots["right-icon"]();
  69. }
  70. const name2 = getRightIconName();
  71. if (name2) {
  72. return _createVNode(Icon, {
  73. "name": name2,
  74. "class": bem("right-icon"),
  75. "onClick": onClickRightIcon
  76. }, null);
  77. }
  78. };
  79. const onTransitionEnd = () => {
  80. state.offset = wrapWidth;
  81. state.duration = 0;
  82. raf(() => {
  83. doubleRaf(() => {
  84. state.offset = -contentWidth;
  85. state.duration = (contentWidth + wrapWidth) / +props.speed;
  86. emit("replay");
  87. });
  88. });
  89. };
  90. const renderMarquee = () => {
  91. const ellipsis = props.scrollable === false && !props.wrapable;
  92. const style = {
  93. transform: state.offset ? `translateX(${state.offset}px)` : "",
  94. transitionDuration: `${state.duration}s`
  95. };
  96. return _createVNode("div", {
  97. "ref": wrapRef,
  98. "role": "marquee",
  99. "class": bem("wrap")
  100. }, [_createVNode("div", {
  101. "ref": contentRef,
  102. "style": style,
  103. "class": [bem("content"), {
  104. "van-ellipsis": ellipsis
  105. }],
  106. "onTransitionend": onTransitionEnd
  107. }, [slots.default ? slots.default() : props.text])]);
  108. };
  109. const reset = () => {
  110. const {
  111. delay,
  112. speed,
  113. scrollable
  114. } = props;
  115. const ms = isDef(delay) ? +delay * 1e3 : 0;
  116. wrapWidth = 0;
  117. contentWidth = 0;
  118. state.offset = 0;
  119. state.duration = 0;
  120. clearTimeout(startTimer);
  121. startTimer = setTimeout(() => {
  122. if (!wrapRef.value || !contentRef.value || scrollable === false) {
  123. return;
  124. }
  125. const wrapRefWidth = useRect(wrapRef).width;
  126. const contentRefWidth = useRect(contentRef).width;
  127. if (scrollable || contentRefWidth > wrapRefWidth) {
  128. doubleRaf(() => {
  129. wrapWidth = wrapRefWidth;
  130. contentWidth = contentRefWidth;
  131. state.offset = -contentWidth;
  132. state.duration = contentWidth / +speed;
  133. });
  134. }
  135. }, ms);
  136. };
  137. onPopupReopen(reset);
  138. onMountedOrActivated(reset);
  139. useEventListener("pageshow", reset);
  140. useExpose({
  141. reset
  142. });
  143. watch(() => [props.text, props.scrollable], reset);
  144. return () => {
  145. const {
  146. color,
  147. wrapable,
  148. background
  149. } = props;
  150. return _withDirectives(_createVNode("div", {
  151. "role": "alert",
  152. "class": bem({
  153. wrapable
  154. }),
  155. "style": {
  156. color,
  157. background
  158. }
  159. }, [renderLeftIcon(), renderMarquee(), renderRightIcon()]), [[_vShow, state.show]]);
  160. };
  161. }
  162. });
  163. export {
  164. stdin_default as default
  165. };