vue 实现 ios 原生picker 效果及实现思路解析


Posted in Javascript onDecember 06, 2017

以前最早实现了一个类似的时间选择插件,但是适用范围太窄,索性最近要把这个实现方式发布出来,就重写了一个高复用的vue组件。

支持安卓4.0以上,safari 7以上

vue 实现 ios 原生picker 效果及实现思路解析

效果预览

gitHub

滚轮部分主要dom结构

<template data-filtered="filtered">
 <div class="pd-select-item">
  <div class="pd-select-line"></div>
  <ul class="pd-select-list">
   <li class="pd-select-list-item">1</li>
  </ul>
  <ul class="pd-select-wheel">
   <li class="pd-select-wheel-item">1</li>
  </ul>
 </div>
</template>
props
props: {
   data: {
    type: Array,
    required: true
   },
   type: {
    type: String,
    default: 'cycle'
   },
   value: {}
  }

设置css样式 使其垂直居中

.pd-select-line, .pd-select-list, .pd-select-wheel {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
}
.pd-select-list {
  overflow: hidden;
}

滚轮3d样式设置

/* 滚轮盒子 */
.pd-select-wheel {
  transform-style: preserve-3d;
  height: 30px;
}
/* 滚轮单项 */
.pd-select-wheel-item {
  white-space: nowrap;
  text-overflow: ellipsis;
  backface-visibility: hidden;
  position: absolute;
  top: 0px;
  width: 100%;
  overflow: hidden;
}

vue 实现 ios 原生picker 效果及实现思路解析

主要注意2个属性 transform-style: preserve-3d; backface-visibility: hidden;

第一个是3d布局,让界面3D化,第二个是让滚轮背后自动隐藏(上图红色部分,背面的dom节点 会自动隐藏)

如何实现3D 滚轮

盒子主要这句css transform: rotate3d(1, 0, 0, x deg);

item主要运用这句css transform: rotate3d(1, 0, 0, xdeg) translate3d(0px, 0px, [x]px);

vue 实现 ios 原生picker 效果及实现思路解析

vue 实现 ios 原生picker 效果及实现思路解析
vue 实现 ios 原生picker 效果及实现思路解析

上面2张图展示了translate3d(0px, 0px, [x]px);这句话的效果 [x]就是圆的半径

vue 实现 ios 原生picker 效果及实现思路解析

从上面的图可以看见,我们只需旋转每个dom自身,然后利用translate3d(0px, 0px, [x]px);把每个dom扩展开

就形成了圆环.α就是每个dom自身旋转的角度,因为这里只用了0到180°,所以用了个盒子在装这些dom

行高 和角度计算

vue 实现 ios 原生picker 效果及实现思路解析

已知两边和夹角 算第三边长度 ~=34px

http://tool.520101.com/calculator/sanjiaoxingjiaodu/

无限滚轮实现

/* 滚轮展示大小限定 */
spin: {start: 0, end: 9, branch: 9}
 
/* 获取spin 数据 */
 getSpinData (index) {
  index = index % this.listData.length
  return this.listData[index >= 0 ? index : index + this.listData.length]
 }
 /* 模运算 获取数组有的索引 这样就构成 圆环了 */

touchend做特殊处理

在touchend 里设置setCSS类型 把滚动数据取整,这样停止的时候就是

一格一格的准确转动到位

// other code ....
/* 计算touchEnd移动的整数距离 */
    let endMove = margin
    let endDeg = Math.round(updateDeg / deg) * deg
    if (type === 'end') {
     this.setListTransform(endMove, margin)
     this.setWheelDeg(endDeg)
    } else {
     this.setListTransform(updateMove, margin)
     this.setWheelDeg(updateDeg)
    }
 // other code ....
惯性缓动
// other code ....
setWheelDeg (updateDeg, type, time = 1000) {
    if (type === 'end') {
     this.$refs.wheel.style.webkitTransition = `transform ${time}ms cubic-bezier(0.19, 1, 0.22, 1)`
     this.$refs.wheel.style.webkitTransform = `rotate3d(1, 0, 0, ${updateDeg}deg)`
    } else {
     this.$refs.wheel.style.webkitTransition = ''
     this.$refs.wheel.style.webkitTransform = `rotate3d(1, 0, 0, ${updateDeg}deg)`
    }
   }
setListTransform (translateY = 0, marginTop = 0, type, time = 1000) {
    if (type === 'end') {
     this.$refs.list.style.webkitTransition = `transform ${time}ms cubic-bezier(0.19, 1, 0.22, 1)`
     this.$refs.list.style.webkitTransform = `translateY(${translateY - this.spin.branch * 34}px)`
     this.$refs.list.style.marginTop = `${-marginTop}px`
     this.$refs.list.setAttribute('scroll', translateY)
     console.log('end')
    } else {
     this.$refs.list.style.webkitTransition = ''
     this.$refs.list.style.webkitTransform = `translateY(${translateY - this.spin.branch * 34}px)`
     this.$refs.list.style.marginTop = `${-marginTop}px`
     this.$refs.list.setAttribute('scroll', translateY)
    }
}
// other code ....

获取当前选中值

/* 在设置完css后获取值 */
setStyle (move, type, time) {
  // ...other code
  /* 设置$emit 延迟 */
  setTimeout(() => this.getPickValue(endMove), 1000)
 // ...other code
}
/* 获取选中值 */
   getPickValue (move) {
    let index = Math.abs(move / 34)
    let pickValue = this.getSpinData(index)
    this.$emit('input', pickValue)
   }

初始化设置

mounted () {
   /* 事件绑定 */
   this.$el.addEventListener('touchstart', this.itemTouchStart)
   this.$el.addEventListener('touchmove', this.itemTouchMove)
   this.$el.addEventListener('touchend', this.itemTouchEnd)
   /* 初始化状态 */
   let index = this.listData.indexOf(this.value)
   if (index === -1) {
    console.warn('当前初始值不存在,请检查后listData范围!!')
    this.setListTransform()
    this.getPickValue(0)
   } else {
    let move = index * 34
    /* 因为往上滑动所以是负 */
    this.setStyle(-move)
    this.setListTransform(-move, -move)
   }

当展示为非无限滚轮的时

这里我们很好判断,就是滚动的距离不能超过原始数的数组长度*34,且不能小于0(实际代码中涉及方向)

/* 根据滚轮类型 line or cycle 判断 updateMove最大距离 */
    if (this.type === 'line') {
     if (updateMove > 0) {
      updateMove = 0
     }
     if (updateMove < -(this.listData.length - 1) * singleHeight) {
      updateMove = -(this.listData.length - 1) * singleHeight
     }
    }
 /* 根据type 控制滚轮显示效果 */
   setHidden (index) {
    if (this.type === 'line') {
     return index < 0 || index > this.listData.length - 1
    } else {
     return false
    }
   },

dom结构也增加了对应的响应

<div class="pd-select-item">
  <div class="pd-select-line"></div>
  <div class="pd-select-list">
   <ul class="pd-select-ul" ref="list">
    <li class="pd-select-list-item" v-for="el,index in renderData " :class="{'hidden':setHidden(el.index)}" :key="index">{{el.value}}</li>
   </ul>
  </div>
  <ul class="pd-select-wheel" ref="wheel">
   <li class="pd-select-wheel-item" :class="{'hidden':setHidden(el.index)}" :style="setWheelItemDeg(el.index)" :index="el.index" v-for="el,index in renderData " :key="index">{{el.value}}</li>
  </ul>
 </div>

总结

以上所述是小编给大家介绍的vue 实现 ios 原生picker 效果及思路解析,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
jquery 插件开发方法小结
Oct 23 Javascript
EXTJS内使用ACTIVEX控件引起崩溃问题的解决方法
Mar 31 Javascript
javascript利用初始化数据装配模版的实现代码
Nov 17 Javascript
前台js对象在后台转化java对象的问题探讨
Dec 20 Javascript
JavaScript获取XML数据附示例截图
Mar 05 Javascript
js获取json元素数量的方法
Jan 27 Javascript
jQuery仿淘宝网产品品牌隐藏与显示效果
Sep 01 Javascript
Linux下为Node.js程序配置MySQL或Oracle数据库的方法
Mar 19 Javascript
微信小程序 基础知识css样式media标签
Feb 15 Javascript
基于vue-ssr的静态网站生成器VuePress 初体验
Apr 17 Javascript
create-react-app中添加less支持的实现
Nov 15 Javascript
JS组件库AlloyTouch实现图片轮播过程解析
May 29 Javascript
微信小程序实现点击按钮修改文字大小功能【附demo源码下载】
Dec 06 #Javascript
基于Vue2的独立构建与运行时构建的差别(详解)
Dec 06 #Javascript
js 两数组去除重复数值的实例
Dec 06 #Javascript
js 提取某()特殊字符串长度的实例
Dec 06 #Javascript
React-Router如何进行页面权限管理的方法
Dec 06 #Javascript
移动前端图片压缩上传的实例
Dec 06 #Javascript
详细分析JS函数去抖和节流
Dec 05 #Javascript
You might like
PHP连接Access数据库的方法小结
2013/06/20 PHP
Codeigniter的dom类用法实例
2015/06/26 PHP
WordPress中用于获取文章作者与分类信息的方法整理
2015/12/17 PHP
php session的应用详细介绍
2017/03/22 PHP
JavaScript 保存数组到Cookie的代码
2010/04/14 Javascript
jquery中的mouseleave和mouseout的区别 模仿下拉框效果
2012/02/07 Javascript
JSON.stringify 语法实例讲解
2012/03/14 Javascript
jquery 插件开发 extjs中的extend用法小结
2013/01/04 Javascript
获取offsetTop和offsetLeft值的js代码(兼容)
2013/04/16 Javascript
各浏览器对document.getElementById等方法的实现差异解析
2013/12/05 Javascript
JavaScript获取table中某一列的值的方法
2014/05/06 Javascript
javascript实现类似超链接的效果
2014/12/26 Javascript
JavaScript控制网页层收起和展开效果的方法
2015/04/15 Javascript
jQuery on()方法使用技巧详解
2015/04/16 Javascript
由ReactJS的Hello world说开来
2015/07/02 Javascript
jQuery实现单击弹出Div层窗口效果(可关闭可拖动)
2015/09/19 Javascript
Bootstrap入门书籍之(五)导航条、分页导航
2016/02/17 Javascript
window.open不被拦截的简单实现代码(推荐)
2016/08/04 Javascript
jquery.Jcrop结合JAVA后台实现图片裁剪上传实例
2016/11/05 Javascript
JavaScript实现短信倒计时60s
2017/10/09 Javascript
利用HBuilder打包前端开发webapp为apk的方法
2017/11/13 Javascript
VUE v-for循环中每个item节点动态绑定不同函数的实例
2018/09/26 Javascript
CryptoJS中AES实现前后端通用加解密技术
2018/12/18 Javascript
微信小程序防止多次点击跳转和防止表单组件输入内容多次验证功能(函数防抖)
2019/09/19 Javascript
分析python动态规划的递归、非递归实现
2018/03/04 Python
Django自定义用户认证示例详解
2018/03/14 Python
python 列表,数组,矩阵两两转换tolist()的实例
2018/04/04 Python
在Python中给Nan值更改为0的方法
2018/10/30 Python
11个Python3字典内置方法大全与示例汇总
2019/05/13 Python
Selenium自动化测试工具使用方法汇总
2020/06/12 Python
10行Python代码实现Web自动化管控的示例代码
2020/08/14 Python
获取邓白氏信用报告:Dun & Bradstreet
2019/01/22 全球购物
2019经典广告词集锦!
2019/07/02 职场文书
解决MultipartFile.transferTo(dest) 报FileNotFoundExcep的问题
2021/07/01 Java/Android
CSS Transition通过改变Height实现展开收起元素
2021/08/07 HTML / CSS
html5调用摄像头截图功能
2022/01/18 Javascript