自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

我們一起聊聊如何巧妙應(yīng)對(duì)iOS鍵盤難題?

移動(dòng)開發(fā) iOS
在移動(dòng)端上,我們的H5頁(yè)面一般是運(yùn)行在宿主APP提供的webview中,簡(jiǎn)單點(diǎn)理解,你其實(shí)可以把它當(dāng)作瀏覽器,就是用來(lái)展現(xiàn)頁(yè)面內(nèi)容的。目前移動(dòng)端主流系統(tǒng)分為Android與iOS,然而兩者提供的webview容器也存在著諸多差異,今天我們就只探討兩者軟鍵盤帶來(lái)的影響。

前言

寫過移動(dòng)端的同學(xué)或多或少都遇到過軟鍵盤帶來(lái)的各種各樣的問題,最典型的就是輸入框被軟鍵盤遮擋、fixed元素失效等問題,并且這些問題在iOS上的表現(xiàn)讓人難以接受。

webview的差異

在移動(dòng)端上,我們的H5頁(yè)面一般是運(yùn)行在宿主APP提供的webview中,簡(jiǎn)單點(diǎn)理解,你其實(shí)可以把它當(dāng)作瀏覽器,就是用來(lái)展現(xiàn)頁(yè)面內(nèi)容的。目前移動(dòng)端主流系統(tǒng)分為Android與iOS,然而兩者提供的webview容器也存在著諸多差異,今天我們就只探討兩者軟鍵盤帶來(lái)的影響。

首先,我們先來(lái)寫個(gè)簡(jiǎn)單的頁(yè)面布局:頭部fixed+中間自適應(yīng)+底部fixed

圖片圖片

Android

事實(shí)上Android的表現(xiàn)并不會(huì)有太大問題,它只不過是在鍵盤彈起來(lái)之后把webview的高度減小了,變成了:原來(lái)的webview高度減去鍵盤的高度

圖片圖片

這樣的表現(xiàn)正是我們期待的,完全沒有影響整個(gè)頁(yè)面的布局

iOS

軟鍵盤

在iOS 8.2 之后,iOS 唯一指定瀏覽器內(nèi)核、Webkit 鼻祖 Safari 將 fixed 元素的布局基準(zhǔn)區(qū)域從鍵盤上方的可見區(qū)域改成了鍵盤背后的整個(gè)視窗,也就是說(shuō)此時(shí)的webview高度并不會(huì)發(fā)生變化,鍵盤是直接蓋在webview上方的。

這樣是為了在鍵盤彈起來(lái)之后,不用重新渲染頁(yè)面,他們是方便了,但遭殃的是我們前端開發(fā)人員...

比如上面這個(gè)頁(yè)面,我們看看iOS的表現(xiàn)是怎樣的:

圖片圖片

可以看到,iOS為了不讓webview壓縮,并且為了不讓軟鍵盤遮擋輸入框,他們自作聰明地把webview整體往上移動(dòng),最大移動(dòng)距離為軟鍵盤的高度。

這樣就導(dǎo)致我們的頭部以及頁(yè)面上半部分內(nèi)容移動(dòng)到了可視區(qū)之外,這個(gè)表現(xiàn)是難以接受的,至少頭部應(yīng)該還要在可視區(qū)。(這就會(huì)讓我們誤以為fixed失效,實(shí)際上它相對(duì)于webview的位置并沒有變,只不過是webview發(fā)生了移動(dòng))

這個(gè)移動(dòng)似乎沒有邏輯,不信大家可以試試把輸入框放到頁(yè)面的各個(gè)位置,我發(fā)現(xiàn)只有輸入框在最頂部,webview才不會(huì)發(fā)生上移,其它位置都或多或少的會(huì)產(chǎn)生移動(dòng)。

還有一個(gè)問題就是,此時(shí)的webview是可以滑動(dòng)的,那么就會(huì)出現(xiàn)有用戶會(huì)將輸入框滑動(dòng)到鍵盤下方,想想這個(gè)體驗(yàn)也是難以接受的...

圖片圖片

并且你會(huì)發(fā)現(xiàn),在頁(yè)面的上方與下方都多出了一個(gè)不論是 Viewport 還是 VisualViewport 都無(wú)法到達(dá)的白色襯底區(qū)域,我們可以嘗試把頁(yè)面所有元素背景都改成黑色再來(lái)看,會(huì)更加明顯

圖片圖片

看到這些奇奇怪怪的問題你心里作何感想??

所有問題產(chǎn)生的根本原因是:iOS為了不用在鍵盤彈起之后重新渲染頁(yè)面,他們并沒有去壓縮webview容器的高度,而是對(duì)webview整體進(jìn)行平移處理

軟鍵盤監(jiān)聽

對(duì)于Android,我們通??梢酝ㄟ^監(jiān)聽resize事件來(lái)實(shí)現(xiàn),但對(duì)于iOS,我們從上面了解到鍵盤彈起,iOS的webview高度并不會(huì)發(fā)生變化,所以也就觸發(fā)不了resize事件。

在iOS中,可以通過focusin & focusout事件來(lái)進(jìn)行監(jiān)聽

export const watchKeyBoard = (callback: (isShow: boolean) => void) => {
  //  IOS
  if (isIOSByUA()) {
    document.body.addEventListener('focusin', () => {
      //軟鍵盤彈出的事件處理
      callback(true)
    })
    document.body.addEventListener('focusout', () => {
      //軟鍵盤收起的事件處理
      callback(false)
    })
  } else {
    //  Android
    const originalHeight =
      document.documentElement.clientHeight || document.body.clientHeight
    window.addEventListener('resize', () => {
      const resizeHeight =
        document.documentElement.clientHeight || document.body.clientHeight
      if (resizeHeight - 0 < originalHeight - 0) {
        // 鍵盤彈起事件
        callback(true)
      } else {
        // 鍵盤收起事件
        callback(false)
      }
    })
  }
}

解決方案

了解完產(chǎn)生問題的原因,我們就可以來(lái)嘗試著解決問題,但想要純前端去解決這個(gè)問題,或多或少都會(huì)存在一些體驗(yàn)問題,也許你可以去推動(dòng)你們的客戶端同學(xué)來(lái)協(xié)助處理這個(gè)問題,只要讓iOS的webview在鍵盤彈起時(shí)的表現(xiàn)與Android一致,就不會(huì)存在這些奇怪的問題了,但似乎他們處理起來(lái)也非常棘手...

模仿Android的處理

雖然我們改不了webview的高度,但我們可以改我們布局的高度,我們只需要將頁(yè)面高度改為頁(yè)面可視區(qū)的高度即可,如果頁(yè)面內(nèi)容有滾動(dòng)交互的話,需要額外處理,要與webview的滾動(dòng)隔離開。

VisualViewport

先來(lái)了解下這個(gè)API,它可以用來(lái)獲取對(duì)應(yīng) window 的視覺視口

  • VisualViewport.offsetLeft :返回視覺視口的左邊框到布局視口的左邊框的 CSS 像素距離。
  • VisualViewport.offsetTop:返回視覺視口的上邊框到布局視口的上邊框的 CSS 像素距離。
  • VisualViewport.pageLeft:返回相對(duì)于初始的 viewport 屬性的 X 軸坐標(biāo)所對(duì)應(yīng)的 CSS 像素?cái)?shù)。
  • VisualViewport.pageTop:返回相對(duì)于初始的 viewport 屬性的 Y 軸坐標(biāo)所對(duì)應(yīng)的 CSS 像素?cái)?shù)。
  • VisualViewport.width:返回視覺視口的寬度所對(duì)應(yīng)的 CSS 像素?cái)?shù)。
  • VisualViewport.height:返回視覺視口的高度所對(duì)應(yīng)的 CSS 像素?cái)?shù)。
  • VisualViewport.scale:返回當(dāng)前視覺視口所應(yīng)用的縮放比例。

這里我們需要的就是這個(gè)VisualViewport.height,用來(lái)獲取可視區(qū)的高度。

但需要注意的是,這個(gè)API最低只支持iOS13,ios13以下的使用window.innerHeight兜底

頁(yè)面布局

整體布局采用flex布局,頭部和底部也就不需要fixed來(lái)定位了,中間自適應(yīng)撐滿剩余高度,超長(zhǎng)滾動(dòng)

圖片圖片

鍵盤打開計(jì)算高度重新布局

我們需要在鍵盤彈起后,計(jì)算可視區(qū)的高度,并將最外層容器高度賦值為可視區(qū)高度

watchKeyBoard((status) => {
  setTimeout(() => {
    console.log(
      'status',
      status ? '鍵盤打開' : '鍵盤關(guān)閉',
    )
    const container = document.getElementById('container')
    if (status) {
      container.style.height = `${
      window.visualViewport.height || window.innerHeight
    }px`
      window.scrollTo(0, 0)
    } else {
      container.style.height = `100vh`
      document.removeEventListener('touchmove', this.stopMove)
    }
  }, 100)
})

這樣頁(yè)面展示算是正常了

圖片

但是隨之而來(lái)的是滾動(dòng)問題??

圖片圖片

處理滾動(dòng)

我們需要禁用全局的滾動(dòng),但對(duì)一些需要滾動(dòng)的區(qū)域需要放開,比如中間的列表部分

if (utils.isIOSByUA()) {
  watchKeyBoard((status) => {
    setTimeout(() => {
      console.log(
        'status',
        status ? '鍵盤打開' : '鍵盤關(guān)閉',
        window.innerHeight,
      )
      const container = document.getElementById('container')
      if (status) {
        container.style.height = `${
        window.visualViewport.height || window.innerHeight
      }px`
        window.scrollTo(0, 0)
        document.addEventListener('touchmove', this.stopMove, {
          passive: false,
        })
        document.addEventListener('touchend', this.scroll)
      } else {
        container.style.height = `100vh`
        document.removeEventListener('touchmove', this.stopMove)
        document.removeEventListener('touchend', this.scroll)
      }
    }, 100)
  })
}
stopMove(e) {
 // 排除可以滾動(dòng)的區(qū)域
  if (['content', 'keyboard_center'].includes(e.target?.className)) return
  e.preventDefault()
}
scroll() {
  window.scrollTo(0, 0)
}

完整體驗(yàn)如下

圖片圖片

比起它原本帶來(lái)的遮擋、滾動(dòng)、fixed失效等體驗(yàn),現(xiàn)在的體驗(yàn)算是可以接受的(這里所有的操作我們只需要在iOS上執(zhí)行即可)

責(zé)任編輯:武曉燕 來(lái)源: 前端南玖
相關(guān)推薦

2022-03-17 08:54:59

軟件系統(tǒng)重構(gòu)

2021-08-27 07:06:10

IOJava抽象

2024-02-20 21:34:16

循環(huán)GolangGo

2024-11-27 16:07:45

2024-09-30 09:33:31

2023-04-03 00:09:13

2024-09-09 00:00:00

編寫技術(shù)文檔

2023-08-04 08:20:56

DockerfileDocker工具

2022-05-24 08:21:16

數(shù)據(jù)安全API

2023-08-10 08:28:46

網(wǎng)絡(luò)編程通信

2023-09-10 21:42:31

2023-06-30 08:18:51

敏捷開發(fā)模式

2021-12-10 07:45:48

字節(jié)音頻視頻

2024-12-10 00:00:25

2022-02-14 07:03:31

網(wǎng)站安全MFA

2022-06-26 09:40:55

Django框架服務(wù)

2022-01-04 12:08:46

設(shè)計(jì)接口

2022-10-28 07:27:17

Netty異步Future

2023-04-26 07:30:00

promptUI非結(jié)構(gòu)化

2022-04-06 08:23:57

指針函數(shù)代碼
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)