vue.js實現仿原生ios時間選擇組件執行個體代碼_javascript技巧

來源:互聯網
上載者:User

前言

最近幾個月一直在看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的選擇效果在進入選擇範圍內和選擇範圍外的滾輪是有差別的

所以為了實現這個效果差別我選擇用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);

每個資料旋轉的角度 和滾輪側視圖圓的半徑

每個資料旋轉的角度和構造原理

如上圖

是我們滾輪的效果立體圖,r 就是我們 translated3d(0px,0px,2.5rem) 這條css中的2.5rem,

如果沒有這句css 那麼所有的資料將匯聚在圓心

 

上圖 不做旋轉(紅色代表我們看到的資料效果)

 

上圖 做了旋轉(紅色 橙色代表我們看到的資料效果)

藍色弧線表示的角度是一樣的(這個涉及角的知識),也是視覺旋轉角度,就是rotate3d這句css裡面的80deg ,我做的是每個間隔20度,這樣實際我們只用旋轉x軸就順帶旋轉了圓心角度,這樣就把整個環給鋪開了。完整一個圓可以裝下360/20 個資料,而我們肉眼正能看見正面的資料,所以過了一定角度就在背後應該不能被我們看見,而-webkit-backface-visibility: hidden;這句話就起了作用。

這裡我們發現輪子裝不完所有資料,而且我們要實現資料迴圈

類似下圖效果

所以就有了第二次資料準備

資料準備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.現在選擇必須 年月日 或者年月日小時分鐘 不能單獨選小時或者分鐘

以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支援雲棲社區。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.