開始
最近做了一個關於視訊的嵌入頁(嵌入頁是分享頁的加強版)的需求,主要涉及h5視訊元件定製化,評論列表鍵盤輸入遮擋,還有一些js跟客戶端互動問題,跟大家交流下公司h5嵌入頁的開發流程。
需求
- 實現一個自定義的視訊播放器,滑動置頂,難點:(視訊定製化,相容性,事件互動)
- 評論列表頁,包括列表展示,評論回覆,點贊。難點:(邏輯複雜、客戶端互動複雜)
- 底部評論發表功能。難點:(鍵盤遮擋問題)
效果圖:
除錯工具
- webview除錯技巧:因為我們的頁面需要很多客戶端環境提供支援(包括引數加簽,呼叫客戶端方法等等),所以以往一樣在Chrome裡除錯是行不通的,所以我們要把我們的除錯頁面嵌入到客戶端,但是又想做到跟本地Chrome除錯一樣可以實時更新程式碼,實時看到效果,最好還能擁有Chrome一樣的控制檯。
1.針對第一點可以這樣做:在本地起一個服務,比如localhost:3000,找到自己電腦的ip,比如:192.168.5.102,然後把 http://192.168.5.102:3000這個url告訴客戶端,讓他們配合偽造一個入口(需要的引數從url後獲取),這樣就可以實現實時更新程式碼,實時看到效果,跟本地除錯效果一樣
2.使用手機除錯工具,我使用的事騰訊提供的 vconsole,可以實現一個簡單的類似Chrome的控制檯效果
- 網路代理跟抓包工具:推薦使用charles,可以方便地實現網路代理跟介面的抓包,定位網路的問題
難點一:視訊定製化
解決方案:由於video標籤相容性複雜,寫法多樣,我的做法是使用比較流行的video庫,基本可以解決基本的相容問題,之後要考慮的只有在此基礎上自定義controllerBar,利用video庫本身就提供的一些事件監聽,可以簡單有效的實現自定義video。因為開發使用的是react,所以我使用的是star比較多,文件比較全的video-react
難點二:無線列表滾動及常用元件的使用
這些常用的功能已經有很多成熟的元件庫為我們做好了,因為用的react,所以用了ant-mobile,有時候會需要自定義主題,參考這個,不重複造輪子 https://mobile.ant.design/docs/react/customize-theme-cn
難點三:鍵盤問題
鍵盤問題具體體現在以下幾個問題:
- position:fixed,會出現如下問題
- 輸入框被鍵盤遮擋問題:
針對以上問題提出解決方案:
1.用absolute代替fixed
2.scrollIntoView來自動讓元素出現在可視區域
思路:用absolute代替fixed,建立一層寬高100%的蒙版,每次喚起鍵盤的時候記錄當前滾動條高度(因為之後要回滾),然後將scrolltop設定為0,滾動到最上方,同時喚出蒙版層,為了保證input能夠出現在可視區下邊緣,對輸入元件用scrollIntoView(false),讓其自動出現在鍵盤上方,如圖:
然後我們要阻止觸控滾動,用了生慶哥共享的程式碼,然後我們在傳送評論之後以及點選蒙版之後,回滾到之前的位置,同時隱藏蒙版跟輸入框。
禁止觸控滾動程式碼
export function disableScroll() {
if (window.addEventListener) // older FF
window.addEventListener('DOMMouseScroll', preventDefault, false);
window.onwheel = preventDefault; // modern standard
window.onmousewheel = document.onmousewheel = preventDefault; // older browsers, IE
window.ontouchmove = preventDefault; // mobile
document.onkeydown = preventDefaultForScrollKeys;
}
export function enableScroll() {
if (window.removeEventListener)
window.removeEventListener('DOMMouseScroll', preventDefault, false);
window.onmousewheel = document.onmousewheel = null;
window.onwheel = null;
window.ontouchmove = null;
document.onkeydown = null;
}
var keys = {37: 1, 38: 1, 39: 1, 40: 1};
function preventDefault(e) {
e = e || window.event;
if (e.preventDefault)
e.preventDefault();
e.returnValue = false;
}
function preventDefaultForScrollKeys(e) {
if (keys[e.keyCode]) {
preventDefault(e);
return false;
}
}
複製程式碼
鍵盤元件程式碼
export default class Dialog extends React.Component {
constructor() {
super()
const doc = window.document;
this.node = doc.createElement('div');
doc.body.appendChild(this.node);
}
componentDidMount() {
this.textArea.focus()
this.scrollTop = document.body.scrollTop // 記錄滾動條位置
document.body.scrollTop = 0
/* 每次喚起鍵盤都要將頁面滾動到最頂端,
這是因為我們用的是position:absolute, top: 0;left:0;right: 0;bottom: 0;
這個元件只出現在頁面頂部,這是用絕對定位代替固定定位的關鍵*/
}
onFocus = (e) => {
setTimeout(() => {
if(this.submit) {
this.submit.scrollIntoView(false)
/* 這裡一定要用false,剛好是它滾動到鍵盤下邊緣,
為什麼要用setTimeout?因為鍵盤喚起有延時,特別是某些機型的安卓機 */
}
}, 0);
}
maskClcik = (ifScrollTop) => {
document.body.scrollTop = ifScrollTop ? 0 : this.props.scrollTop // 蒙版點選恢復到之前的滾動條高度
this.props.focusHandle()
}
....
render() {
return createPortal( // 試了一下react v16的傳送門,還挺好用的
<div className="dialog" onClick={()=>this.maskClcik(false)}>
<div className="share-bottom-fixed" ref={(dom)=>this.submit=dom}>
<TextareaItem
onFocus={(e)=>this.onFocus(e)}
// onBlur={this.maskClcik}
ref={(dom)=>this.textArea=dom}
onChange={this.onChange}
autoHeight={true}
value={this.props.commentContent}
className="write-comment"
placeholder={this.props.reviewType === 3 ? '回覆'+this.props.reviewNickName:'寫評論'} />
<span className='submit' onClick={(e)=>this.submitHandle(e)}>傳送</span>
</div>
</div>, //塞進傳送門的JSX
this.node //傳送門的另一端DOM node
);
}
componentWillUnmount() {
window.document.body.removeChild(this.node);
}
}
複製程式碼
總結:
1.用絕對定位跟滾動條滾動到頂部的方法模仿固定定位
2.利用scrollIntoView(新屬性,移動端相容性良好) 使其每次都能自動出現在鍵盤上方
下面是ios跟安卓的實現效果圖
難點四:客戶端互動問題
1.評論區存在很多與客戶端互動的需求(包括跳轉小家、跳轉評論列表、舉報等等)
- 介面加簽引數獲取
- 分享
原理:
1.js呼叫客戶端方法:客戶端會把交給js呼叫的方法掛載在js的window物件上,呼叫的時候 window.fn()
客戶端呼叫js方法:跟客戶端預定好方法,然後再js的window物件上定義方法:如下:
window.continuePlay = function() {
const player = document.getElementsByTagName('video')[0]
return player?player.play():null
}
複製程式碼
- 使用庫 bbtNative:原理同上,提供了小時光跟孕育的一些公用方法,大家自行看文件。有一下使用注意事項:
1.客戶端方法會在頁面載入完之後才會把方法掛載在webview上,這個時間會根據不同機型而不同,iOS快,Android慢,所以馬上獲取資料的話,需要一個定時器,否則無法獲取加簽引數
componentDidMount() {
Toast.loading('', 12)
setTimeout(()=>{
this.fetchData()
this.fetchDetail()
}, 1000)
}
複製程式碼
2.其中遇到一個比較坑的問題,bbtNative.encryptApi,這個加簽函式安卓機無法返回加簽值,後面去看了下bbtNative庫的原始碼,發現了一些問題,改了原始碼之後已經可以獲取加簽值,但目前生慶哥還沒驗證,所以gitlab上的庫還是存在問題,要是大家以後使用遇到類似問題可以與我討論
收穫
做了這個專案還是收穫頗多的
- 對公司專案的開發流程更加清晰明確
- 對h5於在webview中於原生語言互動有了大概的瞭解
- 創新了一種h5鍵盤遮擋的有效方案
- 能夠認識ios開發跟Android開發程式設計師(為之後我要入手公司的rn專案打下基礎)