coleava / me

1 stars 0 forks source link

小程序之tarojs框架实现下拉demo #23

Open coleava opened 2 years ago

coleava commented 2 years ago

import Taro, { Events } from "@tarojs/taro";
import { View, Text, Image } from "@tarojs/components";
import { AtCalendar } from 'taro-ui';
import "./index.css";
import _ from 'lodash';
const events = new Events();

export default class Select extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isShow: this.props.isShow || false,
      dataSource: this.props.dataSource || [{ value: '北京', label: '北京' }, { value: '上海', label: '上海' }, { value: '武汉', label: '深圳' }],
      currentValue: this.props.currentValue,
      leftIcon: this.props.icon,
      rightIcon: 'chevron-down',
      type: this.props.type,
      placeholder: this.props.placeholder,
      isClear: this.props.isClear || false,
      id: this.props.id
    };
  }

  componentDidMount() {
    Taro.eventCenter.on('closeSelect', () => {
      this.setState({ isShow: false })
    })
    Taro.eventCenter.on('clearSelect', this.clearCurrentValue)
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.dataSource !== this.props.dataSource) {
      this.setState({ dataSource: nextProps.dataSource })
    }
  }

  componentWillUnmount() {
    this.setState({ isShow: false, currentValue: this.props.currentValue, dataSource: this.props.dataSource })
  }

  selected = (item) => {
    let { isClear, isShow } = this.state;
    this.setState({ currentValue: item.value, isShow: !isShow, rightIcon: isClear ? 'close' : 'chevron-down' }, () => {
      if (this.props.selected) {
        this.props.selected(item);
      }
    })
  }

  openClose = (e) => {
    e.stopPropagation();
    if (e.mpEvent && e.mpEvent.target.id === 'close' || (e.target && e.target.id === 'close')) return;
    let { isShow, rightIcon, currentValue, isClear } = this.state;
    isShow = !isShow;
    this.setState({
      isShow,
      rightIcon: rightIcon === 'chevron-down' ? currentValue && isClear ? 'close' : 'chevron-up' : 'chevron-down'
    })
  }

  onCalendar = (e) => {
    this.setState({ currentValue: e.value, isShow: !this.state.isShow, rightIcon: 'chevron-down' }, () => {
      if (this.props.selected) {
        this.props.selected(e.value);
      }
    })
  }

  clearCurrentValue = () => {
    if (this.state.isClear) {
      this.setState({ currentValue: null, isShow: false, rightIcon: 'chevron-down' })
    }
  }

  render() {
    let { currentValue, dataSource, type, placeholder } = this.state;
    let source = _.find(dataSource, p => p.value === currentValue);

    let currentDate;
    if (type === 'calendar') {
      currentDate = currentValue.replace('年 ', '/');
      currentDate = currentDate.replace('月', '/');
      currentDate = currentDate.replace('日', '');
    }

    return <>
      <View className="select-box" style={this.props.boxStyle} >
        <View className="d-flex space-between" style={{ width: '100%', alignItems: 'center', height: '40px', zIndex: process.env.TARO_ENV === 'h5' ? 98 : '' }} onTouchStart={this.openClose}>
          <View className="d-flex align-items-center" style={{ marginLeft: '16px' }}>
            {/* <Image src={leftIcon} style={{ width: 24, height: 24 }} /> */}
            <Text className="current-name">{type !== 'calendar' ? (source ? source.label : placeholder) : currentValue}</Text>
          </View>
          <View className={`at-icon at-icon-${this.state.rightIcon}`} id='close'
            style={{ paddingRight: '15px', color: 'rgb(153, 153, 153)', fontSize: '20px' }} onClick={this.clearCurrentValue} />
        </View>
        {
          !type && this.state.isShow &&
          <View className='option-list' style={{ top: '44px', ...this.props.optionStyle }}>
            {
              this.state.dataSource.map((item, index) => {
                return <View
                  key={index}
                  onClick={() => this.selected(item)}
                  className="option"
                  style={{ color: currentValue === item.value ? '#007AFF' : '#7C7C7D' }}
                >{item.label}</View>
              })
            }
          </View>
        }
        {
          type === 'calendar' && this.state.isShow &&
          <View className="option-list" style={{ width: '100%', padding: '10px', top: '44px' }}>
            <AtCalendar format='YYYY年 M月D日' currentDate={currentDate} onDayClick={this.onCalendar} />
          </View>
        }
      </View>
      <View className='select-box-mask' onClick={this.openClose} style={{ display: !this.state.isShow ? 'none' : '' }} />
    </>
  }
}
coleava commented 2 years ago

css部分


  position: relative;
  /* width: 350px; */
  font-size: 30px;
  height: 60px;
  border-radius: 13px;
  border: 1px solid #DEDEE0;
  background-color: #fff;
  display: flex;
  align-items: center;
}

.select-current {
  position: relative;
  width: 100%;
  padding: 0 10px;
  line-height: 70px;
}

.select-current::after {
  position: absolute;
  display: block;
  right: 16px;
  top: 30px;
  content: '';
  width: 0;
  height: 0;
  border: 10px solid transparent;
  border-top: 10px solid #999;
}

.current-name {
  padding: 20rpx;
  line-height: 60rpx;
  word-wrap: normal;
  overflow: hidden;
  text-align: center;
  color: #7C7C7D;
}

.option-list {
  position: absolute;
  left: 0;
  height: 480px;
  overflow-y: scroll;
  /* padding: 12rpx 20rpx 10rpx 20rpx; */
  border-radius: 20px;
  box-sizing: border-box;
  z-index: 99;
  box-shadow: 0px 0px 1px 1px rgba(0, 0, 0, 0.2) inset;
  background-color: #fff;
}

.option {
  display: block;
  /* width: 100%; */
  line-height: 60px;
  padding: 5px 20px;
  /* border-bottom: 1rpx solid #eee; */
}

.option:last-child {
  border-bottom: none;
  padding-bottom: 0;
}

.select-box-mask {
  position: fixed;
  left: 0;
  top: 0;
  bottom: 0;
  right: 0;
  width: 100%;
  height: 100%;
  z-index: 5;
}