index.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. // components/tabs/index.js
  2. Component({
  3. externalClasses: ['l-class-header', 'l-class-active', 'l-class-inactive', 'l-class-line', 'l-class-tabimage',
  4. 'l-header-class', 'l-active-class', 'l-inactive-class', 'l-line-class', 'l-tabimage-class'
  5. ],
  6. relations: {
  7. '../tabpanel/index': {
  8. type: 'child',
  9. },
  10. linked() {
  11. // 每次有子节点被插入时执行,target是该节点实例对象,触发在该节点attached生命周期之后
  12. this.initTabs();
  13. }
  14. },
  15. options: {
  16. multipleSlots: true // 在组件定义时的选项中启用多slot支持
  17. },
  18. /**
  19. * 组件的属性列表
  20. */
  21. properties: {
  22. activeKey: {
  23. type: String,
  24. value: '',
  25. observer: 'changeCurrent'
  26. },
  27. placement: {
  28. type: String,
  29. value: 'top',
  30. },
  31. aminmated: Boolean,
  32. scrollable: Boolean,
  33. swipeable: {
  34. type: Boolean,
  35. value: true,
  36. },
  37. hasLine: {
  38. type: Boolean,
  39. value: true
  40. },
  41. activeColor: {
  42. type: String,
  43. value: '#333333'
  44. },
  45. inactiveColor: {
  46. type: String,
  47. value: '#bbbbbb'
  48. },
  49. },
  50. data: {
  51. tabList: [],
  52. currentIndex: 0,
  53. transformX: 0,
  54. transformY: 0,
  55. },
  56. ready() {
  57. this.initTabs();
  58. },
  59. /**
  60. * 组件的方法列表
  61. */
  62. methods: {
  63. initTabs() {
  64. this.initTabList();
  65. this.initActiveIndex();
  66. },
  67. initActiveIndex(val = this.data.activeKey) {
  68. let activeKey = val,
  69. currentIndex = this.data.currentIndex;
  70. this.data.tabList.forEach((item, index) => {
  71. activeKey = !val && index == 0 ? item.key : activeKey;
  72. currentIndex = item.key === activeKey ? index : currentIndex;
  73. });
  74. this.setData({
  75. activeKey,
  76. currentIndex,
  77. }, () => {
  78. if (this.data.scrollable) {
  79. this.queryMultipleNodes();
  80. }
  81. });
  82. },
  83. initTabList() {
  84. let items = this.getRelationNodes('../tabpanel/index');
  85. if (items.length > 0) {
  86. const tabList = [];
  87. items.forEach((item) => {
  88. const tabIndex = tabList.findIndex(tabItem => tabItem.tab === item.data.tab);
  89. let tab = {};
  90. if (tabIndex === -1) {
  91. tab = {
  92. tab: item.data.tab,
  93. key: item.data.key,
  94. icon: item.data.icon,
  95. iconStyle: item.data.iconStyle,
  96. image: item.data.image,
  97. subTabs: [],
  98. };
  99. tabList.push(tab);
  100. }
  101. const targetTab = tabIndex === -1 ? tab : tabList[tabIndex];
  102. if (item.data.subTab) {
  103. targetTab.subTabs = targetTab.subTabs || [];
  104. const subTabItem = {
  105. tab: item.data.subTab,
  106. key: item.data.subKey,
  107. };
  108. targetTab.subTabs.push(subTabItem);
  109. targetTab.activeSubKey = this.data.subActiveKey || targetTab.subTabs[0].key;
  110. targetTab.subCurrentIndex = 0;
  111. }
  112. });
  113. this.setData({
  114. tabList,
  115. });
  116. }
  117. },
  118. swiperChange(e) {
  119. const {
  120. source,
  121. current
  122. } = e.detail;
  123. if (source == 'touch') {
  124. const currentIndex = current;
  125. const activeKey = this.data.tabList[current].key;
  126. const subCurrentIndex = this.data.tabList[currentIndex].subCurrentIndex;
  127. const activeSubKey = this.data.tabList[currentIndex].activeSubKey;
  128. this._setChangeData({
  129. activeKey,
  130. currentIndex,
  131. subCurrentIndex,
  132. activeSubKey,
  133. });
  134. }
  135. },
  136. subSwiperChange(e) {
  137. const {
  138. source,
  139. current
  140. } = e.detail;
  141. if (source == 'touch') {
  142. const {
  143. currentIndex,
  144. activeKey
  145. } = this.data;
  146. const subCurrentIndex = current;
  147. const activeSubKey = this.data.tabList[currentIndex].subTabs[subCurrentIndex].key;
  148. const tabs = this.data.tabList[currentIndex];
  149. tabs.activeSubKey = activeSubKey;
  150. tabs.subCurrentIndex = subCurrentIndex;
  151. this.setData({
  152. [`tabList[${currentIndex}]`]: tabs
  153. });
  154. this._setChangeData({
  155. activeKey,
  156. currentIndex,
  157. activeSubKey,
  158. subCurrentIndex
  159. });
  160. }
  161. },
  162. handleChange(e) {
  163. const isSubHeader = e.currentTarget.dataset.headerType === 'subTab';
  164. const {
  165. currentIndex,
  166. activeKey
  167. } = this.data;
  168. const clickIndex = e.currentTarget.dataset.index;
  169. const subCurrentIndex = isSubHeader ? clickIndex : this.data.tabList[clickIndex].subCurrentIndex;
  170. const activeSubKey = isSubHeader ? this.data.tabList[currentIndex].subTabs[subCurrentIndex].key : this.data.tabList[clickIndex].activeSubKey;
  171. if (isSubHeader) {
  172. const tabs = this.data.tabList[currentIndex];
  173. tabs.activeSubKey = activeSubKey;
  174. tabs.subCurrentIndex = subCurrentIndex;
  175. this.setData({
  176. [`tabList[${currentIndex}]`]: tabs
  177. });
  178. this._setChangeData({
  179. activeKey,
  180. currentIndex,
  181. activeSubKey,
  182. subCurrentIndex
  183. });
  184. } else {
  185. const activeKey = e.currentTarget.dataset.key;
  186. this._setChangeData({
  187. activeKey,
  188. currentIndex: clickIndex,
  189. subCurrentIndex,
  190. activeSubKey
  191. });
  192. }
  193. },
  194. _setChangeData({
  195. activeKey,
  196. currentIndex,
  197. activeSubKey = '',
  198. subCurrentIndex = null,
  199. }) {
  200. this.setData({
  201. activeKey,
  202. currentIndex
  203. }, () => {
  204. if (this.data.scrollable) {
  205. this.queryMultipleNodes();
  206. }
  207. });
  208. this.triggerEvent('linchange', {
  209. activeKey,
  210. currentIndex,
  211. activeSubKey,
  212. subCurrentIndex,
  213. });
  214. },
  215. queryMultipleNodes() {
  216. const {
  217. placement,
  218. activeKey,
  219. tabList
  220. } = this.data;
  221. this._getRect('#' + activeKey)
  222. .then((res) => {
  223. if (['top', 'bottom'].indexOf(placement) !== -1) {
  224. this.setData({
  225. transformX: res.left - tabList.length / 2 * res.width,
  226. transformY: 0
  227. });
  228. } else {
  229. this._getRect('.l-tabs-header')
  230. .then((navRect) => {
  231. const transformY = res.top - navRect.top - navRect.height / 2;
  232. this.setData({
  233. transformX: 0,
  234. transformY: transformY
  235. });
  236. });
  237. }
  238. });
  239. },
  240. _getRect(selector) {
  241. return new Promise((resolve, reject) => {
  242. const query = wx.createSelectorQuery().in(this);
  243. query.select(selector).boundingClientRect((res) => {
  244. if (!res) return reject('找不到元素');
  245. resolve(res);
  246. }).exec();
  247. });
  248. }
  249. }
  250. });