index.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  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.reset);
  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: 'reset',
  50. text: {
  51. handler: 'reset',
  52. immediate: true
  53. }
  54. },
  55. created: function created() {
  56. // https://github.com/vant-ui/vant/issues/8634
  57. if (this.vanPopup) {
  58. this.vanPopup.onReopen(this.reset);
  59. }
  60. },
  61. activated: function activated() {
  62. this.reset();
  63. },
  64. methods: {
  65. onClickIcon: function onClickIcon(event) {
  66. if (this.mode === 'closeable') {
  67. this.show = false;
  68. this.$emit('close', event);
  69. }
  70. },
  71. onTransitionEnd: function onTransitionEnd() {
  72. var _this = this;
  73. this.offset = this.wrapWidth;
  74. this.duration = 0; // wait for Vue to render offset
  75. // using nextTick won't work in iOS14
  76. raf(function () {
  77. // use double raf to ensure animation can start
  78. doubleRaf(function () {
  79. _this.offset = -_this.contentWidth;
  80. _this.duration = (_this.contentWidth + _this.wrapWidth) / _this.speed;
  81. _this.$emit('replay');
  82. });
  83. });
  84. },
  85. // not an exposed-api, but may used by some users
  86. start: function start() {
  87. this.reset();
  88. },
  89. // @exposed-api
  90. reset: function reset() {
  91. var _this2 = this;
  92. var delay = isDef(this.delay) ? this.delay * 1000 : 0;
  93. this.offset = 0;
  94. this.duration = 0;
  95. this.wrapWidth = 0;
  96. this.contentWidth = 0;
  97. clearTimeout(this.startTimer);
  98. this.startTimer = setTimeout(function () {
  99. var _this2$$refs = _this2.$refs,
  100. wrap = _this2$$refs.wrap,
  101. content = _this2$$refs.content;
  102. if (!wrap || !content || _this2.scrollable === false) {
  103. return;
  104. }
  105. var wrapWidth = wrap.getBoundingClientRect().width;
  106. var contentWidth = content.getBoundingClientRect().width;
  107. if (_this2.scrollable || contentWidth > wrapWidth) {
  108. doubleRaf(function () {
  109. _this2.offset = -contentWidth;
  110. _this2.duration = contentWidth / _this2.speed;
  111. _this2.wrapWidth = wrapWidth;
  112. _this2.contentWidth = contentWidth;
  113. });
  114. }
  115. }, delay);
  116. }
  117. },
  118. render: function render() {
  119. var _this3 = this;
  120. var h = arguments[0];
  121. var slots = this.slots,
  122. mode = this.mode,
  123. leftIcon = this.leftIcon,
  124. onClickIcon = this.onClickIcon;
  125. var barStyle = {
  126. color: this.color,
  127. background: this.background
  128. };
  129. var contentStyle = {
  130. transform: this.offset ? "translateX(" + this.offset + "px)" : '',
  131. transitionDuration: this.duration + 's'
  132. };
  133. function LeftIcon() {
  134. var slot = slots('left-icon');
  135. if (slot) {
  136. return slot;
  137. }
  138. if (leftIcon) {
  139. return h(Icon, {
  140. "class": bem('left-icon'),
  141. "attrs": {
  142. "name": leftIcon
  143. }
  144. });
  145. }
  146. }
  147. function RightIcon() {
  148. var slot = slots('right-icon');
  149. if (slot) {
  150. return slot;
  151. }
  152. var iconName;
  153. if (mode === 'closeable') {
  154. iconName = 'cross';
  155. } else if (mode === 'link') {
  156. iconName = 'arrow';
  157. }
  158. if (iconName) {
  159. return h(Icon, {
  160. "class": bem('right-icon'),
  161. "attrs": {
  162. "name": iconName
  163. },
  164. "on": {
  165. "click": onClickIcon
  166. }
  167. });
  168. }
  169. }
  170. return h("div", {
  171. "attrs": {
  172. "role": "alert"
  173. },
  174. "directives": [{
  175. name: "show",
  176. value: this.show
  177. }],
  178. "class": bem({
  179. wrapable: this.wrapable
  180. }),
  181. "style": barStyle,
  182. "on": {
  183. "click": function click(event) {
  184. _this3.$emit('click', event);
  185. }
  186. }
  187. }, [LeftIcon(), h("div", {
  188. "ref": "wrap",
  189. "class": bem('wrap'),
  190. "attrs": {
  191. "role": "marquee"
  192. }
  193. }, [h("div", {
  194. "ref": "content",
  195. "class": [bem('content'), {
  196. 'van-ellipsis': this.scrollable === false && !this.wrapable
  197. }],
  198. "style": contentStyle,
  199. "on": {
  200. "transitionend": this.onTransitionEnd
  201. }
  202. }, [this.slots() || this.text])]), RightIcon()]);
  203. }
  204. });