首頁  >  文章  >  web前端  >  vue.js實作仿原生ios時間選擇元件開發經驗

vue.js實作仿原生ios時間選擇元件開發經驗

怪我咯
怪我咯原創
2018-05-28 11:42:074402瀏覽


前言
最近幾個月一直在看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

灰色滾輪部分

#
<p class="picker-panel">
<!--other box-->
<p class="box-day">
  <p class="check-line"></p>
  <p class="day-checked">
    <p class="day-list">
      <p class="list-p" v-for="day in renderListDay">
       {{day.value}}
      </p>
    </p>
  </p>
  <p class="day-wheel">
    <p class="wheel-p" v-for="day in renderListDay" transform: rotate3d(1, 0, 0, 80deg) translate3d(0px, 0px, 2.5rem);>
    {{day.value}}
    </p>
  </p>
</p>
<!--other box-->
</p>
.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-p{
     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, &#39;day&#39;),
            index: k,
          };
          list.push(obj)
        }
        return list
      },

取資料的方法小於0倒著取大於0正著取,索引大於原始資料長度都用%計算來取得正常範圍對應的索引,所以上面的spin 就是我們的取資料的叉子(初始是從-9到9)

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

每條資料旋轉的角度(上半圓是正,下半圓是負)

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

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

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

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

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

惯性滚动
这个实现我是用了一个 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.现在选择必须 年月日 或者年月日小时分钟 不能单独选小时或者分钟

以上是vue.js實作仿原生ios時間選擇元件開發經驗的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn