視訊h5嵌入頁專案總結

weixin_34402408發表於2018-08-22

開始

最近做了一個關於視訊的嵌入頁(嵌入頁是分享頁的加強版)的需求,主要涉及h5視訊元件定製化,評論列表鍵盤輸入遮擋,還有一些js跟客戶端互動問題,跟大家交流下公司h5嵌入頁的開發流程。

需求

  1. 實現一個自定義的視訊播放器,滑動置頂,難點:(視訊定製化,相容性,事件互動)
  2. 評論列表頁,包括列表展示,評論回覆,點贊。難點:(邏輯複雜、客戶端互動複雜)
  3. 底部評論發表功能。難點:(鍵盤遮擋問題)

效果圖:



除錯工具

  1. webview除錯技巧:因為我們的頁面需要很多客戶端環境提供支援(包括引數加簽,呼叫客戶端方法等等),所以以往一樣在Chrome裡除錯是行不通的,所以我們要把我們的除錯頁面嵌入到客戶端,但是又想做到跟本地Chrome除錯一樣可以實時更新程式碼,實時看到效果,最好還能擁有Chrome一樣的控制檯。

1.針對第一點可以這樣做:在本地起一個服務,比如localhost:3000,找到自己電腦的ip,比如:192.168.5.102,然後把 http://192.168.5.102:3000這個url告訴客戶端,讓他們配合偽造一個入口(需要的引數從url後獲取),這樣就可以實現實時更新程式碼,實時看到效果,跟本地除錯效果一樣
2.使用手機除錯工具,我使用的事騰訊提供的 vconsole,可以實現一個簡單的類似Chrome的控制檯效果


  1. 網路代理跟抓包工具:推薦使用charles,可以方便地實現網路代理跟介面的抓包,定位網路的問題

難點一:視訊定製化

解決方案:由於video標籤相容性複雜,寫法多樣,我的做法是使用比較流行的video庫,基本可以解決基本的相容問題,之後要考慮的只有在此基礎上自定義controllerBar,利用video庫本身就提供的一些事件監聽,可以簡單有效的實現自定義video。因為開發使用的是react,所以我使用的是star比較多,文件比較全的video-react

難點二:無線列表滾動及常用元件的使用

這些常用的功能已經有很多成熟的元件庫為我們做好了,因為用的react,所以用了ant-mobile,有時候會需要自定義主題,參考這個,不重複造輪子 https://mobile.ant.design/docs/react/customize-theme-cn

難點三:鍵盤問題

鍵盤問題具體體現在以下幾個問題:

  1. position:fixed,會出現如下問題


  2. 輸入框被鍵盤遮擋問題:


針對以上問題提出解決方案: 

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. 介面加簽引數獲取
  2. 分享

原理: 

1.js呼叫客戶端方法:客戶端會把交給js呼叫的方法掛載在js的window物件上,呼叫的時候 window.fn() 

客戶端呼叫js方法:跟客戶端預定好方法,然後再js的window物件上定義方法:如下:

window.continuePlay = function() {
    const player = document.getElementsByTagName('video')[0]
    return player?player.play():null
}
複製程式碼
  1. 使用庫 bbtNative:原理同上,提供了小時光跟孕育的一些公用方法,大家自行看文件。有一下使用注意事項:

1.客戶端方法會在頁面載入完之後才會把方法掛載在webview上,這個時間會根據不同機型而不同,iOS快,Android慢,所以馬上獲取資料的話,需要一個定時器,否則無法獲取加簽引數

componentDidMount() {
    Toast.loading('', 12)
    setTimeout(()=>{
       this.fetchData()
       this.fetchDetail() 
    }, 1000)
   
  }
複製程式碼

2.其中遇到一個比較坑的問題,bbtNative.encryptApi,這個加簽函式安卓機無法返回加簽值,後面去看了下bbtNative庫的原始碼,發現了一些問題,改了原始碼之後已經可以獲取加簽值,但目前生慶哥還沒驗證,所以gitlab上的庫還是存在問題,要是大家以後使用遇到類似問題可以與我討論

收穫

做了這個專案還是收穫頗多的

  1. 對公司專案的開發流程更加清晰明確
  2. 對h5於在webview中於原生語言互動有了大概的瞭解
  3. 創新了一種h5鍵盤遮擋的有效方案
  4. 能夠認識ios開發跟Android開發程式設計師(為之後我要入手公司的rn專案打下基礎)


相關文章