美文网首页
手机选择城市组件

手机选择城市组件

作者: sweetBoy_9126 | 来源:发表于2020-02-22 15:50 被阅读0次

    点击弹出弹窗

    • citySelect.tsx
    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>
    

    相关文章

      网友评论

          本文标题:手机选择城市组件

          本文链接:https://www.haomeiwen.com/subject/alulqhtx.html