index.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. import { createNamespace, isDef } from '../utils';
  2. import { doubleRaf, raf } from '../utils/dom/raf';
  3. import { BindEventMixin } from '../mixins/bind-event';
  4. import Icon from '../icon';
  5. var _createNamespace = createNamespace('notice-bar'),
  6. createComponent = _createNamespace[0],
  7. bem = _createNamespace[1];
  8. export default createComponent({
  9. mixins: [BindEventMixin(function (bind) {
  10. // fix cache issues with forwards and back history in safari
  11. // see: https://guwii.com/cache-issues-with-forwards-and-back-history-in-safari/
  12. bind(window, 'pageshow', this.start);
  13. })],
  14. inject: {
  15. vanPopup: {
  16. default: null
  17. }
  18. },
  19. props: {
  20. text: String,
  21. mode: String,
  22. color: String,
  23. leftIcon: String,
  24. wrapable: Boolean,
  25. background: String,
  26. scrollable: {
  27. type: Boolean,
  28. default: null
  29. },
  30. delay: {
  31. type: [Number, String],
  32. default: 1
  33. },
  34. speed: {
  35. type: [Number, String],
  36. default: 60
  37. }
  38. },
  39. data: function data() {
  40. return {
  41. show: true,
  42. offset: 0,
  43. duration: 0,
  44. wrapWidth: 0,
  45. contentWidth: 0
  46. };
  47. },
  48. watch: {
  49. scrollable: 'start',
  50. text: {
  51. handler: 'start',
  52. immediate: true
  53. }
  54. },
  55. created: function created() {
  56. var _this = this;
  57. // https://github.com/youzan/vant/issues/8634
  58. if (this.vanPopup) {
  59. this.vanPopup.onReopen(function () {
  60. _this.start();
  61. });
  62. }
  63. },
  64. activated: function activated() {
  65. this.start();
  66. },
  67. methods: {
  68. onClickIcon: function onClickIcon(event) {
  69. if (this.mode === 'closeable') {
  70. this.show = false;
  71. this.$emit('close', event);
  72. }
  73. },
  74. onTransitionEnd: function onTransitionEnd() {
  75. var _this2 = this;
  76. this.offset = this.wrapWidth;
  77. this.duration = 0; // wait for Vue to render offset
  78. // using nextTick won't work in iOS14
  79. raf(function () {
  80. // use double raf to ensure animation can start
  81. doubleRaf(function () {
  82. _this2.offset = -_this2.contentWidth;
  83. _this2.duration = (_this2.contentWidth + _this2.wrapWidth) / _this2.speed;
  84. _this2.$emit('replay');
  85. });
  86. });
  87. },
  88. reset: function reset() {
  89. this.offset = 0;
  90. this.duration = 0;
  91. this.wrapWidth = 0;
  92. this.contentWidth = 0;
  93. },
  94. start: function start() {
  95. var _this3 = this;
  96. var delay = isDef(this.delay) ? this.delay * 1000 : 0;
  97. this.reset();
  98. clearTimeout(this.startTimer);
  99. this.startTimer = setTimeout(function () {
  100. var _this3$$refs = _this3.$refs,
  101. wrap = _this3$$refs.wrap,
  102. content = _this3$$refs.content;
  103. if (!wrap || !content || _this3.scrollable === false) {
  104. return;
  105. }
  106. var wrapWidth = wrap.getBoundingClientRect().width;
  107. var contentWidth = content.getBoundingClientRect().width;
  108. if (_this3.scrollable || contentWidth > wrapWidth) {
  109. doubleRaf(function () {
  110. _this3.offset = -contentWidth;
  111. _this3.duration = contentWidth / _this3.speed;
  112. _this3.wrapWidth = wrapWidth;
  113. _this3.contentWidth = contentWidth;
  114. });
  115. }
  116. }, delay);
  117. }
  118. },
  119. render: function render() {
  120. var _this4 = this;
  121. var h = arguments[0];
  122. var slots = this.slots,
  123. mode = this.mode,
  124. leftIcon = this.leftIcon,
  125. onClickIcon = this.onClickIcon;
  126. var barStyle = {
  127. color: this.color,
  128. background: this.background
  129. };
  130. var contentStyle = {
  131. transform: this.offset ? "translateX(" + this.offset + "px)" : '',
  132. transitionDuration: this.duration + 's'
  133. };
  134. function LeftIcon() {
  135. var slot = slots('left-icon');
  136. if (slot) {
  137. return slot;
  138. }
  139. if (leftIcon) {
  140. return h(Icon, {
  141. "class": bem('left-icon'),
  142. "attrs": {
  143. "name": leftIcon
  144. }
  145. });
  146. }
  147. }
  148. function RightIcon() {
  149. var slot = slots('right-icon');
  150. if (slot) {
  151. return slot;
  152. }
  153. var iconName;
  154. if (mode === 'closeable') {
  155. iconName = 'cross';
  156. } else if (mode === 'link') {
  157. iconName = 'arrow';
  158. }
  159. if (iconName) {
  160. return h(Icon, {
  161. "class": bem('right-icon'),
  162. "attrs": {
  163. "name": iconName
  164. },
  165. "on": {
  166. "click": onClickIcon
  167. }
  168. });
  169. }
  170. }
  171. return h("div", {
  172. "attrs": {
  173. "role": "alert"
  174. },
  175. "directives": [{
  176. name: "show",
  177. value: this.show
  178. }],
  179. "class": bem({
  180. wrapable: this.wrapable
  181. }),
  182. "style": barStyle,
  183. "on": {
  184. "click": function click(event) {
  185. _this4.$emit('click', event);
  186. }
  187. }
  188. }, [LeftIcon(), h("div", {
  189. "ref": "wrap",
  190. "class": bem('wrap'),
  191. "attrs": {
  192. "role": "marquee"
  193. }
  194. }, [h("div", {
  195. "ref": "content",
  196. "class": [bem('content'), {
  197. 'van-ellipsis': this.scrollable === false && !this.wrapable
  198. }],
  199. "style": contentStyle,
  200. "on": {
  201. "transitionend": this.onTransitionEnd
  202. }
  203. }, [this.slots() || this.text])]), RightIcon()]);
  204. }
  205. });