视频h5嵌入页项目总结

519 阅读6分钟

开始

最近做了一个关于视频的嵌入页(嵌入页是分享页的加强版)的需求,主要涉及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项目打下基础)