Develop scale components based on uni-app

? ? ? Why is the uploaded image so wide? After the width attribute in the img tag set is published, it is still full of widescreen. Please help

I. Introduction

The editor recently received a task, which is to no longer use the traditional keyboard when inputting values, but to select values ​​by dragging a ruler, which looks like this:

In fact, this requirement is not the first time that the product wants to do this in the first version of our application.
Of course, when I first received this task, I refused. You can't let me do it, so I will do it right away. First, I have to do some research, because I don't want to spend so much time and cost to develop this component and add some more. stunt up,

If you slide past the edge, the duang can bounce back, but it is not as convenient to use the keyboard to input numbers directly, so the leader will definitely scold me; after some research and time evaluation, I finally chose another set of solutions:

I wrote a set of numeric keyboards by myself, which is much simpler than the scale, and does not consume much performance. It is quite convenient to use.

Why not use the system's own keyboard? Needless to say, everyone knows how disgusting the mobile browser calls the system's own keyboard.
However, the app ushered in a second version, and the product took out the scale again and threatened: "If you want to cut demand, cut me first!".

However, it is true that the second version has a more complex scene. The selected value needs to be limited in the range, and the range will change with some conditions. If users can input the correct value intuitively and quickly, only the scale can be used. .

After two minutes of deliberation, I finally took over the task.

2. Development

First, let's take a look at the characteristics of the scale.

  1. can slide;
  2. Output the value according to the sliding distance;
  3. Slide over the head will automatically rebound;

It seems that we can develop based on the scroll-view component provided by uni-app, which provides the following properties just right for our scale feature:

property name Types of Defaults illustrate
scroll-x Boolean false Allow horizontal scrolling
scroll-left Number/String Set the horizontal scroll bar position
scroll-with-animation Boolean false Use animated transitions when setting scrollbar position
@scroll EventHandle 滚动时触发,event.detail = {scrollLeft, scrollTop, scrollHeight, scrollWidth, deltaX, deltaY}

然后第二步,需要计算刻度。
小编先设置好了默认每个刻度占10像素;

const GUTTER = 10;
复制代码

然后就开始计算我们一共需要多少个刻度,其实很简单,就是你需要多少刻度,就传进来一个最大最小值,然后用最大值减去最小值,就是刻度的数量了;

这时候会出现一个交互问题,因为刻度尺的选择标是放在屏幕中间的,所以刻度尺的边界是需要显示多余的刻度用来充满屏幕,于是小编就决定生成相当于两倍于屏幕宽度的多余刻度;

// 多余的刻度数量
const extraGridCount = Math.ceil(window.innerWidth / GUTTER);
// 生成刻度数组
this.gridList = Array.from(Array(this.gridMax - this.gridMin + extraGridCount * 2)).map((_, i) => {
      const num = i + this.gridMin - extraGridCount;
      const displayNum = this.decimal === 1 ? num / 10 : num;
      return {
        num,
        displayNum,
        isLongGrid: num % GUTTER === 0,
        showText: num % GUTTER === 0 && num >= this.gridMin && num <= this.gridMax
      }
});
复制代码

刻度数组内每个元素就是一个刻度对象,包含了以下属性:

  1. 刻度数值
  2. 刻度显示的数值(显示的数值可能会与实际数值不一致,是为了扩展小数用的)
  3. 是否是长刻度(因为刻度尺每隔10个就会出现一条长刻度)
  4. 是否显示刻度的数值(只有长刻度和有效刻度才会显示数值)

数组生成好,就可以根据数组来渲染整个刻度尺了;

 <u-row v-if="show" class="grid-wrapper" align="top">
    <view
        class="grid-item"
        :class="{'long': item.isLongGrid}"
        v-for="(item, i) in gridList"
        :key="i"
        :style="item.showText ? { ...gridItemStyle, height: '40px' } : gridItemStyle"
    >
      <text
          class="grid-num"
          v-if="item.showText"
      >{{item.displayNum}}</text>
    </view>
  </u-row>
复制代码

渲染完毕之后,就可以通过一些算法计算刻度尺的初始位置了。然后通过scroll事件,在刻度尺滑动过程中计算数值;

scroll(e){
  const scrollLeft = e.detail.scrollLeft;
  let value = Math.floor((scrollLeft - this.offsetScroll + this.gridMin * GUTTER) / GUTTER);
  if(value < this.gridMin){
    value = this.gridMin;
  }else if(value > this.gridMax){
    value = this.gridMax;
  }}
复制代码

其中offsetScroll 就是多余的那部分刻度,需要减掉的,还要判断一下是否小于最小值或者是否大于最大值; 接下来就是刻度尺的回弹了,当滑动超过最大值或最小值时,需要往回弹,在视觉上与计算好的数值保持一致; 其实也只是在滑动结束时算一下刻度尺是否应该回到边界就好了,动画上scroll-view已经帮我们解决好了;

adjustScrollPosition(){
    /** 滚动结束后调节滚动位置 */
    if(this.actualScrollLeft < this.offsetScroll){
        this.scrollLeft = this.offsetScroll + (Math.random() / 100);
    } else if(this.actualScrollLeft > (this.gridMax - this.gridMin) * GUTTER + this.offsetScroll){
        this.scrollLeft = (this.gridMax - this.gridMin) * GUTTER + 
        this.offsetScroll + (Math.random() / 100);
    } else if(Math.floor(this.actualScrollLeft - this.offsetScroll) % GUTTER !== 0){
        const dryScrollLeft = this.actualScrollLeft - this.offsetScroll;
        this.scrollLeft = dryScrollLeft - dryScrollLeft % GUTTER + this.offsetScroll;
    }
}
复制代码

至此,一个刻度尺组件就大致完成了。当然,还有很多细节问题没解决,比如:

  1. 要是需要支持小数位怎么办呢;
  2. 如果刻度过多是否有性能问题呢;
  3. 等等...

这些问题就由大家思考完善一下吧,嘻嘻!

Guess you like

Origin juejin.im/post/7079464646222512136