fs-number-box.vue 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. <template>
  2. <view class="fs-number-box" :class="{ 'fs-number-box-round': round }">
  3. <view class="fs-number-box-item fs-number-box-left" @click="minus">
  4. <fs-icon type="icon-minus" size="32rpx" :color="minusDisabled ? '#c8c9cc' : ''"></fs-icon>
  5. </view>
  6. <input
  7. class="fs-number-box-item fs-number-box-middle"
  8. type="number"
  9. :value="modelValue"
  10. @blur="handleChange"
  11. :disabled="disableInput"
  12. />
  13. <view class="fs-number-box-item fs-number-box-right" @click="add">
  14. <fs-icon type="icon-plus" size="32rpx" :color="addDisabled ? '#c8c9cc' : ''"></fs-icon>
  15. </view>
  16. </view>
  17. </template>
  18. <script>
  19. /**
  20. * 步进器组件
  21. * @description 步进器组件
  22. * @property {Number} min 最小值
  23. * @property {Number} max 最大值
  24. * @property {Number} step 步幅
  25. * @property {Boolean} round 是否圆角
  26. * @property {Boolean} disableInput 禁止输入框输入
  27. */
  28. export default {
  29. name: 'fs-number-box'
  30. }
  31. </script>
  32. <script setup>
  33. import { ref, watch, computed } from 'vue'
  34. const props = defineProps({
  35. modelValue: {
  36. type: Number,
  37. default: 1
  38. },
  39. min: {
  40. type: Number,
  41. default: 1
  42. },
  43. max: {
  44. type: Number,
  45. default: Number.MAX_SAFE_INTEGER
  46. },
  47. step: {
  48. type: Number,
  49. default: 1
  50. },
  51. round: Boolean,
  52. disableInput: Boolean
  53. })
  54. const emits = defineEmits(['update:modelValue', 'change'])
  55. let initValue = ref(props.modelValue)
  56. watch(
  57. () => props.modelValue,
  58. val => {
  59. initValue.value = val
  60. }
  61. )
  62. watch(initValue, val => {
  63. emits('update:modelValue', val)
  64. emits('change', val)
  65. })
  66. const add = () => {
  67. initValue.value += Number(props.step)
  68. if (initValue.value > props.max) {
  69. initValue.value = props.max
  70. }
  71. }
  72. const minus = () => {
  73. initValue.value -= Number(props.step)
  74. if (initValue.value < props.min) {
  75. initValue.value = props.min
  76. }
  77. }
  78. const handleChange = e => {
  79. initValue.value = Number(e.detail.value) || props.min
  80. if (initValue.value < props.min) {
  81. initValue.value = props.min
  82. } else if (initValue.value > props.max) {
  83. initValue.value = props.max
  84. }
  85. }
  86. const minusDisabled = computed(() => initValue.value === props.min)
  87. const addDisabled = computed(() => initValue.value === props.max)
  88. </script>
  89. <style lang="scss" scoped>
  90. .fs-number-box {
  91. display: inline-flex;
  92. border: 2rpx solid var(--border-color);
  93. height: 60rpx;
  94. background-color: #fff;
  95. &-round {
  96. border-radius: 30rpx;
  97. }
  98. &-item {
  99. display: flex;
  100. height: 100%;
  101. justify-content: center;
  102. align-items: center;
  103. }
  104. &-left,
  105. &-right {
  106. width: 60rpx;
  107. }
  108. &-middle {
  109. box-sizing: border-box;
  110. width: 80rpx;
  111. border-left: 2rpx solid var(--border-color);
  112. border-right: 2rpx solid var(--border-color);
  113. padding: 10rpx;
  114. text-align: center;
  115. }
  116. }
  117. </style>