摘要:原文前言一個(gè)移動(dòng)端的事件或者事件,具體看看怎么玩。初始化組件已經(jīng)有了基本的組件,現(xiàn)在我們開始進(jìn)行一個(gè)初始化。因?yàn)槲覀兊谝粋€(gè)元素需要向下移動(dòng)一列,所以第一列應(yīng)該是空的這個(gè)時(shí)候位置也是我們位移最大位置??磮D最后目前只是一個(gè)最基本的例子。
原文: https://www.luoyangfu.com/art...前言
一個(gè)移動(dòng)端的touch 事件或者 mouse 事件,具體看看怎么玩。
先看看效果:
這里年月日都是使用創(chuàng)建好的Picker組件來實(shí)現(xiàn)的,在之前感謝博客園 @糊糊糊糊糊了, 原文地址.
原文中講了實(shí)現(xiàn)Picker核心思路,我也是受益頗多,然后根據(jù)思路以及Github源碼,終于寫了自己想要的Picker,于是就有了記錄,再次感謝.
多帶帶Picker HTML 結(jié)構(gòu)開發(fā)這個(gè)Picker, 觀察Picker節(jié)點(diǎn)結(jié)構(gòu),Picker 是由定高隱藏元素的塊, 一個(gè)定高不隱藏元素的的塊,以及一個(gè)選擇列表組成這三個(gè)部分。我們得知了這個(gè)Picker組成后很容易就可以寫出來下面HTML的結(jié)構(gòu):
20162017201820192020
這個(gè)就是最簡單的 picker 結(jié)構(gòu)了。
CSS 樣式咱們給這塊結(jié)構(gòu)添加樣式,顯示如下, 在這里我們默認(rèn)元素的高度在css 中寫死為 50px.
我們這里就寫了關(guān)于 Picker 基礎(chǔ)樣式。
.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; }
上面僅僅僅僅包含圖片樣式組成,后續(xù)會(huì)逐漸添加各種樣式。
初始化Picker組件已經(jīng)有了基本的 Picker 組件,現(xiàn)在我們開始進(jìn)行一個(gè)初始化。讓第一個(gè)元素顯示在正確的位置。
這里有兩個(gè)基本問題需要先考慮一下:
元素的移動(dòng)范圍
元素的下標(biāo)和位置交換
元素的移動(dòng)范圍我們元素移動(dòng)范圍用下標(biāo)來說的話,應(yīng)該是 1 到 length, 這里length 就是傳入Picker數(shù)據(jù)長度。
因?yàn)槲覀兊谝粋€(gè)元素需要向下移動(dòng)一列,所以第一列應(yīng)該是空的, 這個(gè)時(shí)候位置也是我們位移最大位置。當(dāng)不斷將Picker 向上位移什么時(shí)候?yàn)樽钚〉奈恢媚兀繎?yīng)該是有這樣計(jì)算 (length - Math.ceil(count / 2)) * 50. 這里我們說的是顯示3列情況, length 為數(shù)據(jù)長度, 50為單個(gè)Picker高度,上文已有。
下面直接看元素結(jié)算范圍:
const getMoveRange = function() { const max = Math.floor(visibleCount / 2) * itemHeight; const min = (itemLength - Math.ceil(visibleCount / 2)) * -itemHeight; return [min, max] }
這里就解決了第一個(gè)元素的范圍問題。
這里使用兩個(gè)數(shù)學(xué)函數(shù):元素的下標(biāo)和位置交換
Math.floor 取不大于該數(shù)的最大整數(shù)
Math.ceil 取不小于該數(shù)的最小整數(shù)
這里需要兩個(gè)函數(shù)分別來計(jì)算使用下標(biāo)獲取位置,使用位置來獲取下標(biāo)的。
通過下標(biāo)獲取元素位置時(shí)候有一點(diǎn)需要注意的是,我們元素位置是需要根據(jù)當(dāng)前顯示的個(gè)數(shù)進(jìn)行偏移的,也就說,在計(jì)算之前,需要減去偏移量。偏移量剛好等于 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; }
計(jì)算用了三行代碼, 第一行主要是轉(zhuǎn)化當(dāng)前位置靠近哪一個(gè)元素,得到具體translate,第二行 計(jì)算具體的 index, 這里計(jì)算語句前面使用 -減號(hào), 主要因?yàn)?translate 減去顯示個(gè)數(shù)的1/2后,總是負(fù)值,這里需要將負(fù)值轉(zhuǎn)正,也可以使用 Math.abs 來替代。
上面我們就解決了兩個(gè)問題。
初始化組件首先需要組件初始化為上圖的樣子,這個(gè)時(shí)候,我們開始監(jiān)聽事件,這了我們主要監(jiān)聽 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 元素集合.
這里就對(duì)元素進(jìn)行了touchstart,touchmove, touchend 監(jiān)聽。下面我進(jìn)一步對(duì)事件做處理,讓picker動(dòng)起來。
為了讓picker 在移動(dòng)過程中有過度效果,增加如下css
.picker-wrapper { overflow: visible; height: calc(50px * 3); transition: all 0.3s ease-in-out; /* 這里就對(duì) 元素做了過渡動(dòng)畫處理*/ }
開始對(duì)事件進(jìn)行處理
el.addEventListener("touchstart", function(e) { startAt = Date.now(); startTop = e.touches[0].pageY; // 開始滾動(dòng)的位置 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 就開始彈性滾動(dòng) 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); }); // 每個(gè)item 點(diǎn)擊生效 Array.prototype.forEach.call(pickerItems, function(item, index) { item.addEventListener("click", function(e) { setSelectedEl(index); translateY = getTranslByIndex(index); translateEl(); }); });
這里就對(duì)觸摸事件做了處理,也對(duì)單個(gè)元素的點(diǎn)擊做了監(jiān)聽。
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; // 動(dòng)力參數(shù) let momentumRatio = 7; // 速度速度位移 let velocityTranslate = 0;
這里再開頭申明了一些內(nèi)容,主要說明一下 momentumRatio 和 velocityTranslate 這兩個(gè),前者是動(dòng)力系數(shù)用于短時(shí)間修改位移后慣性移動(dòng),后者是速度位移用于在用戶移動(dòng)過程中移動(dòng)的量。
現(xiàn)在就完成了一個(gè)基本的Picker??磮D:
最后目前只是一個(gè)最基本的例子。如果說需要選擇兩側(cè)有一個(gè)縮放呢。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/105269.html
摘要:官網(wǎng)還不斷的訪問不了。在此推薦一個(gè)移動(dòng)端庫按需引入二次封裝組件列表的下拉刷新和上拉加載更多是移動(dòng)端必須的組件。不用寫死高度了,并且兼容對(duì)外提供了更加簡明易用的刷新,回到頂部,獲得和設(shè)置滾動(dòng)條位置的方法統(tǒng)一的提示,免去重復(fù)代碼。 按需引入mint-ui 本項(xiàng)目用了 mint-ui 作為基礎(chǔ)ui框架,在使用中遇到不少問題。官網(wǎng)doc 還不斷的訪問不了。不過還是很感謝 mint-ui 團(tuán)隊(duì)。...
摘要:移動(dòng)端選擇器有很多,各大組件都有自己的,比如,,,等等。這次的地區(qū)選擇,需要地區(qū)的省份市經(jīng)緯度,還要設(shè)置第一次點(diǎn)開的時(shí)候是特定城市。引入樣式和文件地區(qū)選擇級(jí)聯(lián)地區(qū)選擇設(shè)定默認(rèn)選項(xiàng)省份城市代碼很簡單,不懂的百度一下。移動(dòng)端選擇器picker有很多,各大ui組件都有自己的picker,比如light7,HUI,MUI,jqueryUI等等。但是,我發(fā)現(xiàn)他們都有各種各樣的問題。這次的地區(qū)選擇,需要...
摘要:本組件停止維護(hù)組件庫請(qǐng)移步小程序組件庫請(qǐng)移步有贊前端大量坑位,內(nèi)推私信基于的移動(dòng)端組件支持單列多列和聯(lián)級(jí)數(shù)據(jù)內(nèi)置時(shí)間日期數(shù)據(jù)滾輪效果顏色可配置已啟用試試離線訪問吧點(diǎn)擊查看詳細(xì)使用方法參照源碼參數(shù)描述可選類型默認(rèn)詳細(xì)描述 ?? DEPRECATED 本組件停止維護(hù) ?? Vue 組件庫請(qǐng)移步 Vant ?? 小程序組件庫請(qǐng)移步 Vant Weapp ?? 有贊前端大量坑位,內(nèi)推私信 v...
摘要:正文距離第一篇組件庫文章發(fā)布已經(jīng)過去個(gè)月了,在此期間利用零零散散的時(shí)間持續(xù)更新組件庫,目前移動(dòng)端組件庫已經(jīng)更新大類基礎(chǔ)表單彈出層種組件供使用。鏈接組件庫從到開發(fā)心得主頁更改版版方案祝工作順利鄧文斌年月日正文 距離第一篇UI組件庫文章發(fā)布已經(jīng)過去3個(gè)月了,在此期間利用零零散散的時(shí)間持續(xù)更新owl-ui組件庫,目前owl-ui移動(dòng)端組件庫已經(jīng)更新3大類(基礎(chǔ)、表單、彈出層)9種組件(Button...
摘要:本文簡單介紹近來寫的一款基于的移動(dòng)端輕量級(jí)日期插件。再來看看兼容性對(duì)于移動(dòng)開發(fā)足矣最后就是在綁定事件的兼容性問題,不同廠商對(duì)于這個(gè)事件的定義并不一致,比如里面監(jiān)聽的是事件,但是在安卓里面監(jiān)聽事件完全沒反應(yīng),經(jīng)過一番,發(fā)現(xiàn)安卓需要監(jiān)聽事件。 前言 做過移動(dòng)Web開發(fā)的同學(xué)都知道,移動(dòng)端日期選擇是很常見的需求。在PC端,我們有很豐富的選擇,比較出名的就有Mobiscroll和jQuery ...
閱讀 2675·2021-11-18 10:02
閱讀 1774·2021-09-30 10:00
閱讀 5433·2021-09-22 15:27
閱讀 1274·2019-08-30 15:54
閱讀 3740·2019-08-29 11:13
閱讀 3013·2019-08-29 11:05
閱讀 3386·2019-08-29 11:01
閱讀 629·2019-08-26 13:52