vue.js实现仿原生ios时间选择组件实例代码


Posted in Javascript onDecember 21, 2016

前言

最近几个月一直在看VUE,然后试着只用原生js+vue实现某些组件。

PC端时间选择组件 这是最开始实现的pc上的时间选择,平时移动端也在做,所以就想实现一下移动端的时间选择器,下面分享一下我实现移动端滚轮特效时间选择器的思路和过程。整个组件是基于vue-cli来进行构建的

功能

1.时间选择[ A.年月日选择 B.年月日小时分钟选择 C.小时分钟选择 D.分钟选择]

2.滚轮效果[ A.构成一个圆环首尾相连 B.不构成首尾相连]

3.时间选择范围设置(所选时间超过范围将弹窗提示),分钟间隔设置

4.多语言设置

5.时间格式设置 满足 yyyy/MM/dd HH:mm 这一类的设置规则

6.UE上做到接近ios原生效果

7.扩展 不仅仅只能选择时间,可以传入自定义联动选择数据

这里主要讲讲无限滚轮的实现
数据准备1

这里拿 来做说明

获取一个月有多少天的一个巧妙的方法。

dayList () {
       /* get currentMonthLenght */
        let currentMonthLength = new Date(this.tmpYear, this.tmpMonth + 1, 0).getDate();
       /* get currentMonth day */
        let daylist = Array.from({length: currentMonthLength}, (value, index) => {
          return index + 1
        });
        return daylist
      },

这里我用了vue 的computed方法来实现,放入 yearList monthList dayList hourList minuteList 来存储基础数据,这里数据准备就先告一段落。

静态效果实现

实现滚轮静态效果有多种方式

1.视觉3D效果[加阴影]

2.实际3D效果[CSS3D]

我把实现效果大致分为上面2种,具体的大家可以自己搜索相关资料,这里展开涉及太多就带过好了

我自己实现是用的第二种采用了CSS3D

说明

首先我们看到原生ios的选择效果在进入选择范围内和选择范围外的滚轮是有差别的

vue.js实现仿原生ios时间选择组件实例代码

所以为了实现这个效果差别我选择用2个dom结构来实现,一个dom实现滚轮,一个dom实现黑色选中效果,这样联动的时候就有类似原生的效果差别

picker-panel 装各种选择dom,这里只给出了day的, box-day 装天数据的一个最外层盒子, check-line 实现选中的那2条线, day-list 最外层黑色效果数据, day-wheel 灰色滚轮部分

<div class="picker-panel">
<!--other box-->
<div class="box-day">
  <div class="check-line"></div>
  <div class="day-checked">
    <div class="day-list">
      <div class="list-div" v-for="day in renderListDay">
       {{day.value}}
      </div>
    </div>
  </div>
  <div class="day-wheel">
    <div class="wheel-div" v-for="day in renderListDay" transform: rotate3d(1, 0, 0, 80deg) translate3d(0px, 0px, 2.5rem);>
    {{day.value}}
    </div>
  </div>
</div>
<!--other box-->
</div>
.day-wheel{
    position: absolute;
    overflow: visible;
    height: px2rem(68px);
    font-size: px2rem(36px);
    top:px2rem(180px);
    left: 0;
    right: 0;
    color:$unchecked-date;
    -webkit-transform-style: preserve-3d;
    transform-style: preserve-3d;
    .wheel-div{
     height: px2rem(68px);
     line-height: px2rem(68px);
     position: absolute;
     top:0;
     width: 100%;
     text-align: center;
     -webkit-backface-visibility: hidden;
     backface-visibility: hidden;
     white-space: nowrap;
     overflow: hidden;
     text-overflow: ellipsis;
    }
   }

主要涉及的css属性

transform-style: preserve-3d;

展示3D效果,

-webkit-backface-visibility: hidden;

滚轮背后部分自动隐藏

postition:absolute;

用来定位轮子

transform: rotate3d(1, 0, 0, 80deg) translate3d(0px, 0px, 2.5rem);

每个数据旋转的角度 和滚轮侧视图圆的半径

每个数据旋转的角度和构造原理

vue.js实现仿原生ios时间选择组件实例代码

如上图

是我们滚轮的效果立体图,r 就是我们 translated3d(0px,0px,2.5rem) 这条css中的2.5rem,

如果没有这句css 那么所有的数据将汇聚在圆心

vue.js实现仿原生ios时间选择组件实例代码 

上图 不做旋转(红色代表我们看到的数据效果)

 vue.js实现仿原生ios时间选择组件实例代码

上图 做了旋转(红色 橙色代表我们看到的数据效果)

蓝色弧线表示的角度是一样的(这个涉及角的知识),也是视觉旋转角度,就是rotate3d这句css里面的80deg ,我做的是每个间隔20度,这样实际我们只用旋转x轴就顺带旋转了圆心角度,这样就把整个环给铺开了。完整一个圆可以装下360/20 个数据,而我们肉眼正能看见正面的数据,所以过了一定角度就在背后应该不能被我们看见,而-webkit-backface-visibility: hidden;这句话就起了作用。

这里我们发现轮子装不完所有数据,而且我们要实现数据循环

类似下图效果

vue.js实现仿原生ios时间选择组件实例代码

所以就有了第二次数据准备

数据准备2

这里也是用我们的dayList作为初始数据[1,2,3,4,.....,30,31]

这里我们每次取19个数据来作为渲染数据,而我们需要renderListDay初始呈现是[23,24,25,26,27,28,29,30,31,1,2,3,4,5,6,7,8,9,10]

因为这样取最中间的数刚好是第一个(仅在初始化的时候)

renderListDay(){
        let list = [];
        for (let k = this.spin.day.head; k <= this.spin.day.last; k++) {
          let obj = {
            value: this.getData(k, 'day'),
            index: k,
          };
          list.push(obj)
        }
        return list
      },

取数据的方法 小于0倒着取 大于0正着取,索引大于原始数据长度都用%计算来获得正常范围对应的索引,所以上面的spin 就是我们的取数据的叉子(初始是从-9到9)

getData(idx, type){
       //...
        else if (type == 'day') {
          return this.dayList[idx % this.dayList.length >= 0 ? idx % this.dayList.length : idx % this.dayList.length + this.dayList.length];
        } 
        //...
      },

每条数据旋转的角度(上半圆是正,下半圆是负)

<div class="wheel-div" v-for="day in renderListDay" v-bind:data-index="day.index" v-bind:style="{transform: 'rotate3d(1, 0, 0, '+ (-day.index)*20%360+'deg) translate3d(0px, 0px, 2.5rem)'}">{{day.value}}{{day.value}}</div>

接着需要旋转到我们需要的角度,跟我们的初始化时间对上,this.orDay-this.DayList[0] 是获取偏移量来矫正角度

this.$el.getElementsByClassName('day-wheel')[0].style.transform = 'rotate3d(1, 0, 0, ' + (this.orDay - this.dayList[0]) * 20 + 'deg)';

增加touch事件

剩下的事就很好处理了,给对应的dom绑定事件根据touchmove的距离来转换成旋转的角度 和check-list的位移这里translateY是用来记录实际移动的距离的,最后输出需要算入偏移量

<div class="box-day" v-on:touchstart="myTouch($event,'day')" v-on:touchmove="myMove($event,'day')" v-on:touchend="myEnd($event,'day')">
  <div class="check-line"></div>
  <div class="day-checked">
    <div class="day-list" data-translateY="0" style="transform: translateY(0rem)">
      <div class="list-div" v-for="day in renderListDay" v-bind:data-index="day.index">
        {{day.value}}
      </div>
    </div>
  </div>
  <div class="day-wheel" style=" transform: rotate3d(1, 0, 0,0deg)">
    <div class="wheel-div" v-for="day in renderListDay" v-bind:data-index="day.index" v-bind:style="{transform: 'rotate3d(1, 0, 0, '+ (-day.index)*20%360+'deg) translate3d(0px, 0px, 2.5rem)'}">
     {{day.value}}
    </div>
  </div>
</div>

惯性滚动

这个实现我是用了一个 cubic-bezier(0.19, 1, 0.22, 1)

判断手势是不是flicker 如果是flicker通过一个瞬时速度来算出位移,和时间,然后一次性设置,然后用transition做惯性滚动,
普通拖动 设置1秒

这个实际效果还是有点不好,以后来改进。

其他功能的实现

这里不做详细说明了

总结

自适应方面用了手淘的解决方案

这次实现这个组件最困难的就是实现无限滚动,和无限滚动的渲染数据的构造,接着就是惯性滚动的实现。

已知问题

1.惯性滚动不完美

2.无限滚动实现了。非无限滚动没实现,就是渲染数据就是[1,2,3,4,5,6,7,8,9,10]

3.现在选择必须 年月日 或者年月日小时分钟 不能单独选小时或者分钟

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JS删除数组元素的函数介绍
Mar 27 Javascript
JS控制图片翻转示例代码(兼容firefox,ie,chrome)
Dec 19 Javascript
JQuery的$命名冲突详细解析
Dec 28 Javascript
js 获取时间间隔实现代码
May 12 Javascript
Javascript限制网页只能在微信内置浏览器中访问
Nov 09 Javascript
微信小程序 Tab页切换更新数据
Jan 05 Javascript
ECMAscript 变量作用域总结概括
Aug 18 Javascript
javascript 通过键名获取键盘的keyCode方法
Dec 31 Javascript
JS严格模式知识点总结
Feb 27 Javascript
vue使用Element组件时v-for循环里的表单项验证方法
Jun 28 Javascript
layui给下拉框、按钮状态、时间赋初始值的方法
Sep 10 Javascript
Vue-cli打包后部署到子目录下的路径问题说明
Sep 02 Javascript
详解jQuery的表单验证插件--Validation
Dec 21 #Javascript
JS无缝滚动效果实现方法分析
Dec 21 #Javascript
简单实现JS计算器功能
Dec 21 #Javascript
jQuery实现立体式数字滚动条增加效果
Dec 21 #Javascript
Bootstrap Search Suggest使用例子
Dec 21 #Javascript
简单实现Bootstrap标签页
Aug 09 #Javascript
获取JavaScript异步函数的返回值
Dec 21 #Javascript
You might like
BBS(php &amp; mysql)完整版(一)
2006/10/09 PHP
PHP 中英文混合排版中处理字符串常用的函数
2007/04/12 PHP
遍历指定目录下的所有目录和文件的php代码
2011/11/27 PHP
PHP版 汉字转码的实现详解
2013/06/09 PHP
PHP将XML转数组过程详解
2013/11/13 PHP
PHP连接sql server 2005环境配置及问题解决
2014/08/08 PHP
基于PHP代码实现中奖概率算法可用于刮刮卡、大转盘等抽奖算法
2015/12/20 PHP
YII框架中使用memcache的方法详解
2017/08/02 PHP
JQuery的html(data)方法与&amp;lt;script&amp;gt;脚本块的解决方法
2010/03/09 Javascript
JavaScript检查弹出窗口是否被阻拦的方法技巧
2015/03/13 Javascript
Javascript农历与公历相互转换的简单实例
2016/10/09 Javascript
JavaScript面向对象分层思维全面解析
2016/11/22 Javascript
jQuery实现的checkbox级联选择下拉菜单效果示例
2016/12/26 Javascript
vue-cli + sass 的正确打开方式图文详解
2017/10/27 Javascript
面包屑导航详解
2017/12/07 Javascript
vue2.0 自定义 饼状图 (Echarts)组件的方法
2018/03/02 Javascript
基于IView中on-change属性的使用详解
2018/03/15 Javascript
Python列表切片用法示例
2017/04/19 Python
python实现图书管理系统
2018/03/12 Python
Python基于最小二乘法实现曲线拟合示例
2018/06/14 Python
python人民币小写转大写辅助工具
2018/06/20 Python
Python开发的十个小贴士和技巧及长常犯错误
2018/09/27 Python
python os.listdir按文件存取时间顺序列出目录的实例
2018/10/21 Python
python 实现目录复制的三种小结
2019/12/04 Python
Sasa莎莎海外旗舰店:香港莎莎美妆平台
2018/03/21 全球购物
结构和类有什么异同
2012/07/16 面试题
写自荐信三大法宝
2014/01/24 职场文书
终止合同协议书
2014/04/17 职场文书
2014预备党员党课学习心得范文
2014/07/08 职场文书
2014年党的群众路线整改措施思想汇报
2014/10/12 职场文书
补充协议书
2015/01/28 职场文书
行政上诉状范文
2015/05/23 职场文书
村主任当选感言
2015/08/01 职场文书
超市店长竞聘书
2015/09/15 职场文书
教你部署vue项目到docker
2022/04/05 Vue.js
react中useState使用:如何实现在当前表格直接更改数据
2022/08/05 Javascript