学习移动端组件 Picker一下

栏目: CSS · 发布时间: 5年前

内容简介:原文:一个移动端的touch 事件或者 mouse 事件,具体看看怎么玩。先看看效果:

原文: https://www.luoyangfu.com/art...

前言

一个移动端的touch 事件或者 mouse 事件,具体看看怎么玩。

先看看效果:

学习移动端组件 Picker一下

这里年月日都是使用创建好的Picker组件来实现的,在之前感谢博客园 @糊糊糊糊糊了 , 原文地址 .

原文中讲了实现Picker核心思路,我也是受益颇多,然后根据思路以及 Github源码 ,终于写了自己想要的Picker,于是就有了记录,再次感谢.

单独Picker

HTML 结构

开发这个Picker, 观察Picker节点结构,Picker 是由定高隐藏元素的块, 一个定高不隐藏元素的的块,以及一个选择列表组成这三个部分。我们得知了这个Picker组成后很容易就可以写出来下面HTML的结构:

<div class="picker">
    <div class="picker-wrapper" id="wrapper">
        <div>2016</div>
        <div>2017</div>
        <div>2018</div>
        <div>2019</div>
        <div>2020</div>
    </div>
    <div class="center-highlight"></div>
</div>

这个就是最简单的 picker 结构了。

CSS 样式

咱们给这块结构添加样式,显示如下, 在这里我们默认元素的高度在css 中写死为 50px .

学习移动端组件 Picker一下

我们这里就写了关于 Picker 基础样式。

.picker {
  overflow: hidden;
  position: relative;
  z-index: 1;
}

.picker-wrapper {
  overflow: visible;
  height: calc(50px * 3);
}

.picker-item {
  height: 50px;
  line-height: 50px;
  text-align: center;
  color: #999;
}

.picker-item.active {
  color: #000;
}

.picker-center-highlight {
  height: 50px;
  position: absolute;
  width: 100%;
  top: 50%;
  margin-top: -25px;
  z-index: 2;
}

.picker-center-highlight::before, .picker-center-highlight::after {
  content: '';
  display: block;
  height: 2px;
  background-color: #000;
  width: 100%;
  transform: scaleY(0.5);
  position: absolute;
}

.picker-center-highlight::before {
  top: 0;
}

.picker-center-highlight::after {
  bottom: 0;
}

上面仅仅仅仅包含图片样式组成,后续会逐渐添加各种样式。

初始化Picker组件

已经有了基本的 Picker 组件,现在我们开始进行一个初始化。让第一个元素显示在正确的位置。

这里有两个基本问题需要先考虑一下:

  • 元素的移动范围
  • 元素的下标和位置交换

元素的移动范围

我们元素移动范围用下标来说的话,应该是 1 到 length , 这里length 就是传入Picker数据长度。

因为我们第一个元素需要向下移动一列,所以第一列应该是空的, 这个时候位置也是我们位移 最大位置 。当不断将Picker 向上位移什么时候为最小的位置呢?应该是有这样计算 (length - Math.ceil(count / 2)) * 50 . 这里我们说的是显示 3列 情况, length 为数据长度, 50为单个Picker高度,上文已有。

下面直接看元素结算范围:

const getMoveRange = function() {
  const max = Math.floor(visibleCount / 2) * itemHeight;
  const min = (itemLength - Math.ceil(visibleCount / 2)) * -itemHeight;
  return [min, max]
}

这里就解决了第一个元素的范围问题。

这里使用两个数学函数:

Math.floor 取不大于该数的最大整数

Math.ceil 取不小于该数的最小整数

元素的下标和位置交换

这里需要两个函数分别来计算使用下标获取位置,使用位置来获取下标的。

通过下标获取元素位置时候有一点需要注意的是,我们元素位置是需要根据当前显示的个数进行偏移的,也就说,在计算之前,需要减去偏移量。偏移量刚好等于 Math.floor(count / 2)

const getTranslByIndex = function(index) {
  const offset = Math.floor(visibleCount / 2)
  
  if(index >= 0) {
    return (index - offset) * -itemHeight
  }
}

通过位移获取元素位置就简单很多了。

const getIndexByTransl = function(transl) {
  transl = Math.round(transl / itemHeight) * itemHeight;
  const index = - (transl - Math.floor(visibleCount / 2) * itemHeight) / itemHeight;
  
  return index;
}

计算用了三行代码, 第一行主要是转化当前位置靠近哪一个元素,得到具体translate,第二行 计算具体的 index, 这里计算语句前面使用 - 减号, 主要因为 translate 减去显示个数的1/2后,总是负值,这里需要将负值转正,也可以使用 Math.abs 来替代。

上面我们就解决了两个问题。

初始化组件

学习移动端组件 Picker一下

首先需要组件初始化为上图的样子,这个时候,我们开始监听事件,这了我们主要监听 touchstart, touchmove, touchend 事件。

const translateEl = function(transl) {
  el.style.transform = `translateY(${transl}px)`;
};

const setSelectedEl = function(index) {
  Array.prototype.forEach.call(pickerItems, (item, idx) => {
    item.classList.remove("active");
  });
  pickerItems[index].classList.add("active");
};

function initEvent() {
  el.addEventListener("touchstart", function(e) {
    console.log("touchstart", e);
  });
  el.addEventListener("touchmove", function(e) {
    console.log("touchmove", e);
  });
  el.addEventListener("touchend", function(e) {
    console.log("touchenv", e);
  });
}

window.onload = function onload() {
  translateY = getTranslByIndex(0);
  setSelectedEl(0);
  translateEl();
  initEvent();
};

上面的 pickerItems 就是选中的picker 元素集合.

这里就对元素进行了touchstart,touchmove, touchend 监听。下面我进一步对事件做处理,让picker动起来。

为了让picker 在移动过程中有过度效果,增加如下css

.picker-wrapper {
    overflow: visible;
    height: calc(50px * 3);
    transition: all 0.3s ease-in-out; /* 这里就对 元素做了过渡动画处理*/
}

开始对事件进行处理

el.addEventListener('touchstart', function(e) {
    startAt = Date.now();
    startTop = e.touches[0].pageY;
    // 开始滚动的位置
    startTranslateY = translateY;
  });
  el.addEventListener('touchmove', function(e) {
    const deltaY = e.touches[0].pageY - startTop;
    translateY = startTranslateY + deltaY;
    velocityTranslate = translateY - prevTranslateY || translateY;

    prevTranslateY = translateY;
    translateEl();
  });
  el.addEventListener('touchend', function(e) {
    let momentumTranslate = 0;
    // 小于 300 就开始弹性滚动
    if (Date.now() - startAt < 300) {
      momentumTranslate = translateY + velocityTranslate * momentumRatio;
    }

    let translate = Math.round(translateY / itemHeight) * itemHeight;

    if (momentumTranslate) {
      translate = Math.round(momentumTranslate / itemHeight) * itemHeight;
    }

    const range = getMoveRange();
    translateY = Math.max(Math.min(translate, range[1]), range[0]);
    translateEl();
    const index = getIndexByTransl(translateY);
    setSelectedEl(index);
  });

  // 每个item 点击生效
  Array.prototype.forEach.call(pickerItems, function(item, index) {
    item.addEventListener('click', function(e) {
      setSelectedEl(index);
      translateY = getTranslByIndex(index);
      translateEl();
    });
  });

这里就对触摸事件做了处理,也对单个元素的点击做了监听。

const el = document.querySelector('#wrapper');
const itemHeight = 50;
const visibleCount = 3;
const itemLength = 5;
const pickerItems = document.querySelectorAll('.picker-item');
let startAt = Date.now();
let startTop = 0;
let translateY = 0;
let startTranslateY = 0;
let prevTranslateY = 0;
// 动力参数
let momentumRatio = 7;
// 速度速度位移
let velocityTranslate = 0;

这里再开头申明了一些内容,主要说明一下 momentumRatiovelocityTranslate 这两个,前者是动力系数用于短时间修改位移后惯性移动,后者是速度位移用于在用户移动过程中移动的量。

现在就完成了一个基本的Picker。看图:

学习移动端组件 Picker一下

最后

目前只是一个最基本的例子。如果说需要选择两侧有一个缩放呢。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Speed Up Your Site

Speed Up Your Site

Andrew B. King / New Riders Press / 2003-01-14 / USD 39.99

There's a time bomb on the web: user patience. It starts ticking each time someone opens one of your pages. You only have a few seconds to get compelling content onto the screen. Fail, and you can kis......一起来看看 《Speed Up Your Site》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

SHA 加密
SHA 加密

SHA 加密工具