su-tabs.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. "use strict";
  2. const common_vendor = require("../../../common/vendor.js");
  3. const sheep_helper_index = require("../../helper/index.js");
  4. require("../../helper/test.js");
  5. require("../../helper/digit.js");
  6. const _sfc_main = {
  7. name: "su-tabs",
  8. data() {
  9. return {
  10. addStyle: sheep_helper_index.addStyle,
  11. addUnit: sheep_helper_index.addUnit,
  12. firstTime: true,
  13. scrollLeft: 0,
  14. scrollViewWidth: 0,
  15. lineOffsetLeft: 0,
  16. tabsRect: {
  17. left: 0
  18. },
  19. innerCurrent: 0,
  20. moving: false
  21. };
  22. },
  23. props: {
  24. // 滑块的移动过渡时间,单位ms
  25. duration: {
  26. type: Number,
  27. default: 300
  28. },
  29. // tabs标签数组
  30. list: {
  31. type: Array,
  32. default: []
  33. },
  34. // 滑块颜色
  35. lineColor: {
  36. type: String,
  37. default: ""
  38. },
  39. // 菜单选择中时的样式
  40. activeStyle: {
  41. type: [String, Object],
  42. default() {
  43. return {
  44. color: "#303133"
  45. };
  46. }
  47. },
  48. // 菜单非选中时的样式
  49. inactiveStyle: {
  50. type: [String, Object],
  51. default() {
  52. return {
  53. color: "#606266"
  54. };
  55. }
  56. },
  57. // 滑块长度
  58. lineWidth: {
  59. type: [String, Number],
  60. default: 20
  61. },
  62. // 滑块高度
  63. lineHeight: {
  64. type: [String, Number],
  65. default: 3
  66. },
  67. // 滑块背景显示大小,当滑块背景设置为图片时使用
  68. lineBgSize: {
  69. type: String,
  70. default: "cover"
  71. },
  72. // 菜单item的样式
  73. itemStyle: {
  74. type: [String, Object],
  75. default() {
  76. return {
  77. height: "44px"
  78. };
  79. }
  80. },
  81. // 菜单是否可滚动
  82. scrollable: {
  83. type: Boolean,
  84. default: true
  85. },
  86. // 当前选中标签的索引
  87. current: {
  88. type: [Number, String],
  89. default: 0
  90. },
  91. // 默认读取的键名
  92. keyName: {
  93. type: String,
  94. default: "name"
  95. }
  96. },
  97. watch: {
  98. current: {
  99. immediate: true,
  100. handler(newValue, oldValue) {
  101. if (newValue !== this.innerCurrent) {
  102. this.innerCurrent = newValue;
  103. this.$nextTick(() => {
  104. this.resize();
  105. });
  106. }
  107. }
  108. },
  109. // list变化时,重新渲染list各项信息
  110. list() {
  111. this.$nextTick(() => {
  112. this.resize();
  113. });
  114. }
  115. },
  116. computed: {
  117. textStyle() {
  118. return (index) => {
  119. const style = {};
  120. const customeStyle = index === this.innerCurrent ? sheep_helper_index.addStyle(this.activeStyle) : sheep_helper_index.addStyle(this.inactiveStyle);
  121. if (this.list[index].disabled) {
  122. style.color = "#c8c9cc";
  123. }
  124. return sheep_helper_index.deepMerge(customeStyle, style);
  125. };
  126. }
  127. },
  128. async mounted() {
  129. this.init();
  130. },
  131. methods: {
  132. $uGetRect(selector, all) {
  133. return new Promise((resolve) => {
  134. common_vendor.index.createSelectorQuery().in(this)[all ? "selectAll" : "select"](selector).boundingClientRect((rect) => {
  135. if (all && Array.isArray(rect) && rect.length) {
  136. resolve(rect);
  137. }
  138. if (!all && rect) {
  139. resolve(rect);
  140. }
  141. }).exec();
  142. });
  143. },
  144. setLineLeft() {
  145. const tabItem = this.list[this.innerCurrent];
  146. if (!tabItem) {
  147. return;
  148. }
  149. let lineOffsetLeft = this.list.slice(0, this.innerCurrent).reduce((total, curr) => total + curr.rect.width, 0);
  150. const lineWidth = sheep_helper_index.getPx(this.lineWidth);
  151. this.lineOffsetLeft = lineOffsetLeft + (tabItem.rect.width - lineWidth) / 2;
  152. if (this.firstTime) {
  153. setTimeout(() => {
  154. this.firstTime = false;
  155. }, 10);
  156. }
  157. },
  158. // nvue下设置滑块的位置
  159. animation(x, duration = 0) {
  160. },
  161. // 点击某一个标签
  162. clickHandler(item, index) {
  163. this.$emit("click", {
  164. ...item,
  165. index
  166. });
  167. if (item.disabled)
  168. return;
  169. this.innerCurrent = index;
  170. this.resize();
  171. this.$emit("change", {
  172. ...item,
  173. index
  174. });
  175. },
  176. init() {
  177. sheep_helper_index.sleep().then(() => {
  178. this.resize();
  179. });
  180. },
  181. setScrollLeft() {
  182. const tabRect = this.list[this.innerCurrent];
  183. const offsetLeft = this.list.slice(0, this.innerCurrent).reduce((total, curr) => {
  184. return total + curr.rect.width;
  185. }, 0);
  186. const windowWidth = sheep_helper_index.sys().windowWidth;
  187. let scrollLeft = offsetLeft - (this.tabsRect.width - tabRect.rect.width) / 2 - (windowWidth - this.tabsRect.right) / 2 + this.tabsRect.left / 2;
  188. scrollLeft = Math.min(scrollLeft, this.scrollViewWidth - this.tabsRect.width);
  189. this.scrollLeft = Math.max(0, scrollLeft);
  190. },
  191. // 获取所有标签的尺寸
  192. resize() {
  193. if (this.list.length === 0) {
  194. return;
  195. }
  196. Promise.all([this.getTabsRect(), this.getAllItemRect()]).then(
  197. ([tabsRect, itemRect = []]) => {
  198. this.tabsRect = tabsRect;
  199. this.scrollViewWidth = 0;
  200. itemRect.map((item, index) => {
  201. this.scrollViewWidth += item.width;
  202. this.list[index].rect = item;
  203. });
  204. this.setLineLeft();
  205. this.setScrollLeft();
  206. }
  207. );
  208. },
  209. // 获取导航菜单的尺寸
  210. getTabsRect() {
  211. return new Promise((resolve) => {
  212. this.queryRect("u-tabs__wrapper__scroll-view").then((size) => resolve(size));
  213. });
  214. },
  215. // 获取所有标签的尺寸
  216. getAllItemRect() {
  217. return new Promise((resolve) => {
  218. const promiseAllArr = this.list.map(
  219. (item, index) => this.queryRect(`u-tabs__wrapper__nav__item-${index}`, true)
  220. );
  221. Promise.all(promiseAllArr).then((sizes) => resolve(sizes));
  222. });
  223. },
  224. // 获取各个标签的尺寸
  225. queryRect(el, item) {
  226. return new Promise((resolve) => {
  227. this.$uGetRect(`.${el}`).then((size) => {
  228. resolve(size);
  229. });
  230. });
  231. }
  232. }
  233. };
  234. function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
  235. return {
  236. a: common_vendor.f($props.list, (item, index, i0) => {
  237. return {
  238. a: common_vendor.t(item[$props.keyName]),
  239. b: common_vendor.n(item.disabled && "u-tabs__wrapper__nav__item__text--disabled"),
  240. c: common_vendor.s($options.textStyle(index)),
  241. d: index,
  242. e: common_vendor.o(($event) => $options.clickHandler(item, index), index),
  243. f: `u-tabs__wrapper__nav__item-${index}`,
  244. g: common_vendor.n(`u-tabs__wrapper__nav__item-${index}`),
  245. h: common_vendor.n(item.disabled && "u-tabs__wrapper__nav__item--disabled")
  246. };
  247. }),
  248. b: common_vendor.s($data.addStyle($props.itemStyle)),
  249. c: common_vendor.s({
  250. flex: $props.scrollable ? "" : 1
  251. }),
  252. d: common_vendor.s({
  253. width: $data.addUnit($props.lineWidth),
  254. transform: `translate(${$data.lineOffsetLeft}px)`,
  255. transitionDuration: `${$data.firstTime ? 0 : $props.duration}ms`,
  256. height: $data.addUnit($props.lineHeight),
  257. background: $props.lineColor ? $props.lineColor : "var(--ui-BG-Main)",
  258. backgroundSize: $props.lineBgSize
  259. }),
  260. e: $props.scrollable,
  261. f: $data.scrollLeft
  262. };
  263. }
  264. const Component = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-035e7744"], ["__file", "/Users/RuHu.Xu/Desktop/mall-newfeifan-zx-app/sheep/ui/su-tabs/su-tabs.vue"]]);
  265. wx.createComponent(Component);