手机选择城市组件

2020-02-22  本文已影响0人  sweetBoy_9126

点击弹出弹窗

const CitySelect: React.FunctionComponent = (props) => {
  const [dialogVisible, setDialogVisible] = useState(false)
  const onClick = () => {
    setDialogVisible(true)
  }
  const onClose = () => {
    setDialogVisible(false)
  }
  return (
    <>
      <div onClick={onClick}>{props.children}</div>
      {dialogVisible && <Dialog onClose={onClose}/>}
    </>
  )
}
const Dialog: React.FC<{onClose: () => void}> = (props) => {
  return ReactDOM.createPortal((
    <div className={"ireact-citySelect-dialog"} onClick={props.onClose}>
      弹出内容
    </div>
  ), document.body)
}

查询当前位置模块

const Dialog: React.FC<{onClose: () => void}> = (props) => {
  return ReactDOM.createPortal((
    <div className={"ireact-citySelect-dialog"} onClick={props.onClose}>
      <header>
        <Icon name={"left"}/>
        <span>选择城市</span>
      </header>
      <CurrentLocation/>
      <h2>全部城市</h2>
      <div className="cityIndex">ABCD...</div>
      <div className="cityList">所有城市</div>
    </div>
  ), document.body)
}
const CurrentLocation: React.FC = () => {
  const [city, setCity] = useState<string>('加载中...')
  useEffect(() => {
    const xhr = new XMLHttpRequest()
    xhr.open('get', 'http://ip-api.com/json/?lang=zh-CN')
    xhr.onload = () => {
      const string = xhr.responseText
      const obj = JSON.parse(string)
      const C = obj.city
      setCity(C)
    }
    xhr.send()
    xhr.onerror = () => {
      setCity('未知')
    }
  }, [])
  return (
    <div className={"currentCity"}>
      {city}
    </div>
  )
}

数据列表处理

这里我们使用写死的城市数据,然后引入一个tiny-pinyin库来讲城市的首字母取出来

import pinyin from 'tiny-pinyin'
interface Prop {
  dataSource: string[]
}
const CitySelect: React.FunctionComponent<Prop> = (props) => {
  const lists: {[key: string]: string[]} = {}
  props.dataSource.map((city) => {
    const py = pinyin.convertToPinyin(city)
    const index = py[0]
    lists[index] = lists[index] || []
    lists[index].push(city)
  })
}

使用Context将城市数据传给dialog

interface Context {
  lists: {[key: string]: string[]}
}
const CityContext = createContext<Context>({lists: {a: []}})
const CitySelect: React.FunctionComponent<Prop> = (props) => {
  const lists: Context['lists'] = {}
  return (
    <CityContext.Provider value={{lists}}>
      <div onClick={onClick}>{props.children}</div>
      {dialogVisible && <Dialog onClose={onClose}/>}
    </CityContext.Provider>
  )
}
const Dialog: React.FC<{onClose: () => void}> = (props) => {
  const {lists} = useContext(CityContext)
  const indexList = Object.keys(lists).sort()
  return ReactDOM.createPortal((
    <ol className="ireact-citySelect-index">
        {indexList.map(a => <li key={a}>{a}</li>)}
      </ol>
  ))

渲染字母和对应城市

将之前的lists对象里的key和value结构转换成数组结构,数组里面的每一项还是数组,第一项是key,第二项是对应的value,我们可以使用Object.entries()

// 转换后根据第一项也就是字母进行排序每一项,因为每一项的第零项都是字符串
// 所以需要用charCodeAt转换成number
const cityList = Object.entries(lists).sort(
    (a, b) => a[0].charCodeAt(0) - b[0].charCodeAt(0)
  )
<div className="cityList">
        {cityList.map(([letter, list]) =>
          <div key={letter} className={"ireact-citySelect-cityList"}>
            <h4>{letter}</h4>
            <ol>
              {list.map(city =>
                <li key={city}>{city}</li>
              )}
            </ol>
          </div>
        )}
      </div>
上一篇下一篇

猜你喜欢

热点阅读