DynamicTabs_gz

一个简易tabs标签页,只需创建该类的实例,按需传入配置即可在页面上创建

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.gf.qytechs.cn/scripts/517538/1485921/DynamicTabs_gz.js

  1. // ==UserScript==
  2. // @name DynamicTabs_gz
  3. // @namespace http://tampermonkey.net/
  4. // @license Apache-2.0
  5. // @version 0.2
  6. // @author byhgz
  7. // @description 一个简易tabs标签页,只需创建该类的实例,按需传入配置即可在页面上创建
  8. // @noframes
  9. // ==/UserScript==
  10. /**
  11. *
  12. * 一个简易Tabs标签页,只需创建该类的实例,按需传入配置即可在页面上创建
  13. *
  14. * @author byhgz
  15. */
  16. class DynamicTabs_gz {
  17. #selector;
  18. #tabsConfig;
  19. #activeTabId;
  20. #options;
  21. #buttonContainerSelector = '[name="buttonContainer"]';
  22. #contentContainerSelector = '[name="contentContainer"]';
  23.  
  24. /**
  25. *
  26. * @param selector{string} css选择器
  27. * @param tabsConfig {Array} 选项卡配置,参数为数组,数组每个对象为一个选项卡和对应的选项卡内容
  28. * @param options {Object} 其他选项,可设置自定义样式和事件处理类名
  29. */
  30. constructor(selector, tabsConfig, options = {}) {
  31. this.#selector = selector; // 选项卡容器的选择器
  32. this.#tabsConfig = tabsConfig; // 选项卡配置数组
  33. this.#activeTabId = tabsConfig[0].id; // 默认激活的第一个选项卡ID
  34. this.#options = options; // 可选配置项,如自定义样式和事件处理函数
  35.  
  36. // 初始化选项卡
  37. this.#init();
  38. }
  39.  
  40. // 私有初始化方法
  41. #init() {
  42. // 获取选项卡容器元素
  43. const tabsContainer = document.querySelector(this.#selector);
  44.  
  45. if (!tabsContainer) {
  46. throw new Error(`No element found matching the selector: ${this.#selector}`);
  47. }
  48.  
  49. // 添加默认样式
  50. this.#addDefaultStyles();
  51.  
  52. // 创建选项卡按钮
  53. this.#createButtons(tabsContainer);
  54.  
  55. // 创建选项卡内容
  56. this.#createContents(tabsContainer);
  57. }
  58.  
  59. // 私有添加默认样式的方法
  60. #addDefaultStyles() {
  61. const defaultClasses = {
  62. tabButton: 'dynamic-tab-button',
  63. tabButtonActive: 'dynamic-tab-button-active',
  64. tabContent: 'dynamic-tab-content',
  65. tabContentActive: 'dynamic-tab-content-active'
  66. };
  67.  
  68. // 合并用户提供的类名
  69. const classes = {...defaultClasses, ...this.#options.classes};
  70.  
  71. // 获取用户提供的样式或默认样式
  72. const backgroundColor = this.#options.backgroundColor || '#ccc';
  73. const borderColor = this.#options.borderColor || '#ccc';
  74. const textColor = this.#options.textColor || 'black';
  75. const fontWeight = this.#options.fontWeight || 'normal';
  76. const activeBackgroundColor = this.#options.activeBackgroundColor || '#007BFF';
  77. const activeTextColor = this.#options.activeTextColor || 'white';
  78. const contentBorderColor = this.#options.contentBorderColor || '#ccc';
  79. const contentBackgroundColor = this.#options.contentBackgroundColor || '#f9f9f9';
  80.  
  81. const defaultStyle = `
  82. ${this.#selector}>${this.#buttonContainerSelector}>.${classes.tabButton} {
  83. padding: 10px 20px;
  84. margin: 5px;
  85. cursor: pointer;
  86. border: 1px solid ${borderColor};
  87. background-color: ${backgroundColor};
  88. color: ${textColor};
  89. font-weight: ${fontWeight};
  90. }
  91. ${this.#selector}>${this.#buttonContainerSelector}>.${classes.tabButton}.${classes.tabButtonActive} {
  92. background-color: ${activeBackgroundColor};
  93. color: ${activeTextColor};
  94. }
  95. ${this.#selector}>${this.#contentContainerSelector}>.${classes.tabContent} {
  96. margin-top: 5px;
  97. padding: 20px;
  98. border: 1px solid ${contentBorderColor};
  99. background-color: ${contentBackgroundColor};
  100. display: none;
  101. }
  102. ${this.#selector}>${this.#contentContainerSelector}>.${classes.tabContent}.${classes.tabContentActive} {
  103. display: block;
  104. }
  105. ${this.#selector} {
  106. display: flex;
  107. flex-direction: column;
  108. }
  109. ${this.#selector}[data-tab-position="bottom"] > ${this.#buttonContainerSelector} {
  110. order: 2;
  111. }
  112. ${this.#selector}[data-tab-position="bottom"] > ${this.#contentContainerSelector} {
  113. order: 1;
  114. }
  115. ${this.#selector}[data-tab-position="left"] > ${this.#buttonContainerSelector},
  116. ${this.#selector}[data-tab-position="right"] > ${this.#buttonContainerSelector} {
  117. flex-direction: column;
  118. width: 20%;
  119. }
  120. ${this.#selector}[data-tab-position="left"] > ${this.#contentContainerSelector},
  121. ${this.#selector}[data-tab-position="right"] > ${this.#contentContainerSelector} {
  122. width: 80%;
  123. }
  124. ${this.#selector}[data-tab-position="left"] {
  125. flex-direction: row;
  126. }
  127. ${this.#selector}[data-tab-position="right"] {
  128. flex-direction: row-reverse;
  129. }
  130. `;
  131.  
  132. // 如果提供了自定义样式,则覆盖默认样式
  133. const customStyle = this.#options.styles || '';
  134.  
  135. const style = document.createElement('style');
  136. style.innerHTML = defaultStyle + customStyle;
  137. document.head.appendChild(style);
  138. this.setTabPosition(this.#options.tabPosition || 'top');
  139. }
  140.  
  141. /**
  142. * 设置选项卡位置,可设置为 'top'、'bottom'、'left' 或 'right'
  143. * @param position {string} 选项卡位置
  144. */
  145. setTabPosition(position) {
  146. // 设置 tabPosition 属性
  147. const tabsContainer = document.querySelector(this.#selector);
  148. tabsContainer.setAttribute("data-tab-position", position);
  149. }
  150.  
  151.  
  152. // 私有创建选项卡按钮的方法
  153. #createButtons(tabsContainer) {
  154. const buttonContainer = document.createElement('div');
  155. // 添加name属性
  156. buttonContainer.setAttribute("name", "buttonContainer");
  157. const classes = this.#options.classes || {};
  158.  
  159. this.#tabsConfig.forEach(tab => {
  160. const button = document.createElement('button');
  161. button.className = `${classes.tabButton || 'dynamic-tab-button'}`;
  162. button.textContent = tab.title;
  163. button.setAttribute("data-tab-id", tab.id);
  164. button.setAttribute("data-tab-title", tab.title);
  165.  
  166. if (tab.id === this.#activeTabId) {
  167. button.classList.add(classes.tabButtonActive || 'dynamic-tab-button-active');
  168. }
  169. buttonContainer.appendChild(button);
  170. });
  171. tabsContainer.appendChild(buttonContainer);
  172.  
  173. const butS = document.querySelector(`${this.#selector}>${this.#buttonContainerSelector}`);
  174. butS.addEventListener('click', (event) => {
  175. if (event.target.tagName !== "BUTTON") return;
  176. const dataTabId = event.target.getAttribute("data-tab-id");
  177. if (dataTabId === null) return;
  178. this.activateTabId(dataTabId);
  179. // 调用自定义的点击事件处理函数(如果存在)
  180. if (this.#options.onTabClick) {
  181. const {id,title,content} = this.#tabsConfig.find(tab => tab.id === dataTabId);
  182. this.#options.onTabClick(id,title,content);
  183. }
  184. });
  185. }
  186.  
  187. // 私有创建选项卡内容的方法
  188. #createContents(tabsContainer) {
  189. const contentContainer = document.createElement('div');
  190. contentContainer.setAttribute("name", "contentContainer");
  191. const classes = this.#options.classes || {};
  192.  
  193. for (let tab of this.#tabsConfig) {
  194. // 创建一个div来包装选项卡外层
  195. const tabDiv = document.createElement('div');
  196. tabDiv.className = `${classes.tabContent || 'dynamic-tab-content'}`;
  197. tabDiv.setAttribute("data-tab-id", tab.id);
  198. tabDiv.setAttribute("data-tab-title", tab.title);
  199. // 创建一个div来包装选项卡内容
  200. const tabContentDiv = document.createElement('div');
  201. tabContentDiv.innerHTML = tab.content;
  202.  
  203. if (tab.id === this.#activeTabId) {
  204. tabDiv.classList.add(classes.tabContentActive || 'dynamic-tab-content-active');
  205. }
  206. tabDiv.appendChild(tabContentDiv);
  207. contentContainer.appendChild(tabDiv);
  208. }
  209.  
  210. tabsContainer.appendChild(contentContainer);
  211. }
  212.  
  213. /**
  214. * 激活指定的选项卡
  215. * @param toType {{type: string,value:string}} 匹配的方式和匹配的值
  216. */
  217. #activateTab(toType) {
  218. const classes = this.#options.classes || {};
  219. // 更新按钮状态
  220. const butCss = `${this.#selector}>${this.#buttonContainerSelector}>.${classes.tabButton || 'dynamic-tab-button'}`;
  221. const buttons = document.querySelectorAll(butCss);
  222. buttons.forEach(button => {
  223. let dataTabValue;
  224. if (toType.type === "id") {
  225. dataTabValue = button.getAttribute("data-tab-id");
  226. } else {
  227. dataTabValue = button.getAttribute("data-tab-title");
  228. }
  229. if (dataTabValue === toType.value) {
  230. button.classList.add(classes.tabButtonActive || 'dynamic-tab-button-active');
  231. } else {
  232. button.classList.remove(classes.tabButtonActive || 'dynamic-tab-button-active');
  233. }
  234. });
  235.  
  236. // 更新内容状态
  237. const contentCss = `${this.#selector}>${this.#contentContainerSelector}>.${classes.tabContent || 'dynamic-tab-content'}`;
  238. const contents = document.querySelectorAll(contentCss);
  239. contents.forEach(tabDiv => {
  240. let dataTabValue;
  241. if (toType.type === "id") {
  242. dataTabValue = tabDiv.getAttribute("data-tab-id");
  243. } else {
  244. dataTabValue = tabDiv.getAttribute("data-tab-title");
  245. }
  246. if (dataTabValue === toType.value) {
  247. tabDiv.classList.add(classes.tabContentActive || 'dynamic-tab-content-active');
  248. } else {
  249. tabDiv.classList.remove(classes.tabContentActive || 'dynamic-tab-content-active');
  250. }
  251. });
  252.  
  253. this.#activeTabId = toType.value;
  254. }
  255.  
  256. /**
  257. * 激活指定的选项卡,通过选项卡id
  258. * @param tabID {string}
  259. */
  260. activateTabId(tabID) {
  261. this.#activateTab({type: "id", value: tabID})
  262. }
  263.  
  264. /**
  265. * 激活指定的选项卡,通过选项卡标题
  266. * @param tabTitle {string}
  267. */
  268. activateTabTitle(tabTitle) {
  269. this.#activateTab({type: "title", value: tabTitle})
  270. }
  271. }

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址