NumberInputWidget

数字输入框组件

当前为 2025-04-29 提交的版本,查看 最新版本

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.gf.qytechs.cn/scripts/534382/1580036/NumberInputWidget.js

  1. const createNumberInput = function () {
  2. // 创建宿主元素
  3. const container = document.createElement("div");
  4. container.id = "numberInputWidget";
  5. // 创建 shadowRoot
  6. const shadowRoot = container.attachShadow({ mode: "open" });
  7. shadowRoot.innerHTML = `<style>
  8. .number-input {
  9. display: inline-flex;
  10. border: 1px solid #dcdfe6;
  11. border-radius: 4px;
  12. overflow: hidden;
  13. }
  14.  
  15. .number-input__button {
  16. width: 32px;
  17. height: 32px;
  18. background: #f5f7fa;
  19. border: none;
  20. outline: none;
  21. cursor: pointer;
  22. position: relative;
  23. transition: background 0.3s;
  24. }
  25.  
  26. .number-input__button:hover {
  27. background: #e4e7ed;
  28. }
  29.  
  30. .number-input__button:disabled {
  31. cursor: not-allowed;
  32. color: #c0c4cc;
  33. background: #f5f7fa;
  34. }
  35.  
  36. .number-input__button::before {
  37. content: "";
  38. position: absolute;
  39. top: 50%;
  40. left: 50%;
  41. transform: translate(-50%, -50%);
  42. width: 10px;
  43. height: 2px;
  44. background: #606266;
  45. }
  46.  
  47. .number-input__button--plus::after {
  48. content: "";
  49. position: absolute;
  50. top: 50%;
  51. left: 50%;
  52. transform: translate(-50%, -50%);
  53. width: 2px;
  54. height: 10px;
  55. background: #606266;
  56. }
  57.  
  58. .number-input__input {
  59. width: 60px;
  60. height: 32px;
  61. border: none;
  62. border-left: 1px solid #dcdfe6;
  63. border-right: 1px solid #dcdfe6;
  64. text-align: center;
  65. outline: none;
  66. font-size: 14px;
  67. color: #606266;
  68. }
  69.  
  70. .number-input__input:focus {
  71. border-color: #409eff;
  72. }
  73.  
  74. .number-input__input:disabled {
  75. background: #f5f7fa;
  76. cursor: not-allowed;
  77. }
  78. </style>
  79. </head>
  80. <body>
  81. <div class="number-input" data-min="0" data-max="10" data-step="1" data-value="1">
  82. <button class="number-input__button number-input__button--minus" type="button"></button>
  83. <input type="text" class="number-input__input" value="1">
  84. <button class="number-input__button number-input__button--plus" type="button"></button>
  85. </div>`;
  86. class NumberInput {
  87. constructor(container) {
  88. this.container = container;
  89. this.input = container.querySelector(".number-input__input");
  90. this.min = parseFloat(container.dataset.min) || 1;
  91. this.max = parseFloat(container.dataset.max) || Infinity;
  92. this.step = parseFloat(container.dataset.step) || 1;
  93. this.value = parseFloat(GM_getValue("redirectInterval", 3)) || this.min;
  94.  
  95. this.init();
  96. }
  97.  
  98. init() {
  99. this.input.value = this.value;
  100. this.updateButtonState();
  101.  
  102. // 绑定事件
  103. this.container
  104. .querySelector(".number-input__button--minus")
  105. .addEventListener("click", () => this.changeValue(-this.step));
  106. this.container
  107. .querySelector(".number-input__button--plus")
  108. .addEventListener("click", () => this.changeValue(this.step));
  109. this.input.addEventListener("change", () => this.validateInput());
  110. this.input.addEventListener("keydown", (e) => this.handleKeydown(e));
  111. }
  112.  
  113. changeValue(delta) {
  114. const newValue = this.value + delta;
  115. this.value = Math.max(this.min, Math.min(this.max, newValue));
  116. this.input.value = Number.isInteger(this.value)
  117. ? this.value
  118. : this.value.toFixed(1);
  119. GM_setValue("redirectInterval", this.input.value);
  120. this.updateButtonState();
  121. }
  122.  
  123. validateInput() {
  124. let value = parseFloat(this.input.value);
  125. if (isNaN(value)) {
  126. value = this.min;
  127. }
  128. this.value = Math.max(this.min, Math.min(this.max, value));
  129. this.input.value = Number.isInteger(this.value)
  130. ? this.value
  131. : this.value.toFixed(1);
  132. GM_setValue("redirectInterval", this.input.value);
  133. this.updateButtonState();
  134. }
  135.  
  136. updateButtonState() {
  137. const minusBtn = this.container.querySelector(
  138. ".number-input__button--minus"
  139. );
  140. const plusBtn = this.container.querySelector(
  141. ".number-input__button--plus"
  142. );
  143.  
  144. minusBtn.disabled = this.value <= this.min;
  145. plusBtn.disabled = this.value >= this.max;
  146. }
  147.  
  148. handleKeydown(e) {
  149. if (e.key === "ArrowUp") {
  150. e.preventDefault();
  151. this.changeValue(this.step);
  152. } else if (e.key === "ArrowDown") {
  153. e.preventDefault();
  154. this.changeValue(-this.step);
  155. }
  156. }
  157. }
  158.  
  159. // 初始化所有数字输入框
  160. shadowRoot.querySelectorAll(".number-input").forEach((container) => {
  161. new NumberInput(container);
  162. });
  163. return container;
  164. };

QingJ © 2025

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