實現貼邊懸浮可拖動的交互效果

最新更新時間:2019年10月15日09:51:32

《猛戳-查看我的博客地圖-總有你意想不到的驚喜》

本文內容:一般情況下,在應用的首頁,會有一個貼邊的、懸浮的、可拖動的按鈕,用來快速進入具體的某個頁面,或者用來調起客服,或者其他信息。

概述

本文使用 react 框架,採用組件化方案實現這個交互效果,並且完全兼容 Android 和 iOS 雙端。尤其是針對 iOS 端,當頁面滾動到上下邊界時出現的橡皮筋效果,也做了很好的處理。方案簡單易懂,希望大家參考和學習。

父組件

import React from 'react'
import Child from './Child'
export default class Parent extends React{

  constructor(props){}

  componentDidMount() {}

  render(){
    return <div id='parent' className={styles.container}>
    	<Child/>
    </div>
  }

子組件

此處的小助手是可拖動的的這個子組件

import React from 'react'
export default class Child extends React.PureComponent{

  constructor(props){
    super(props);
    this.state = {}
    this.relativeY = 0;//手指觸摸 小助手 的點距離該元素頂部的距離
    this.reachTop = false;//移動 小助手 是否超過屏幕頂部
    this.reachBottom = false;//移動 小助手 是否超過屏幕底部
    this.childtDom = null;
    this.html = null;
  }

  componentDidMount() {
    let _this = this;
    this.childtDom = document.getElementById('child');
    this.html = document.documentElement;
    //頁面初始化 禁止body滾動-iOS頁面上下滾動的橡皮筋效果
    //如果使用 touchstart childtDom上的onClick事件失效
    document.body.addEventListener('touchmove', _this.preventScroll, {passive: false});
    //開始觸摸parent 解除body滾動
    document.getElementById('parent').addEventListener('touchstart', function (e) {
      //觸摸的元素不是小助手 解除禁止body滾動
      //觸摸的元素是小助手 body處於禁止滾動狀態
      if(e.target.id != 'child'){
        document.body.removeEventListener('touchmove', _this.preventScroll);
      }
    }, {passive: false});
    //觸摸parent結束 禁止body滾動-iOS頁面上下滾動的橡皮筋效果
    document.getElementById('parent').addEventListener('touchend', function () {
      document.body.addEventListener('touchmove', _this.preventScroll, {passive: false});
    }, {passive: false});
  }

  componentWillUnmount() {
    //組件卸載-卸載事件
    document.body.removeEventListener('touchmove', this.preventScroll);
  }

  /**
   * 手指放在 小助手 上移動
   * @param event
   * @return
   */
  onTouchMove(e){
    let clientY = e.touches[0].clientY;//手指觸摸屏幕的點距離文檔頂部的距離 文檔總高度可能會超過屏幕高度
    let smallAssistantTop = clientY + this.relativeY;//小助手 相對屏幕頂部絕對定位的距離
    this.childtDom.style.top = smallAssistantTop + 'px'
    if(smallAssistantTop < 0){
      this.reachTop = true;
    }
    if(smallAssistantTop > this.html.offsetHeight - 70){
      this.reachBottom = true;
    }
  }

  /**
   * 手指放在 小助手
   * @param event
   * @return
   */
  onTouchStart(e){
    this.relativeY = e.target.offsetTop - e.touches[0].clientY
  }

  /**
   * 手指離開 小助手
   * @param event
   * @return
   */
  onTouchEnd(){
    if(this.reachTop){
      this.childtDom.style.top = 0 + 'px'
      this.reachTop = false;
    }
    if(this.reachBottom){
      this.childtDom.style.top = this.html.offsetHeight - 70 + 'px'
      this.reachBottom = false;
    }
  }

  /**
   * 阻止頁面滾動
   * @param
   * @return
   */
  preventScroll(e){
    e.preventDefault();
  }
  
  render(){
    return <div
      id='child'
      style={{position:'fixed',bottom:'100px',width:'70px',height:'70px'}}
      onTouchMove={(e)=>{this.onTouchMove(e)}}
      onTouchStart={(e)=>{this.onTouchStart(e)}}
      onTouchEnd={(e)=>{this.onTouchEnd(e)}}
    >
      <img style={{width:'100%',height:'100%',pointerEvents:'none'}} src={require('./a.gif')}/>
    </div>
  }
}

參考資料

感謝閱讀,歡迎評論^-^

打賞我吧^-^

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章