亚洲精品久久久中文字幕-亚洲精品久久片久久-亚洲精品久久青草-亚洲精品久久婷婷爱久久婷婷-亚洲精品久久午夜香蕉

更多QQ空间微信QQ好友腾讯朋友复制链接
您的位置:首頁(yè)/技術(shù)文章
文章詳情頁(yè)

JS如何讓你的移動(dòng)端交互體驗(yàn)更加優(yōu)秀

【字号: 作者:豬豬瀏覽:82日期:2024-03-26 09:32:52
目錄1. 即時(shí)反饋1.1 按鈕的即時(shí)反饋1.2 持續(xù)性的反饋1.3 頁(yè)面初始化1.4 數(shù)據(jù)的展示2. 行為跟隨2.1 點(diǎn)擊按鈕后呼起彈窗2.2 列表中有對(duì)象變動(dòng)時(shí)2.3 絲滑的滑動(dòng)跟隨3. 考慮移動(dòng)設(shè)備的握持姿勢(shì)3.1 避免滾動(dòng)穿透3.2 原生 select 標(biāo)簽的使用4. 良好的兜底策略4.1 全屏沉浸式頁(yè)面應(yīng)當(dāng)保持關(guān)閉操作4.2 永遠(yuǎn)不要相信后臺(tái)一直很穩(wěn)定4.3 懶加載5. 總結(jié)1. 即時(shí)反饋

我們?cè)谕嬗螒虻倪^(guò)程中,通常都會(huì)遇到一個(gè)詞:“打擊感”,通俗的理解就是我們做出的每一個(gè)操作,都有很強(qiáng)烈的反饋,比如視覺(jué)上的動(dòng)畫(huà)變化,聽(tīng)覺(jué)上產(chǎn)生的聲音,或者移動(dòng)設(shè)備的震動(dòng)感等。

1.1 按鈕的即時(shí)反饋

在前端頁(yè)面中,也應(yīng)當(dāng)像游戲中的打擊感一樣,用戶(hù)任何的操作都應(yīng)當(dāng)予以即時(shí)的反饋,告訴用戶(hù)他的操作是有效的,系統(tǒng)已收到他的操作,內(nèi)部正在處理中。

例如用戶(hù)在點(diǎn)擊頁(yè)面中的按鈕時(shí),按鈕最好有一種被按下的效果:

button:active { transform: translateY(4px);}

若按鈕被下壓的效果不太適合頁(yè)面整體的風(fēng)格,您也可以做一個(gè)背景顏色上的變化。

1.2 持續(xù)性的反饋

每個(gè)用戶(hù)的設(shè)備型號(hào)、網(wǎng)絡(luò)狀態(tài)等情況都不一樣,我們不能要求每個(gè)用戶(hù)都在良好的 WiFi 下操作我們的頁(yè)面。

若用戶(hù)的某個(gè)行為產(chǎn)生了網(wǎng)絡(luò)請(qǐng)求,并要根據(jù)請(qǐng)求返回的結(jié)果,反饋給用戶(hù)。這種情況,頁(yè)面都應(yīng)當(dāng)給用戶(hù)一種持續(xù)性的反饋,表示一個(gè)動(dòng)作正在后臺(tái)執(zhí)行。如果沒(méi)有這種效果,即使已經(jīng)在請(qǐng)求接口了,用戶(hù)也會(huì)認(rèn)為點(diǎn)擊沒(méi)有反應(yīng),會(huì)多次的去點(diǎn)擊按鈕,以期望得到響應(yīng)。

我們可以在這里給自己定下一條規(guī)則:

凡是有網(wǎng)絡(luò)請(qǐng)求的情形,均要有 loading 效果的持續(xù)性反饋。

我們通??梢栽谟脩?hù)觸發(fā)的按鈕上展示 loading 效果,也可以在全局頁(yè)面上展示 loading 效果,這個(gè)根據(jù)每個(gè)頁(yè)面的風(fēng)格自行選擇即可。

JS如何讓你的移動(dòng)端交互體驗(yàn)更加優(yōu)秀

例如頁(yè)面上有個(gè)紅包需要點(diǎn)擊按鈕開(kāi)啟,當(dāng)用戶(hù)點(diǎn)擊按鈕后,按鈕就可以展示出一個(gè)旋轉(zhuǎn)的 loading 效果,待接口返回結(jié)果再打開(kāi)紅包,展示具體的金額,或者其他的結(jié)果。

1.3 頁(yè)面初始化

在現(xiàn)在大部分前后端分離的場(chǎng)景下(同時(shí)沒(méi)有使用同構(gòu)直出方案),都是先展示出一個(gè)沒(méi)有數(shù)據(jù)的前端頁(yè)面,然后請(qǐng)求數(shù)據(jù),待數(shù)據(jù)返回后再渲染頁(yè)面。

這種情形和上面 1.2 中是一樣的,不過(guò)這個(gè)是在剛進(jìn)入頁(yè)面就觸發(fā)的!這里我們也是要展示出 loading 效果的,只不過(guò)是 loading 展示的時(shí)機(jī)的問(wèn)題。

1.先一個(gè)全局 loading 的開(kāi)啟頁(yè),在數(shù)據(jù)沒(méi)有返回回來(lái)時(shí),看不到任何相關(guān)活動(dòng)元素;

2.先用初始化的假數(shù)據(jù)或者兜底數(shù)據(jù),渲染一個(gè)基本框架,然后在某個(gè)位置展示 loading 效果,并請(qǐng)求數(shù)據(jù),數(shù)據(jù)返回后再替換假數(shù)據(jù)進(jìn)行渲染。

這兩種方式也是各有不同的使用場(chǎng)景,就我個(gè)人而言,我更喜歡第 2 種方式,能夠第一時(shí)間將頁(yè)面中的元素展示給用戶(hù);但如果頁(yè)面布局因接口的數(shù)據(jù)改變較大,建議還是采用第 1 種方式,這樣 loading 結(jié)束時(shí),不會(huì)出現(xiàn)頁(yè)面大幅度閃動(dòng)的感覺(jué)。

1.4 數(shù)據(jù)的展示

我們拿到接口的數(shù)據(jù)后,通常會(huì)有兩種展示狀態(tài):

1.無(wú)數(shù)據(jù),進(jìn)行“暫無(wú)數(shù)據(jù)”之類(lèi)的提示;

2.有數(shù)據(jù),正常展示數(shù)據(jù);

比如一個(gè)展示獎(jiǎng)品列表中數(shù)據(jù)中,這里我們通常會(huì)初始化一個(gè) list 變量來(lái)接收接口返回的數(shù)據(jù):

const List = () => { const [list, setList] = useState([]); useEffect(() => { // 設(shè)置數(shù)據(jù) // setList([]); }, []); return ( <div className='list'> {list.length ? (<div className='container'> {list.map((item) => ( <div key={item.key}>{item.title}</div> ))}</div> ) : (<div className='nothing'>暫無(wú)數(shù)據(jù)</div> )} </div> );};

在請(qǐng)求接口的過(guò)程中,頁(yè)面會(huì)展示什么?“暫無(wú)數(shù)據(jù)”,給用戶(hù)的第一視覺(jué)感受就是:我的獎(jiǎng)品丟了。等過(guò)一會(huì)兒接口返回?cái)?shù)據(jù)了,然后又重新將數(shù)據(jù)展示出來(lái)。

這里,我們就忽略了一個(gè)很重要的狀態(tài):loading狀態(tài)。因?yàn)椤皶簾o(wú)數(shù)據(jù)”,也是一種結(jié)果,不是過(guò)程,是要告訴用戶(hù),您當(dāng)前是沒(méi)有數(shù)據(jù)的。因此,不能把“暫無(wú)數(shù)據(jù)”作為 loading 狀態(tài)來(lái)展示。

const List = () => { const [loading, setLoading] = useState(true); const [list, setList] = useState([]); useEffect(() => { // 設(shè)置數(shù)據(jù) // setList([]); setLoading(false); // 請(qǐng)求完接口,再把loading狀態(tài)取消,該展示什么結(jié)果就展示什么 }, []); if (loading) { return ( <div className='list'><div className='loading'>請(qǐng)求數(shù)據(jù)中...</div> </div> ); } return ( <div className='list'> {list.length ? (<div className='container'> {list.map((item) => ( <div key={item.key}>{item.title}</div> ))}</div> ) : (<div className='nothing'>暫無(wú)數(shù)據(jù)</div> )} </div> );};2. 行為跟隨

這里我也不太想好用個(gè)什么名字,概況來(lái)說(shuō),告訴用戶(hù)剛才發(fā)生了什么,將用戶(hù)操作可視化, 來(lái)增強(qiáng)用戶(hù)對(duì)操作行為的感知度, 同時(shí)也能對(duì)元素內(nèi)容的認(rèn)知。

因用戶(hù)行為產(chǎn)生的新交互,應(yīng)當(dāng)與當(dāng)前用戶(hù)的行為相關(guān)。

2.1 點(diǎn)擊按鈕后呼起彈窗

用戶(hù)點(diǎn)擊按鈕后,會(huì)彈出一個(gè)彈窗,彈窗可以從按鈕所在的方向或者位置,彈出到整個(gè)頁(yè)面的中心。

JS如何讓你的移動(dòng)端交互體驗(yàn)更加優(yōu)秀

給到用戶(hù)的感受就是該彈窗與按鈕是相關(guān)的。

2.2 列表中有對(duì)象變動(dòng)時(shí)

例如在一個(gè)表格或者列表中,有新增、修改或者刪除一行(一列)的行為,可以用一個(gè)動(dòng)畫(huà)和背景色來(lái)區(qū)分該元素, 過(guò)一段時(shí)間再恢復(fù)正常。

JS如何讓你的移動(dòng)端交互體驗(yàn)更加優(yōu)秀

2.3 絲滑的滑動(dòng)跟隨

在不添加任何 CSS 屬性時(shí),滑動(dòng)有滾動(dòng)條區(qū)域時(shí),總感覺(jué)有一種卡頓感,就是手指滑動(dòng)時(shí)頁(yè)面就跟著滑動(dòng),手指離開(kāi)則頁(yè)面停止滑動(dòng)。

這里我們添加上一個(gè)屬性即可:

body { -webkit-overflow-scrolling: touch;}3. 考慮移動(dòng)設(shè)備的握持姿勢(shì)

在現(xiàn)在手機(jī)屏幕越來(lái)越大的趨勢(shì)下,單手握持手機(jī)時(shí),大模板只能在以左下角或者右下角為中心的區(qū)域活動(dòng)。因此,在底部區(qū)域操作的情況越來(lái)越多,例如底部區(qū)域的導(dǎo)航,彈窗中點(diǎn)擊空白區(qū)域即可關(guān)閉等等。

3.1 避免滾動(dòng)穿透

在一個(gè)可滾動(dòng)的頁(yè)面中,呼起一個(gè)彈窗,這個(gè)彈窗中的內(nèi)容也比較多,也需要滾動(dòng),如果不加處理的話,可能會(huì)造成兩個(gè)區(qū)域同時(shí)滾動(dòng),體驗(yàn)不好。也就是避免滾動(dòng)穿透。

這里我們就要把底層的滾動(dòng)鎖住,只可以滾動(dòng)處在最上層的區(qū)域。這里的原理我就不多講解,推薦一個(gè)我一直在使用的組件tua-body-scroll-lock,該組件導(dǎo)出了 2 個(gè)方法:

1.lock: 鎖定區(qū)域,傳入 dom 元素,則表示該 dom 區(qū)域內(nèi)是可以滾動(dòng)的;

2.unlock: 解除鎖定,當(dāng)彈窗消除時(shí),需要解除被鎖定的區(qū)域;

在 react 中的使用方式:

useEffect(() => { // 鎖定body的滾動(dòng),只在彈窗內(nèi)部滾動(dòng) // 只有需要設(shè)置可以滾動(dòng)區(qū)域時(shí),才使用該方法 if (props.scrollContainer) { lock(props.scrollContainer); } return () => { if (props.scrollContainer) { unlock(props.scrollContainer); } };}, [props.scrollContainer]);

同時(shí)的,我們最好在遮罩區(qū)域添加可以關(guān)閉彈窗的操作,避免用戶(hù)伸手夠彈窗右上角的關(guān)閉按鈕。

3.2 原生 select 標(biāo)簽的使用

在移動(dòng)端開(kāi)發(fā)中,下拉框我們使用原生 select 標(biāo)簽時(shí),iOS 和 Android 的表現(xiàn)是不一樣的,iOS 會(huì)出現(xiàn)在屏幕的底部,滾動(dòng)選擇某個(gè)選項(xiàng);而 Android 中,則是屏幕中間彈出一個(gè)彈層,然后可以進(jìn)行選擇。

JS如何讓你的移動(dòng)端交互體驗(yàn)更加優(yōu)秀

如果圖方便的話,其實(shí)可以使用原生的 select 標(biāo)簽。但這種方式,總感覺(jué)與頁(yè)面元素之間產(chǎn)生了割裂,因此如果可以的話,盡量模擬出一個(gè) select 標(biāo)簽。

4. 良好的兜底策略

每個(gè)用戶(hù)的設(shè)備型號(hào)、網(wǎng)絡(luò)狀態(tài)等情況都不一樣??倳?huì)因?yàn)楦鞣N各樣的原因,導(dǎo)致頁(yè)面展示異常。因此,我們應(yīng)當(dāng)做好提示和一些兜底策略。

4.1 全屏沉浸式頁(yè)面應(yīng)當(dāng)保持關(guān)閉操作

通常情況下,在移動(dòng)端 APP 中打開(kāi)的頁(yè)面,頂部都會(huì)有一個(gè)白色的標(biāo)題欄。但有些活動(dòng)頁(yè)面為了更好地沉浸式體驗(yàn),會(huì)把白色標(biāo)題欄去掉,同時(shí)還去掉了右劃退出的操作,只能點(diǎn)擊自定義的返回按鈕才能退出。

JS如何讓你的移動(dòng)端交互體驗(yàn)更加優(yōu)秀

例如這個(gè)頁(yè)面,左上角的返回按鈕是頁(yè)面本身自定義的。而這個(gè)頁(yè)面必須是接口正常返回?cái)?shù)據(jù)后才展示出來(lái),在最開(kāi)始時(shí),如果有異常時(shí),會(huì)展示錯(cuò)誤信息,但沒(méi)有返回按鈕。這就導(dǎo)致用戶(hù)無(wú)法退出該活動(dòng),只能殺掉 APP 再重新進(jìn)入。

體驗(yàn)非常不好,這里我們就要保證:全屏沉浸式頁(yè)面不管是哪種狀態(tài),應(yīng)當(dāng)全程保持關(guān)閉操作!

當(dāng)然,現(xiàn)在已經(jīng)沒(méi)有這個(gè)問(wèn)題了。

4.2 永遠(yuǎn)不要相信后臺(tái)一直很穩(wěn)定

后臺(tái)經(jīng)常說(shuō)的一句話是“不要相信任何從前端傳過(guò)來(lái)的數(shù)據(jù)”,我們也一樣:

永遠(yuǎn)不要相信后臺(tái)一直很穩(wěn)定。

我們要做好接口服務(wù)可能會(huì)掛掉的預(yù)案:

1.設(shè)置請(qǐng)求接口的超時(shí)時(shí)間,不要讓用戶(hù)無(wú)限制等待;

2.良好的提示;

3.有條件時(shí),可以自動(dòng)重試,或者讓用戶(hù)手動(dòng)嘗試重試請(qǐng)求接口;

4.采用兜底策略遮蓋;

前 3 種我們都可以理解,當(dāng)接口異常并無(wú)法繼續(xù)后續(xù)的操作時(shí),應(yīng)當(dāng)告知用戶(hù)有服務(wù)有異常了,可以稍后重試。

對(duì)于第 4 種,通??赡軙?huì)發(fā)生在高并發(fā)的抽獎(jiǎng)過(guò)程中,越是讓用戶(hù)重試,并發(fā)量就越高。因此在抽獎(jiǎng)異常時(shí),可以直接告訴用戶(hù)未中獎(jiǎng),而不是“服務(wù)異常”之類(lèi)的話術(shù)。要不然,一方面會(huì)引起用戶(hù)的不滿(mǎn),另一方面會(huì)造成用戶(hù)的大量重試。

這個(gè)百度在春晚發(fā)紅包中,就有用到過(guò),在服務(wù)器短時(shí)間內(nèi)承受到高并發(fā)量時(shí),則直接告訴用戶(hù)未抽中紅包;同時(shí),對(duì)于一些抽獎(jiǎng)會(huì)同時(shí)發(fā)放多個(gè)獎(jiǎng)品時(shí),也要做好每個(gè)獎(jiǎng)品服務(wù)都可以會(huì)掛掉的準(zhǔn)備,比如同時(shí)會(huì)發(fā)放 3 個(gè)獎(jiǎng)品:

1.服務(wù)都正常,正常發(fā)放;

2.2 個(gè)正常,就只發(fā)放 2 個(gè)獎(jiǎng)品,左右排列;

3.只有 1 個(gè)服務(wù)正常,則只發(fā)放 1 個(gè)獎(jiǎng)品,居中排列;

4.均異常,則告訴用戶(hù)未中獎(jiǎng);

千萬(wàn)不要留有空間或者槽位告訴用戶(hù)“該位置本應(yīng)該有獎(jiǎng)品,但實(shí)際上沒(méi)有”的感覺(jué)。

4.3 懶加載

懶加載是一個(gè)老生常談的話題,這里我們只針對(duì)圖片懶加載來(lái)進(jìn)行梳理。

在頁(yè)面中圖片比較多時(shí),請(qǐng)盡量使用圖片懶加載,并考慮好圖片加載失敗的情況,可以先創(chuàng)建一個(gè) Image 來(lái)先加載圖片,加載城后再給到頁(yè)面中的 dom 元素,否則使用兜底圖片:

// 判斷圖片是否可以加載成功const loadImage = (imgUrl: string): Promise<HTMLImageElement> => { return new Promise((resolve, reject) => { const img = new Image(); img.src = imgUrl; if (img.complete) { return resolve(img); } img.onload = () => { resolve(img); }; img.onerror = reject; });};// IntersectionObserver的回調(diào),當(dāng)dom元素進(jìn)入到可是區(qū)域內(nèi)時(shí)const targetExposeCallback = async (dom: HTMLElement) => { let original = dom.getAttribute(’data-original’); if (original) { try { await loadImage(original); } catch (err) { // 1x1的圖片 original = ’data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==’; } setLoading(false); if (dom.tagName.toLowerCase() === ’img’) { dom.setAttribute(’src’, original); } else { // eslint-disable-next-line dom.style.backgroundImage = `url('${original}')`; } dom.setAttribute(’data-original’, ’’); }};

同時(shí),我們?cè)隗w驗(yàn)的過(guò)程中發(fā)現(xiàn),在有些華為手機(jī)里,圖片還沒(méi)加載完畢時(shí),會(huì)展示一個(gè)裂開(kāi)的圖片,如果該圖片 alt 注釋?zhuān)舶?alt 注釋顯示出來(lái),稍過(guò)一會(huì)兒,等圖片加載完畢了,就正常展示圖片了。

這種情況,我們也可以使用圖片懶加載,或者將圖片設(shè)置為背景圖片,避免出現(xiàn)圖片裂開(kāi)的狀態(tài)。

5. 總結(jié)

我們?cè)谝苿?dòng)端開(kāi)發(fā)的過(guò)程中,總會(huì)有多種解決方案。如果我們站在用戶(hù)的角度多想一想,就能讓產(chǎn)品的交互體驗(yàn)變的更好。

以上就是JS如何讓你的移動(dòng)端交互體驗(yàn)更加優(yōu)秀的詳細(xì)內(nèi)容,更多關(guān)于JS讓你的移動(dòng)端交互體驗(yàn)更加優(yōu)秀的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: JavaScript
相關(guān)文章:
主站蜘蛛池模板: 91精品婷婷国产综合久久8 | 亚洲国产爱久久全部精品 | 国产一区二区三区免费播放 | 免费国产成人高清在线观看视频 | 黄色生活毛片 | 亚洲精品国产精品国自产 | 男人免费看片 | 欧美黄色片在线观看 | 日韩欧美国产偷亚洲清高 | 亚洲视频影院 | 日本美女视频韩国视频网站免费 | 日本japanesevideo护士 | 亚洲欲色 | 黄色毛片大全 | 国产女人成人精品视频 | 99久久久精品免费观看国产 | 在线观看国产一区亚洲bd | 免费国产成人综合 | 成人精品| 2022色婷婷综合久久久 | 免费国产网站 | 天堂婷婷| 在线观看国产日本 | 国产亚洲欧美日韩在线看片 | 亚洲wu码| 牛牛a级毛片在线播放 | 亚洲国产综合网 | 在线观看国产亚洲 | 国产草| 800玖玖爱在线观看香蕉 | 在线网站cosplay福利视频 | 成人在线免费观看网站 | 亚洲欧美日韩在线观看二区 | 久久精品乱子伦免费 | 大色香蕉色视频大全 | 免费无遮挡十八女禁污污网站 | 欧美精品久久久亚洲 | 国产精品女同一区二区久久夜 | 日本乱人伦片中文三区 | 欧美一级视频在线观看欧美 | 成人a毛片免费视频观看 |