vertical-rule.vue 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. <template>
  2. <view>
  3. <view class="flex justify-start align-items">
  4. <!-- <scroll-view :scroll-y="true" :scroll-with-animation="true" :scroll-top="scrollTop" :show-scrollbar="false"
  5. :style="{height: height + 'px'}" @scroll="scroll" style="width: auto;"> -->
  6. <scroll-view :scroll-with-animation="true" :scroll-top="scrollTop" :show-scrollbar="false"
  7. :style="{height: '96vh'}" @scroll="scroll" style="width: auto;">
  8. <view class="flex" >
  9. <!-- :style="{paddingTop: height/2 + 'px', paddingBottom: height/2 - lineWidth + 'px'}" -->
  10. <!-- 数值 -->
  11. <view>
  12. <!-- :class="index%2==0 ? 'bg-red' : 'bg-blue'" -->
  13. <view v-for="(item,index) in options" :key="index" :style="{height: 4.95 +'px'}"
  14. style="width: 20px;position: relative;">
  15. <view style="margin-top: 0rpx;position: absolute;font-size: 24rpx;" :class="selectIndex == index ? 'line-label' : ''">{{item.val}}</view>
  16. </view>
  17. </view>
  18. <!-- 刻度线 -->
  19. <view class="line" style="border-right: 2px solid #000;">
  20. <view v-for="(item,index) in options" :key="index" :style="{height: lineWidth - 1 + 'px'}"
  21. :class="item.type">
  22. </view>
  23. </view>
  24. </view>
  25. </scroll-view>
  26. <!-- 标记 -->
  27. <!-- <view class="flex align-items mark">
  28. <view class="markLine"></view>
  29. <view class="triangl-left"></view>
  30. </view> -->
  31. </view>
  32. </view>
  33. </template>
  34. <script>
  35. import debounce from './debounce.js'
  36. export default {
  37. name: "vertical-rule",
  38. props: {
  39. height: {
  40. type: Number,
  41. default: 200
  42. },
  43. min: { // 最小值
  44. type: Number,
  45. default: 0,
  46. validator: function(val) {
  47. return parseFloat(val) >= 0
  48. }
  49. },
  50. max: { // 最大值
  51. type: Number,
  52. default: 150,
  53. validator: function(val) {
  54. return parseFloat(val) >= 0
  55. }
  56. },
  57. value: { // 初始值
  58. type: Number,
  59. default: 50,
  60. validator: function(val) {
  61. return parseFloat(val) >= 0
  62. }
  63. },
  64. multiple: { // 倍数 只支持10的倍数; multiple = 1 表示每个刻度的值等于1;multiple = 10 表示每个刻度的值等于0.1
  65. type: [Number],
  66. default: 10
  67. },
  68. lineWidth: { // 每个刻度之间的宽度
  69. type: Number,
  70. default: 6,
  71. validator: function(val) {
  72. return parseFloat(val) >= 0
  73. }
  74. }
  75. },
  76. data() {
  77. return {
  78. options: [], // 刻度线
  79. selectIndex: -1,
  80. scrollTop: 0, //初始位置
  81. currentVal: '0', // 当前值
  82. totalHeight: 0,
  83. };
  84. },
  85. mounted() {
  86. this.init()
  87. },
  88. methods: {
  89. // 初始化刻度尺
  90. init: function() {
  91. // 最大值不能小于最小值
  92. if (this.min >= this.max) return
  93. this.options = []
  94. let index = this.min
  95. let length = this.max * this.multiple
  96. for (let i = this.min * this.multiple; i <= length; i++) {
  97. let type = ''
  98. if (i % 5 == 0) {
  99. type = 'line-md'
  100. if (i % 10 == 0) {
  101. type = 'line-lg'
  102. }
  103. } else {
  104. type = 'line-sm'
  105. }
  106. // 每 10 格 显示一个刻度值
  107. let val = ''
  108. if (i % 10 == 0) {
  109. val = i / this.multiple
  110. }
  111. this.options.push({
  112. type: type,
  113. val: val
  114. })
  115. }
  116. // 总高度 = 总格子 * 每个格子的高度
  117. this.totalHeight = ((this.max - this.min) * this.multiple) * this.lineWidth
  118. console.log('总高度 = 总格子 * 每个格子的高度', this.totalHeight)
  119. // 初始位置
  120. setTimeout(() => {
  121. // 初始值必须在min 与 max 之间
  122. if (this.value < this.min) {
  123. this.scrollTop = 0
  124. } else if (this.value > this.max) {
  125. this.scrollTop = this.heigh
  126. } else {
  127. this.scrollTop = (this.value - this.min) * this.multiple * this.lineWidth
  128. }
  129. this.currentVal = this.value
  130. this.selectIndex = this.options.findIndex((item, index) => this.value == item.val)
  131. this.$emit('change', this.currentVal)
  132. }, 40)
  133. },
  134. scroll: function(e) {
  135. var result = ((this.max - this.min) / this.totalHeight * e.detail.scrollTop) + this.min
  136. this.currentVal = result
  137. this.$emit('change', this.currentVal)
  138. // 处理滑在两个刻度之间,自动靠近最近一个刻度
  139. debounce(() => {
  140. var num = Math.round(result * this.multiple)/this.multiple
  141. this.scrollTop = (num - this.min) * this.multiple * this.lineWidth
  142. this.selectIndex = this.options.findIndex((item, index) => num == item.val)
  143. }, 500)
  144. }
  145. }
  146. }
  147. </script>
  148. <style>
  149. .flex {
  150. display: flex;
  151. }
  152. .justify-start {
  153. justify-content: flex-start;
  154. }
  155. .align-items {
  156. align-items: center;
  157. }
  158. .mark {
  159. z-index: 100;
  160. margin-left: -30px;
  161. }
  162. .markLine {
  163. width: 23px;
  164. height: 2px;
  165. background: #3F86FF;
  166. }
  167. .triangl-left {
  168. width: 0;
  169. height: 0;
  170. border-right: 12px solid #3F86FF;
  171. border-top: 6px solid transparent;
  172. border-bottom: 6px solid transparent;
  173. border-radius: 2px;
  174. margin-left: -5px;
  175. }
  176. .bg-red {
  177. background: red;
  178. }
  179. .bg-blue {
  180. background: blue;
  181. }
  182. .line {
  183. display: flex;
  184. flex-direction: column;
  185. align-items: flex-end;
  186. }
  187. .line-lg {
  188. width: 50px;
  189. border-top: 2px solid #000;
  190. }
  191. .line-md {
  192. width: 40px;
  193. border-top: 2px solid #000;
  194. }
  195. .line-sm {
  196. width: 20px;
  197. border-top: 2px solid #000;
  198. }
  199. .line-label {
  200. /* color: #3F86FF; */
  201. }
  202. </style>