用Antd和React寫的Antd介紹網站,原始碼有詳細註釋
阿新 • • 發佈:2019-02-17
git倉庫地址 :https://github.com/mingChen2017/Antd-React-example
演示地址:39.108.54.113/antd這是一個非常簡單的例子,利用了AntD和react,希望能幫助初學者學習,特別是在ModuleDescribe.js,即元件->元件介紹這一頁面有非常多詳細的註釋,後續我會繼續完善。
import React from 'react'; import QueueAnim from 'rc-queue-anim'; import PropTypes from 'prop-types'; import TweenOne, { TweenOneGroup } from 'rc-tween-one'; import Icon from 'antd/lib/icon'; import './moduleDescribe.css' const textData = { //title: 'General', }; //資料陣列,把頁面的顯示層再分為資料和邏輯 let dataArray = [ { title: 'General', background: '#ffd8d8', subTitle:'按鈕和圖示', //如果在這裡要用css的符號實現分行或者是其他功能,那麼需要加上一個父級標籤 //這裡的寫法還不夠純淨,作為model層應該只存放資料而不包括html語句,我個人認為合理的做法是把這部分資料設定成一個數組,在ViewMode層再遍歷後轉成html content: <div> <h3> •按鈕</h3> <p></p> <h3> •圖示(icon):提供了上百個符合antd設計規範的圖示</h3> </div> }, { title: 'Layout', background: '#fed7ff', subTitle:'展示', content: <div> <p> •柵格</p> <p> •佈局:Layout Header Sider Content Footer</p> </div> }, { title: 'Navigation' , background: '#d3d1ff', subTitle:'導航', content: <div> <p> •固釘:將頁面元素釘在可視範圍。</p> <p> •麵包屑:顯示當前頁面在系統層級結構中的位置,並能向上返回。</p> <p> •下拉選單</p> <p> •導航選單</p> <p> •分頁</p> <p> •步驟條:引導使用者按照流程完成任務的導航條</p> </div> }, { title: 'Data Entry' , background: '#afdbe1', subTitle:'資料輸入', content: <div> <p> •自動完成:輸入框自動完成功能</p> <p> •級聯選擇</p> <p> •多選框</p> <p> •日期選擇框</p> <p> •表單</p> <p> •數字輸入框</p> <p> •輸入款</p> <p> •提及</p> <p> •評分</p> <p> •單選框</p> <p> •滑動輸入條</p> <p> •開關</p> <p> •樹選擇</p> <p> •時間選擇框</p> <p> •穿梭框</p> <p> •上傳</p> </div> }, { title: 'Data Display' , background: '#bee1c5', subTitle:'資料展示', content: <div> <p> •頭像</p> <p> •微標數:參考微信小紅點</p> <p> •日曆</p> <p> •卡片</p> <p> •走馬燈</p> <p> •摺疊面板</p> <p> •氣泡卡片</p> <p> •文字提示:移到文字上會顯示簡單的文字提示氣泡框。</p> <p> •表格</p> <p> •標籤頁</p> <p> •標籤</p> <p> •時間戳</p> <p> •樹形控制元件</p> </div>}, { title: 'Feedback' , background: '#ecffd8', subTitle:'反饋', content:<div> <p> •警告提示</p> <p> •對話方塊</p> <p> •全域性提示</p> <p> •通知提醒框</p> <p> •進度條</p> <p> •氣泡確認框</p> <p> •載入中</p> </div>}, { title: 'Other' , background: '#e1d2ba', subTitle:'其它', content:<div> <p> •錨點:用於跳轉到頁面指定位置。</p> <p> •回到頂部</p> <p> •國際化:翻譯</p> </div>}, ]; //遍歷陣列錄入資料 dataArray = dataArray.map(item => ({ ...item, ...textData })); class ModuleDescribe extends React.Component { //限制prop的型別,一般對外部傳來的引數需要做型別驗證 static propTypes = { className: PropTypes.string.isRequired, }; //設定預設props /* [ { name: 'Zachary He', age: 13, married: true, }, { name: 'Alice Yo', name: 17, }, { name: 'Jonyu Me', age: 20, married: false, } ] propTypes: { myArray: React.PropTypes.arrayOf( React.propTypes.shape({ name: React.propTypes.string.isRequired, age: React.propTypes.number.isRequired, married: React.propTypes.bool }) ) } */ static defaultProps = { className: 'pic-details-demo', }; constructor(props) { super(props); /* 假如我們是以<ModuleDescribe></ModuleDescribe>呼叫的 this.props.children拿到的是兩個標籤中間的子節點 */ //console.error("this.props.children:"+this.props.children) this.state = { /* 使用classnames來動態修改或者新增多個className react原生動態新增多個className會報錯: import style from './style.css' <div className={style.class1 style.class2}</div> 想要得到最終渲染的效果是: <div class='class1 class2'></div> 引入classnames庫,安裝: npm install classnames --save 使用: import classnames from 'classnames' <div className=classnames({ 'class1': true, //這裡的true可以省略 'class2': true )> </div> 其他用法: 可以傳入陣列物件: var arr = ['b', { c: true, d: false }]; classNames('a', arr); // => 'a b c' 可以傳入動態class let buttonType = 'primary'; classNames({ [`btn-${buttonType}`]: true }); */ /* 區域性state會讓 */ picOpen: {}, }; } //元件被點選後的動畫 onImgClick = (e, i) => { const { picOpen } = this.state; Object.keys(picOpen).forEach((key) => { //檢查是否有其他開啟的狀態的視窗,如果有就關閉 if (key !== i && picOpen[key]) { picOpen[key] = false; } }); picOpen[i] = true; //更改狀態,重新渲染 this.setState({ picOpen, }); }; //元件被關閉的動畫 onClose = (e, i) => { const { picOpen } = this.state; picOpen[i] = false; //更改狀態,重新渲染 this.setState({ picOpen, }); }; //關閉動畫執行完畢 onTweenEnd = (i) => { const { picOpen } = this.state; //刪除picOpen[i] delete picOpen[i] 結果為: ["a",undefined,"c","d"],在下面會通過判斷型別來推斷它是否被開啟 delete picOpen[i]; this.setState({ picOpen, }); }; getDelay = (e) => { //console.error("getDelay:"+e.index) const i = e.index + dataArray.length % 4; console.error("e.index:"+e.index); return (i % 4) * 100 + Math.floor(i / 4) * 100 + 200; }; getType = (e) => { //console.error("getType:"+e.index) const animationType=["alpha","left","right","top","bottom","scale","scaleBig","scaleX","scaleY"]; return animationType[4]; } getChildren = () => { const imgWidth = 300; const imgHeight = 200; const imgBoxWidth = 330; const imgBoxHeight = 220; //console.error("getLiChildren prepare") //map()方法建立一個新陣列,其結果是該陣列中的每個元素都呼叫一個提供的函式後返回的結果。每個元素都是回撥函式的結果。 return dataArray.map((item, i) => { //console.error("getLiChildren begin:"+i) const { background,title, subTitle, content } = item; const isEnter = typeof this.state.picOpen[i] === 'boolean'; //讀取該視窗是否被開啟 const isOpen = this.state.picOpen[i]; const left = isEnter ? 0 : imgBoxWidth * (i % 4); const imgLeft = isEnter ? imgBoxWidth * (i % 4) : 0; const isRight = false; const isTop = Math.floor(i / 4); let top = isTop ? (isTop - 1) * imgBoxHeight : 0; top = isEnter ? top : imgBoxHeight * isTop; let imgTop = isTop ? imgBoxHeight : 0; imgTop = isEnter ? imgTop : 0; //這個是點選後彈出的左邊視窗的屬性 const liStyle = isEnter ? { width: '100%', height: 600, zIndex: 1 } : null; //點選後的陰影動畫 const liAnimation = isOpen ? ({ boxShadow: '0 2px 8px rgba(140, 140, 140, .35)',repeat:1}) : ({ boxShadow: '0 0px 0px rgba(140, 140, 140, 0)' ,repeat:1}); let aAnimation = isEnter ? ({ delay: 400,//新點選的目標移動後就目標多久回去 ease: 'easeInOutCubic', width: imgWidth, height: imgHeight, onComplete: this.onTweenEnd.bind(this, i), left: imgBoxWidth * (i % 4), top: isTop ? imgBoxHeight : 0, }) : null; //假如這個圖案是被點選的是什麼效果 aAnimation = isOpen ? ({ ease: 'easeInOutCubic', left: isRight ? (imgBoxWidth * 2) - 10 : 0, width: '50%', height: '100%', top: 0, }) : aAnimation; // 位置 js 控制; return ( /*該部分是進場動畫*/ <TweenOne key={i} style={ { left, top, ...liStyle, } } //component是css標籤的意思,比如在這裡用了li的話,在頁面實際上會生成一對<li></li>標籤 component="li" className={isOpen ? 'open' : ''} animation={liAnimation} > <TweenOne component="a" onClick={e => this.onImgClick(e, i)} style={{ left: imgLeft, top: imgTop, width: 300, height: 200 }} //aAnimation會經過兩層判斷,先是判斷是否進入的動畫,再判斷是否點選的動畫 {item.title} animation={aAnimation} > {/*我是一段註釋*/} {/*<--圖片會隨著緩慢變大,不是因為給圖片設定了動效,是因為圖片的width為100%,所以它會一直隨著外面的容器變大,實際上TweenOne是一個隱形的容器,假如在這裡用div畫了一個長方形,不會有特效。-->*/} <div className="my-rectangle" style={{background }}>{title}</div> </TweenOne> {/*<控制右邊頁面的動畫-->*/} <TweenOneGroup enter={[ { opacity: 0, duration: 0, type: 'from', delay: 400, }, { ease: 'easeOutCubic', type: 'from', left: isRight ? '60%' : '0%' }, ]} leave={{ ease: 'easeInOutCubic', left: isRight ? '60%' : '0%' }} component="" > {isOpen && ( <div className={`${this.props.className}-text-wrapper`} key="text" style={{ left: isRight ? '0%' : '50%', }} > <h1> {subTitle} </h1> <Icon type="cross" onClick={e => this.onClose(e, i)} /> {/*<!--這個標籤表示標題下面的橫線,雖然我也不知道為什麼不是<em></em>-->*/} <em /> <p>{content}</p> </div> )} </TweenOneGroup> </TweenOne> ); }); }; render() { return ( <div> {/*<!--this.getLiChildren()每一次返回,QueueAnim標籤都會執行一次,為每一個return分配delay component className....通過列印this.getDelay可以證明-->*/} {/*QueueAnim裡面函式是依個全部執行完才執行下一個,例如下面會先執行六次this.getDelay,再執行六次this.getType>,根據實驗,delay會影響後面this.getType的執行順序, 由於antd是非同步載入,會先執行this.getLiChildren(),再執行QueueAnim裡的函式 */} {/*<!-- QueueAnim會執行括號內的函式*/} <QueueAnim delay={this.getDelay} component="ul" className={`${this.props.className}-image-wrapper`} type={this.getType} duration={2000} > {/*在這裡我們拿到的是一個數組,但是編譯器會自動拼接陣列的所有元素,驗證的辦法是 這裡可以寫成this.getChildren()[0],那麼螢幕只會顯示一個子元件*/} {this.getChildren()} {console.error(this.getChildren)} </QueueAnim> </div> ); } } export default ModuleDescribe;