index.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. var component_1 = require("../common/component");
  4. var touch_1 = require("../mixins/touch");
  5. var utils_1 = require("../common/utils");
  6. component_1.VantComponent({
  7. mixins: [touch_1.touch],
  8. classes: ['nav-class', 'tab-class', 'tab-active-class', 'line-class'],
  9. relation: {
  10. name: 'tab',
  11. type: 'descendant',
  12. linked: function (child) {
  13. this.child.push(child);
  14. this.updateTabs(this.data.tabs.concat(child.data));
  15. },
  16. unlinked: function (child) {
  17. var index = this.child.indexOf(child);
  18. var tabs = this.data.tabs;
  19. tabs.splice(index, 1);
  20. this.child.splice(index, 1);
  21. this.updateTabs(tabs);
  22. }
  23. },
  24. props: {
  25. color: String,
  26. sticky: Boolean,
  27. animated: Boolean,
  28. swipeable: Boolean,
  29. lineWidth: {
  30. type: Number,
  31. value: -1
  32. },
  33. lineHeight: {
  34. type: Number,
  35. value: -1
  36. },
  37. active: {
  38. type: Number,
  39. value: 0
  40. },
  41. type: {
  42. type: String,
  43. value: 'line'
  44. },
  45. border: {
  46. type: Boolean,
  47. value: true
  48. },
  49. duration: {
  50. type: Number,
  51. value: 0.3
  52. },
  53. zIndex: {
  54. type: Number,
  55. value: 1
  56. },
  57. swipeThreshold: {
  58. type: Number,
  59. value: 4
  60. },
  61. offsetTop: {
  62. type: Number,
  63. value: 0
  64. }
  65. },
  66. data: {
  67. tabs: [],
  68. lineStyle: '',
  69. scrollLeft: 0,
  70. scrollable: false,
  71. trackStyle: '',
  72. wrapStyle: '',
  73. position: ''
  74. },
  75. watch: {
  76. swipeThreshold: function () {
  77. this.set({
  78. scrollable: this.child.length > this.data.swipeThreshold
  79. });
  80. },
  81. color: 'setLine',
  82. lineWidth: 'setLine',
  83. lineHeight: 'setLine',
  84. active: 'setActiveTab',
  85. animated: 'setTrack',
  86. offsetTop: 'setWrapStyle'
  87. },
  88. beforeCreate: function () {
  89. this.child = [];
  90. },
  91. mounted: function () {
  92. var _this = this;
  93. this.setLine(true);
  94. this.setTrack();
  95. this.scrollIntoView();
  96. this.getRect('.van-tabs__wrap').then(function (rect) {
  97. _this.navHeight = rect.height;
  98. _this.observerContentScroll();
  99. });
  100. },
  101. destroyed: function () {
  102. // @ts-ignore
  103. this.createIntersectionObserver().disconnect();
  104. },
  105. methods: {
  106. updateTabs: function (tabs) {
  107. tabs = tabs || this.data.tabs;
  108. this.set({
  109. tabs: tabs,
  110. scrollable: tabs.length > this.data.swipeThreshold
  111. });
  112. this.setActiveTab();
  113. },
  114. trigger: function (eventName, index) {
  115. this.$emit(eventName, {
  116. index: index,
  117. title: this.data.tabs[index].title
  118. });
  119. },
  120. onTap: function (event) {
  121. var index = event.currentTarget.dataset.index;
  122. if (this.data.tabs[index].disabled) {
  123. this.trigger('disabled', index);
  124. }
  125. else {
  126. this.trigger('click', index);
  127. this.setActive(index);
  128. }
  129. },
  130. setActive: function (active) {
  131. if (active !== this.data.active) {
  132. this.trigger('change', active);
  133. this.set({ active: active });
  134. this.setActiveTab();
  135. }
  136. },
  137. setLine: function (skipTransition) {
  138. var _this = this;
  139. if (this.data.type !== 'line') {
  140. return;
  141. }
  142. var _a = this.data, color = _a.color, active = _a.active, duration = _a.duration, lineWidth = _a.lineWidth, lineHeight = _a.lineHeight;
  143. this.getRect('.van-tab', true).then(function (rects) {
  144. var rect = rects[active];
  145. var width = lineWidth !== -1 ? lineWidth : rect.width / 2;
  146. var height = lineHeight !== -1 ? "height: " + lineHeight + "px;" : '';
  147. var left = rects
  148. .slice(0, active)
  149. .reduce(function (prev, curr) { return prev + curr.width; }, 0);
  150. left += (rect.width - width) / 2;
  151. var transition = skipTransition
  152. ? ''
  153. : "transition-duration: " + duration + "s; -webkit-transition-duration: " + duration + "s;";
  154. _this.set({
  155. lineStyle: "\n " + height + "\n width: " + width + "px;\n background-color: " + color + ";\n -webkit-transform: translateX(" + left + "px);\n transform: translateX(" + left + "px);\n " + transition + "\n "
  156. });
  157. });
  158. },
  159. setTrack: function () {
  160. var _this = this;
  161. var _a = this.data, animated = _a.animated, active = _a.active, duration = _a.duration;
  162. if (!animated)
  163. return '';
  164. this.getRect('.van-tabs__content').then(function (rect) {
  165. var width = rect.width;
  166. _this.set({
  167. trackStyle: "\n width: " + width * _this.child.length + "px;\n left: " + -1 * active * width + "px;\n transition: left " + duration + "s;\n display: -webkit-box;\n display: flex;\n "
  168. });
  169. var props = { width: width, animated: animated };
  170. _this.child.forEach(function (item) {
  171. item.set(props);
  172. });
  173. });
  174. },
  175. setActiveTab: function () {
  176. var _this = this;
  177. this.child.forEach(function (item, index) {
  178. var data = {
  179. active: index === _this.data.active
  180. };
  181. if (data.active) {
  182. data.inited = true;
  183. }
  184. if (data.active !== item.data.active) {
  185. item.set(data);
  186. }
  187. });
  188. utils_1.nextTick(function () {
  189. _this.setLine();
  190. _this.setTrack();
  191. _this.scrollIntoView();
  192. });
  193. },
  194. // scroll active tab into view
  195. scrollIntoView: function () {
  196. var _this = this;
  197. var _a = this.data, active = _a.active, scrollable = _a.scrollable;
  198. if (!scrollable) {
  199. return;
  200. }
  201. Promise.all([
  202. this.getRect('.van-tab', true),
  203. this.getRect('.van-tabs__nav')
  204. ]).then(function (_a) {
  205. var tabRects = _a[0], navRect = _a[1];
  206. var tabRect = tabRects[active];
  207. var offsetLeft = tabRects
  208. .slice(0, active)
  209. .reduce(function (prev, curr) { return prev + curr.width; }, 0);
  210. _this.set({
  211. scrollLeft: offsetLeft - (navRect.width - tabRect.width) / 2
  212. });
  213. });
  214. },
  215. onTouchStart: function (event) {
  216. if (!this.data.swipeable)
  217. return;
  218. this.touchStart(event);
  219. },
  220. onTouchMove: function (event) {
  221. if (!this.data.swipeable)
  222. return;
  223. this.touchMove(event);
  224. },
  225. // watch swipe touch end
  226. onTouchEnd: function () {
  227. if (!this.data.swipeable)
  228. return;
  229. var _a = this.data, active = _a.active, tabs = _a.tabs;
  230. var _b = this, direction = _b.direction, deltaX = _b.deltaX, offsetX = _b.offsetX;
  231. var minSwipeDistance = 50;
  232. if (direction === 'horizontal' && offsetX >= minSwipeDistance) {
  233. if (deltaX > 0 && active !== 0) {
  234. this.setActive(active - 1);
  235. }
  236. else if (deltaX < 0 && active !== tabs.length - 1) {
  237. this.setActive(active + 1);
  238. }
  239. }
  240. },
  241. setWrapStyle: function () {
  242. var _a = this.data, offsetTop = _a.offsetTop, position = _a.position;
  243. var wrapStyle;
  244. switch (position) {
  245. case 'top':
  246. wrapStyle = "\n top: " + offsetTop + "px;\n position: fixed;\n ";
  247. break;
  248. case 'bottom':
  249. wrapStyle = "\n top: auto;\n bottom: 0;\n ";
  250. break;
  251. default:
  252. wrapStyle = '';
  253. }
  254. // cut down `set`
  255. if (wrapStyle === this.data.wrapStyle)
  256. return;
  257. this.set({ wrapStyle: wrapStyle });
  258. },
  259. observerContentScroll: function () {
  260. var _this = this;
  261. if (!this.data.sticky) {
  262. return;
  263. }
  264. var offsetTop = this.data.offsetTop;
  265. var windowHeight = wx.getSystemInfoSync().windowHeight;
  266. // @ts-ignore
  267. this.createIntersectionObserver().disconnect();
  268. // @ts-ignore
  269. this.createIntersectionObserver()
  270. .relativeToViewport({ top: -(this.navHeight + offsetTop) })
  271. .observe('.van-tabs', function (res) {
  272. var top = res.boundingClientRect.top;
  273. if (top > offsetTop) {
  274. return;
  275. }
  276. var position = res.intersectionRatio > 0 ? 'top' : 'bottom';
  277. _this.$emit('scroll', {
  278. scrollTop: top + offsetTop,
  279. isFixed: position === 'top'
  280. });
  281. _this.setPosition(position);
  282. });
  283. // @ts-ignore
  284. this.createIntersectionObserver()
  285. .relativeToViewport({ bottom: -(windowHeight - 1 - offsetTop) })
  286. .observe('.van-tabs', function (res) {
  287. var _a = res.boundingClientRect, top = _a.top, bottom = _a.bottom;
  288. if (bottom < _this.navHeight) {
  289. return;
  290. }
  291. var position = res.intersectionRatio > 0 ? 'top' : '';
  292. _this.$emit('scroll', {
  293. scrollTop: top + offsetTop,
  294. isFixed: position === 'top'
  295. });
  296. _this.setPosition(position);
  297. });
  298. },
  299. setPosition: function (position) {
  300. var _this = this;
  301. if (position !== this.data.position) {
  302. this.set({ position: position }).then(function () {
  303. _this.setWrapStyle();
  304. });
  305. }
  306. }
  307. }
  308. });