tabs.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
  2. var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
  3. if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
  4. else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
  5. return c > 3 && r && Object.defineProperty(target, key, r), r;
  6. };
  7. import dom from '../behaviors/dom';
  8. import touch from '../behaviors/touch';
  9. import { SuperComponent, wxComponent } from '../common/src/index';
  10. import props from './props';
  11. import config from '../common/config';
  12. const { prefix } = config;
  13. const name = `${prefix}-tabs`;
  14. var Position;
  15. (function (Position) {
  16. Position["top"] = "top";
  17. Position["right"] = "right";
  18. Position["bottom"] = "bottom";
  19. Position["left"] = "left";
  20. })(Position || (Position = {}));
  21. const trackLineWidth = 30;
  22. let Tabs = class Tabs extends SuperComponent {
  23. constructor() {
  24. super(...arguments);
  25. this.behaviors = [dom, touch];
  26. this.externalClasses = [`${prefix}-class`, `${prefix}-class-item`, `${prefix}-class-active`, `${prefix}-class-track`];
  27. this.relations = {
  28. './tab-panel': {
  29. type: 'descendant',
  30. linked(target) {
  31. this.children.push(target);
  32. target.index = this.children.length - 1;
  33. this.updateTabs();
  34. },
  35. unlinked(target) {
  36. this.children = this.children.filter((item) => item.index !== target.index);
  37. this.updateTabs(() => this.setTrack());
  38. },
  39. },
  40. };
  41. this.properties = props;
  42. this.controlledProps = [
  43. {
  44. key: 'value',
  45. event: 'change',
  46. },
  47. ];
  48. this.observers = {
  49. value(name) {
  50. if (name !== this.getCurrentName()) {
  51. this.setCurrentIndexByName(name);
  52. }
  53. },
  54. animation(v) {
  55. this.setData({ animate: v });
  56. },
  57. placement() {
  58. this.adjustPlacement();
  59. },
  60. };
  61. this.data = {
  62. prefix,
  63. classPrefix: name,
  64. tabs: [],
  65. currentIndex: -1,
  66. trackStyle: '',
  67. isScrollX: true,
  68. isScrollY: false,
  69. direction: 'X',
  70. animate: { duration: 0 },
  71. offset: 0,
  72. };
  73. this.methods = {
  74. adjustPlacement() {
  75. const { placement } = this.properties;
  76. let isScrollX = false;
  77. let isScrollY = false;
  78. if (placement === Position.top || placement === Position.bottom) {
  79. isScrollX = true;
  80. }
  81. else {
  82. isScrollY = true;
  83. }
  84. this.setData({
  85. isScrollX,
  86. isScrollY,
  87. direction: isScrollX ? 'X' : 'Y',
  88. });
  89. },
  90. };
  91. }
  92. created() {
  93. this.children = this.children || [];
  94. }
  95. attached() {
  96. wx.nextTick(() => {
  97. this.setTrack();
  98. });
  99. this.adjustPlacement();
  100. this.gettingBoundingClientRect(`.${name}`, true).then((res) => {
  101. this.containerWidth = res[0].width;
  102. });
  103. }
  104. updateTabs(cb) {
  105. const { children } = this;
  106. this.setData({
  107. tabs: children.map((child) => child.data),
  108. }, cb);
  109. this.setCurrentIndexByName(this.properties.value);
  110. }
  111. setCurrentIndexByName(name) {
  112. const { children } = this;
  113. const index = children.findIndex((child) => child.getComputedName() === `${name}`);
  114. if (index > -1) {
  115. this.setCurrentIndex(index);
  116. }
  117. }
  118. setCurrentIndex(index) {
  119. if (index <= -1 || index >= this.children.length)
  120. return;
  121. this.children.forEach((child, idx) => {
  122. const isActive = index === idx;
  123. if (isActive !== child.data.active) {
  124. child.render(isActive, this);
  125. }
  126. });
  127. if (this.data.currentIndex === index)
  128. return;
  129. this.setData({
  130. currentIndex: index,
  131. });
  132. this.setTrack();
  133. }
  134. getCurrentName() {
  135. if (this.children) {
  136. const activeTab = this.children[this.data.currentIndex];
  137. if (activeTab) {
  138. return activeTab.getComputedName();
  139. }
  140. }
  141. }
  142. calcScrollOffset(containerWidth, targetLeft, targetWidth, offset, currentIndex) {
  143. return currentIndex * targetWidth - (1 / 2) * containerWidth + targetWidth / 2;
  144. }
  145. setTrack() {
  146. if (!this.properties.showBottomLine)
  147. return;
  148. const { children } = this;
  149. if (!children)
  150. return;
  151. const { currentIndex, isScrollX, direction } = this.data;
  152. if (currentIndex <= -1)
  153. return;
  154. this.gettingBoundingClientRect(`.${prefix}-tabs__item`, true)
  155. .then((res) => {
  156. const rect = res[currentIndex];
  157. if (!rect)
  158. return;
  159. let count = 0;
  160. let distance = 0;
  161. for (const item of res) {
  162. if (count < currentIndex) {
  163. distance += isScrollX ? item.width : item.height;
  164. count += 1;
  165. }
  166. }
  167. if (this.containerWidth) {
  168. const offset = this.calcScrollOffset(this.containerWidth, rect.left, rect.width, this.data.offset, currentIndex);
  169. this.setData({
  170. offset,
  171. });
  172. }
  173. if (isScrollX) {
  174. distance += (rect.width - trackLineWidth) / 2;
  175. }
  176. let trackStyle = `-webkit-transform: translate${direction}(${distance}px);
  177. transform: translate${direction}(${distance}px);
  178. `;
  179. trackStyle += isScrollX ? `width: ${trackLineWidth}px;` : `height: ${rect.height}px;`;
  180. this.setData({
  181. trackStyle,
  182. });
  183. })
  184. .catch((err) => {
  185. this.triggerEvent('error', err);
  186. });
  187. }
  188. onTabTap(event) {
  189. const { index } = event.currentTarget.dataset;
  190. this.changeIndex(index);
  191. }
  192. onTouchStart(event) {
  193. if (!this.properties.swipeable)
  194. return;
  195. this.touchStart(event);
  196. }
  197. onTouchMove(event) {
  198. if (!this.properties.swipeable)
  199. return;
  200. this.touchMove(event);
  201. }
  202. onTouchEnd() {
  203. if (!this.properties.swipeable)
  204. return;
  205. const { direction, deltaX, offsetX } = this;
  206. const minSwipeDistance = 50;
  207. if (direction === 'horizontal' && offsetX >= minSwipeDistance) {
  208. const index = this.getAvailableTabIndex(deltaX);
  209. if (index !== -1) {
  210. this.changeIndex(index);
  211. }
  212. }
  213. }
  214. onTouchScroll(event) {
  215. this._trigger('scroll', event.detail);
  216. }
  217. changeIndex(index) {
  218. const currentTab = this.data.tabs[index];
  219. const { value, label } = currentTab;
  220. if (!(currentTab === null || currentTab === void 0 ? void 0 : currentTab.disabled) && index !== this.data.currentIndex) {
  221. this._trigger('change', { value, label });
  222. }
  223. this._trigger('click', { value, label });
  224. }
  225. getAvailableTabIndex(deltaX) {
  226. const step = deltaX > 0 ? -1 : 1;
  227. const { currentIndex, tabs } = this.data;
  228. const len = tabs.length;
  229. for (let i = step; currentIndex + step >= 0 && currentIndex + step < len; i += step) {
  230. const newIndex = currentIndex + i;
  231. if (newIndex >= 0 && newIndex < len && tabs[newIndex] && !tabs[newIndex].disabled) {
  232. return newIndex;
  233. }
  234. }
  235. return -1;
  236. }
  237. };
  238. Tabs = __decorate([
  239. wxComponent()
  240. ], Tabs);
  241. export default Tabs;