<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
級聯選單分為兩部分:head與body。
包含兩部分:已選項列表,候選選單
已選項列表
候選選單
├─ src │ ├─ App.js │ ├─ components │ │ └─ Cascader │ │ ├─ CascaderContent // content部分 │ │ │ ├─ CascaderContent.js │ │ │ └─ style.js │ │ ├─ CascaderHead // head部分 │ │ │ ├─ CascaderHead.js │ │ │ └─ style.js │ │ ├─ index.js // 入口 │ │ ├─ style.js │ │ ├─ Cascader.js │ │ └─ testData // 測試資料 │ │ └─ data.js │ ├─ index.css │ └─ index.js
levels
根據資料來源dataSource與value生成一個陣列,資料結構如下。
陣列的長度為已選項數加一,最大為資料來源的最大深度
onChange
點選選單項,如果為不可選狀態,則return。如果有onSelect回撥,則將已選的value傳遞給回撥函數
value
初始化的時候,value為預設值,後面在此基礎上進行修改
loading
有時候資料可能是非同步請求獲取的,增加一個定時器,可以在資料未載入完的時候,顯示loading效果。
tabActiveIndex
當前候選的選單的索引,,選中一項後,值加一,如果已經選到了最大深度,那麼索引為最後一頁。
classPrefix
是一個變數,方便設定公共變數
import React, { useMemo, useState } from "react"; import { useCallback, useEffect } from "react"; import { Wrapper } from "./style"; const classPrefix = `antdm-cascader-view` export const CascaderContent = function ({ visible = false, ...props }) { // 當前頁 const [tabActiveIndex, setTabActiveIndex] = useState(0); // 初始值 const [value, setValue] = useState(props.value || props.defaultValue || []); // loading效果 const [loading, setLoading] = useState(true); const levels = useMemo(() => { const ret = [] let currentOptions = props.options let reachedEnd = false for (const v of value) { const target = currentOptions.find(option => option.value === v) ret.push({ selected: target, options: currentOptions, }) // 沒有下一項的時候中止遍歷 if (!target || !Array.isArray(target.children) || target.children.length === 0) { reachedEnd = true break } currentOptions = target.children } if (!reachedEnd) { ret.push({ selected: undefined, options: currentOptions, }) } return ret; }, [props.options, value]) // 點選選項的時候 const onChange = useCallback((item, index) => { if (item?.disabled) { return } const newValue = [...value.slice(0, index), item.value]; setValue(newValue); props.onSelect?.(newValue) }, [value, props.onSelect]) // 選中資料後,切換下一級選單 useEffect(() => { const max = levels.length - 1 if (tabActiveIndex > max) { setTabActiveIndex(max) } }, [tabActiveIndex, levels]) useEffect(() => { setTabActiveIndex(levels.length - 1) }, [value]) useEffect(() => { if (visible) { setValue(props.value || props.defaultValue || []); } }, [visible]) useEffect(() => { setValue(props.value || props.defaultValue || []) }, [props.value, props.defaultValue]) // 設定定時器,使用loading效果 useEffect(() => { const timer = setTimeout(() => { if (props.options?.length === 0) { setLoading(false) } return () => { clearTimeout(timer) } }, 3000); }, []) // 資料載入完畢後取消loading效果 useEffect(() => { if (props.options.length !== 0) { setLoading(false) } }, [props.options]) return <Wrapper> <div className={classPrefix}> <div className={`${classPrefix}-tabs`}> {levels.map((item, index) => { return <div key={index} onClick={() => { setTabActiveIndex(index) }} className={`${classPrefix}-tab ${tabActiveIndex === index && classPrefix + "-tab-active"}`}> {item?.selected?.label ? item?.selected?.label : item?.selected?.label === "" ? "" : "請選擇"} </div> })} </div> <div className={`${classPrefix}-content`}> {!loading ? levels.map((item, index) => { return <div key={index.toString()} style={{ display: index === tabActiveIndex ? "block" : "none" }} className={`${classPrefix}-list`} > {item.options.map((o, i) => { return <div key={i.toString()} className={`${classPrefix}-item ${o.value === item?.selected?.value && classPrefix + "-item-active"}`}> <div onClick={() => onChange(o, index)} className={`${classPrefix}-item-main ${o?.disabled && classPrefix + "-item-disabled"}`}> {o.label} </div> {o.value === item?.selected?.value && <div className={`${classPrefix}-item-extra`}>✓</div>} </div> })} </div> }) : "loading..."} </div> </div> </Wrapper> }
當已經沒有下一級選單的時候,確定按鈕變為可點選狀態
import React from "react"; import { Wrapper } from "./style"; const classPrefix = `antdm-cascader` export const CascaderHead = function (props) { return <Wrapper> <div className={classPrefix}> <div className={`${classPrefix}-header`}> <a className={`${classPrefix}-header-button`} onClick={() => { props.onCancel?.() }} > {props.cancelText || "取消"} </a> <div className={`${classPrefix}-header-title`}>{props.title}</div> <a className={`${classPrefix}-header-button ${props.canCommit ? '' : classPrefix + '-header-confirm-disable'}`} onClick={() => { props.canCommit && props.onConfirm?.(); }} > {props.confirmText || "確定"} </a> </div> </div> </Wrapper> }
import React, { useState, useCallback, useEffect } from "react"; import { Popup } from "antd-mobile"; import { CascaderHead } from "./CascaderHead/CascaderHead"; import { CascaderContent } from "./CascaderContent/CascaderContent"; import { Wrapper } from "./style"; export const CascaderModal = function (props) { const [value, setValue] = useState(props.value || props.defaultValue || []); const [canCommit, setCanCommit] = useState(false); const onChange = useCallback((v) => { setValue(v); props.onSelect?.(v) }, [props.onSelect]) // 將選擇的資料提交出去 const onConfirm = useCallback(() => { props.onConfirm?.(value) }, [props.onConfirm, value]) // 取消 const onCancel = useCallback(() => { props.onCancel?.() }, [props.onCancel]) useEffect(() => { if (value.length === 0) { return; } let children = props.options; let i = 0; for (i; i < value.length; i++) { const obj = children.find(item => item.value === value[i]); if (!obj) { children = undefined; break; } else { children = obj.children } } setCanCommit(!Array.isArray(children) || children.length === 0) }, [value, props.options]) useEffect(() => { setValue(props.value || props.defaultValue || []) }, [props.value, props.defaultValue]) useEffect(() => { if (props.visible) { setCanCommit(false); } }, [props.visible]) return <Wrapper> <Popup className="antdm-cascader-modal" visible={props.visible} onClose={onCancel} animationType="slide-up" popup={true} > <CascaderHead {...props} canCommit={canCommit} onCancel={onCancel} onConfirm={onConfirm} /> <CascaderContent {...props} visible={props.visible} onSelect={onChange} /> </Popup> </Wrapper> }
以上就是React實現antdM的級聯選單範例的詳細內容,更多關於React antdM級聯選單的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45