ReactNative ActionSheet的封裝

最近要用到一個(gè)選擇菜單,由于nuke自帶的樣式不符合項(xiàng)目的統(tǒng)一樣式規(guī)范,所以自己抽了一個(gè)出來,關(guān)鍵代碼是動(dòng)態(tài)向body插入子元素以及transition效果的實(shí)現(xiàn)。


IMG_3826.PNG

調(diào)用示例:

const data = {
    onSale:'出售中',
    inventory:'倉(cāng)庫(kù)中',
    all:'全部'
}
ActionSheet.select(data).then(result=>{
      //result:{key:'onSale',value:'出售中'}
})

1-16優(yōu)化,選項(xiàng)過多超過一屏后顯示滾動(dòng)列表,高度響應(yīng)qap安卓鍵盤呼出關(guān)閉
組件實(shí)現(xiàn):

/**
 * Actionsheet
 * 下拉動(dòng)作菜單
 * @author lxy
 */
import {createElement, PureComponent, render, unmountComponentAtNode} from 'rax';
import {View, Text, TouchableHighlight, Dimensions,ScrollView} from 'nuke';
import style from './style.less'
import QN from 'QAP-SDK'
import doTransition from "$util/PyTransition";

let {height, width} = Dimensions.get(`screen`)//獲取屏幕寬高
let pureHeight = height / (width / 750) - 200 / (width / 750) //根據(jù)比例計(jì)算屏幕真實(shí)高度
let keyBoardHeight = 0 //鍵盤高度
if (!QN.os.ios) {
  QN.on('Global.KeyboardWillShow', ({height}) => {
    keyBoardHeight = height
    Actionsheet.updateHeight() //重新計(jì)算組件高度
  })
  QN.on('Global.KeyboardWillHide', () => {
    keyBoardHeight = 0
    Actionsheet.updateHeight()
  })
}

export default class Actionsheet extends PureComponent {
  /**
   *
   * @param data eg:{onSale:`出售中`,out:`已售完`}
   * @returns {Promise<any>}
   */
  static select(data) {
    if (!SelectDown.isExist) {
      Actionsheet.isExist = true;//單例模式,同一頁面只允許存在一個(gè)實(shí)例
      Actionsheet.dom = document.createElement('div');//頁面渲染節(jié)點(diǎn)
      document.body.appendChild(Actionsheet.dom);//將dom節(jié)點(diǎn)插入document
      render('<SelectDown data={data}/>', Actionsheet.dom);//渲染組件到dom節(jié)點(diǎn)中
      return new Promise((resolve, reject) => {
        Actionsheet.promise = {resolve, reject}//回調(diào)promise
      })
    }
  }

  componentDidMount() {
    const option = {
      timingFunction: 'ease-in-out',
      delay: 0,
      duration: 200
    }
    //初始化動(dòng)畫效果,遮罩層由透明變?yōu)?.5,body區(qū)域內(nèi)容從最底部上滑
    doTransition(this.refs.side, {transform: `translateY(${-Actionsheet.bottom - 10})`}, option)//10 marginBottom
    doTransition(this.refs.mask, {backgroundColor: 'rgba(0,0,0,0.5)'})
  }
  constructor(props) {
    let {data} = props
    super(props);
    let map = new Map();
    for (let k of Object.keys(data)) {//存儲(chǔ)選擇數(shù)據(jù)
      map.set(k, data[k]);
    }
    this.state = {
      map,
      showSide: false,
      remainHeight:pureHeight-keyBoardHeight,
      allHeight:(map.size + 1) * 114 + 16,////計(jì)算組件高度,(數(shù)據(jù)長(zhǎng)度+取消)*114+取消marginTop
    }
   Actionsheet.instance=this
    const {remainHeight,allHeight} = this.state
    Actionsheet.bottom = remainHeight>allHeight?allHeight:remainHeight
  }
  destroy() {
    unmountComponentAtNode(SelectDown.dom)//銷毀react實(shí)例
    document.body.removeChild(SelectDown.dom)//移除dom節(jié)點(diǎn)
    Actionsheet.isExist = false//銷毀組件
  }

  chooseItem({key, value}) {
    Actionsheet.promise.resolve({key, value})//處理選擇事件
    this.destroy()
  }
//渲染選項(xiàng)列表
  renderBody = () => {
    let self = this;
    let list = []
    let i = 0;
    for (let [key, values] of this.state.map.entries()) {
      let ownStyle;
      if (i == 0) {//處理首尾選項(xiàng)邊框
        ownStyle = styles.topBorder
      }
      if (i == this.state.map.size - 1) {
        ownStyle = styles.bottomBorder
      }
      list.push(
        <TouchableHighlight key={key} style={[style.content, ownStyle, i != 0 ? styles.border : '']}
                            onPress={this.chooseItem.bind(self, {key, value: values})}>
          <Text style={style.text}>
            {values}
          </Text>
        </TouchableHighlight>
      )
      i++;
    }
    const {remainHeight,allHeight} = this.state
    //屏幕剩余高度大于選項(xiàng)高度,顯示選項(xiàng)實(shí)際高度,否則顯示屏幕剩余高度
    const height = remainHeight>allHeight?allHeight:remainHeight
    return (
      <View ref="side" style={[style.bottom, {bottom: -Actionsheet.bottom,height:height}]}>
        <ScrollView style={style.list}>
          {list}
        </ScrollView>
        <TouchableHighlight style={style.cancle} onPress={this.destroy}>
          <Text style={style.textCancle}>取消</Text>
        </TouchableHighlight>
      </View>
    )
  }

  render() {
    return (
      <View ref='mask' onClick={this.destroy} style={[style.container, {height: height}]}>
        {this.renderBody()}
      </View>
    )
  }
}
Actionsheet.isExist = false
Actionsheet.updateHeight=function(){ //更新屏幕剩余高度
  Actionsheet.instance&& Actionsheet.instance.setState({
    remainHeight: pureHeight-keyBoardHeight
  })

}
const styles = {
  topBorder: {
    borderTopRightRadius: '10rem',
    borderTopLeftRadius: '10rem',
    height:'104rem'
  },
  bottomBorder: {
    borderBottomRightRadius: '10rem',
    borderBottomLeftRadius: '10rem',
    height:'104rem'
  },
  border: {
    borderTopWidth: '1rem',
    borderTopColor: '#DCDEE3'
  }
}

style.less

.container{
  width: 750rem;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  background-color: rgba(0,0,0,0);
  position: fixed;
  bottom: 0;
}
.bottom{
  width: 750rem;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
  position: fixed;
}
.cancle{
  margin-top: 16rem;
  width: 710rem;
  justify-content: center;
  align-items: center;
  height: 114rem;
  background-color: #fff;
  border-radius: 10rem;
}
.content{
  width: 710rem;
  justify-content: center;
  align-items: center;
  height: 114rem;
  background-color: #fff;
}
.list{
  width: 710rem;
  background-color: #fff;
  border-radius: 10rem;
  justify-content: flex-start;
  align-items: center;
  padding-top: 10rem;
  padding-bottom: 10rem;
}
.text{
  font-family: MicrosoftYaHei;
  width: 710rem;
  font-size: 32rem;
  color: #333333;
  text-align: center;
}
.textCancle{
  font-family: MicrosoftYaHei;
  width: 710rem;
  font-size: 32rem;
  color: #F54531;
  text-align: center;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容