ant design螞蟻金服基於react打造的一個服務於企業級產品的UI框架。而ant design pro呢?就是基於Ant Design這個框架搭建的中後臺管理控制台的腳手架。 話不多說,今天給大家分享一個自己寫的一個組件。 源碼如下: index.tsx文件: index.less文件: A ...
ant design螞蟻金服基於react打造的一個服務於企業級產品的UI框架。而ant design pro呢?就是基於Ant Design這個框架
搭建的中後臺管理控制台的腳手架。
話不多說,今天給大家分享一個自己寫的一個組件。
源碼如下:
index.tsx文件:
1 import React,{Fragment} from 'react'; 2 import styles from './index.less'; 3 import undefined from '@/e2e/__mocks__/antd-pro-merge-less'; 4 export interface State { 5 list:Array<any>, 6 cacheList:Array<any>, 7 eventIF:boolean, 8 } 9 export interface Props { 10 style?:any, 11 styleSon?:any, 12 val?:valFrom, 13 dataSource?:Array<dataSource>, 14 onClickSon?:any, 15 onMouseEnterSon?:any, 16 onMouseLeaveSon?:any 17 } 18 interface valFrom{ 19 type?:TYPE|string,//動畫類型 20 direction?:DIRECTION|string,//方向 21 time?:number,//時間 單位s 22 delay?:number,//動畫執行前的延時時間 單位s 23 sonDelay?:number//列表子項動畫延時 24 domId?:string,//事件綁定dom id 25 event?:EVENT|string,//動畫執行事件 26 hideModel?:boolean//背景是否顯示 27 28 } 29 export const enum TYPE{FADEIN} 30 export const enum DIRECTION{TOP,BUTTOM,LEFT,REGIST,TOPLEFT,TOPREGIST,BUTTOMLEFT,BUTTOMREGIST} 31 export const enum EVENT{CLICK,MOUSEENTER} 32 interface dataSource{keys:any,title:any,style?:any} 33 export class Father extends React.Component<Props, State> { 34 constructor(props: Props) { 35 super(props); 36 this.state = { 37 list:[],//列表項 38 cacheList:[],//暫時存儲,觀望是否綁定dom 39 eventIF:false,//是否觸發了event事件 40 }; 41 if(this.props.val !== undefined){ 42 const val:valFrom = this.props.val; 43 if(this.props.val.type != undefined && !(val.type===TYPE.FADEIN || val.type==="fadeIn")){ 44 throw Error(`type定義錯誤:錯誤值為 ${val.type},type取值為{enum:TYPE,'fadeIn'}`,); 45 } 46 if(this.props.val.direction != undefined && !(val.direction === DIRECTION.TOP || val.direction === DIRECTION.BUTTOM || 47 val.direction === DIRECTION.LEFT||val.direction === DIRECTION.REGIST || val.direction === DIRECTION.TOPLEFT || 48 val.direction === DIRECTION.TOPREGIST || val.direction === DIRECTION.BUTTOMLEFT || val.direction === DIRECTION.BUTTOMREGIST || 49 val.direction === 'top' || val.direction === 'buttom' || val.direction=== 'left' || val.direction === 'regist' || 50 val.direction=== 'topLeft' || val.direction === 'topRegist' || val.direction === 'buttomLeft' || val.direction === 'buttomRegist')){ 51 throw Error(`direction定義錯誤:錯誤值為 ${val.direction},direction取值為{enum:DIRECTION,'top','buttom','left','regist', 52 'topLeft','topRegist','buttomLeft','buttomRegist'}`); 53 } 54 window.onload = function(){ 55 if(val.domId !== undefined){ 56 if(document.getElementById(val.domId)===undefined || document.getElementById(val.domId)===null){ 57 throw Error(`指定id的DOM元素不存在!`,); 58 } 59 if(val.event === undefined){ 60 console.warn(`指定DOM元素情況下未指定綁定事件event!`); 61 } 62 } 63 } 64 if(val.event !== undefined){ 65 if(!(val.event === EVENT.CLICK || val.event === EVENT.MOUSEENTER || val.event === 'click' || 66 val.event === 'mouseEnter')){ 67 throw Error(`event定義錯誤:錯誤值為 ${val.event},event取值為{enum:EVENT,'click','mouseEnter'}`,); 68 } 69 if(val.domId === undefined){ 70 console.warn(`綁定事件後未指定DOM元素!`); 71 } 72 } 73 } 74 } 75 isWidth=(strs:Array<any>):number=>{ 76 let str : Array<string> = []; 77 for(let i=0;i<strs.length;i++){ 78 if(strs[i].type!==undefined && strs[i].type===Son){ 79 str.push(strs[i].props.children); 80 } 81 } 82 let max:number = 0; 83 let reg:RegExp = /[\u4E00-\u9FA5\uF900-\uFA2D]/i; 84 str.forEach(element => { 85 let forMax = 0; 86 for(let i=0;i<element.length;i++){ 87 if(reg.test(element.charAt(i))){ 88 forMax+=2; 89 }else{ 90 forMax++; 91 } 92 } 93 if(forMax > max){ 94 max = forMax; 95 } 96 }); 97 return max; 98 } 99 isWidth1=(maxWidth:number,data:Array<dataSource>):number=>{ 100 let max:number = maxWidth; 101 let reg:RegExp = /[\u4E00-\u9FA5\uF900-\uFA2D]/i; 102 data.forEach(element => { 103 let forMax = 0; 104 for(let i=0;i<element.title.length;i++){ 105 if(reg.test(element.title.charAt(i))){ 106 forMax+=2; 107 }else{ 108 forMax++; 109 } 110 } 111 if(forMax > max){ 112 max = forMax; 113 } 114 }); 115 return max; 116 } 117 setList=():void=>{ 118 //清零 119 this.state.list.length = 0; 120 const list = [...this.state.cacheList]; 121 this.setState({list,eventIF:true}); 122 //解除綁定 123 if(this.props.val != undefined && this.props.val.domId != undefined){ 124 let dom:any = document.getElementById(this.props.val.domId); 125 let event:string = "click"; 126 if(this.props.val.event === EVENT.MOUSEENTER){ 127 event = "mouseenter"; 128 } 129 dom.removeEventListener(event,this.setList); 130 } 131 } 132 bindEvent=(val:any):void=>{ 133 if(this.props.val != undefined && this.props.val.domId != undefined && this.props.val.event != undefined){ 134 const dom:any = document.getElementById(this.props.val.domId); 135 let event:string = "click"; 136 if(this.props.val.event === EVENT.MOUSEENTER){ 137 event = "mouseenter"; 138 } 139 dom.addEventListener(event,this.setList); 140 } 141 } 142 render() { 143 //預設動畫效果 144 const defVal:valFrom = { 145 type:TYPE.FADEIN, 146 direction:DIRECTION.LEFT, 147 time:.5, 148 sonDelay:.1, 149 delay:0, 150 }; 151 const defV = {...defVal,...this.props.val} 152 //Son項數 153 let index:number = 0; 154 //最大文字占格 155 let width:number=0; 156 //字體大小 157 let fontSize:number = 13; 158 //Son高度 159 let formatHeight:number = 26; 160 //Father及Son寬度 161 let formatWidth:number = 0; 162 163 let sonStr:any = this.props.children; 164 // //寬高自適應 165 if(this.props.children != undefined){ 166 width = this.isWidth(sonStr); 167 } 168 if(this.props.dataSource != undefined){ 169 width = this.isWidth1(width,this.props.dataSource); 170 } 171 fontSize = this.props.style!==undefined && this.props.style.fontSize!==undefined?Number.parseInt(this.props.style.fontSize):13; 172 formatHeight = fontSize*2; 173 formatWidth = fontSize*width*0.6; 174 175 //綁定dom後是否隱藏模板 176 let hideModel = "visible"; 177 if(!this.state.eventIF){ 178 //清零 179 this.state.list.length = 0; 180 this.state.cacheList.length = 0; 181 //子項寫入 182 if(this.props.children != null && this.props.children != undefined){ 183 for(let i=0;i<sonStr.length;i++){ 184 if(sonStr[i].type!==undefined && sonStr[i].type===Son){ 185 this.state.cacheList.push(<List title={sonStr[i].props.children} style={sonStr[i].props.style} styleSon={this.props.styleSon} 186 animation={defV} index={index++} formatHeight={formatHeight} 187 formatWidth = {formatWidth} keys={this.props.children[i].props.keys !==undefined? 188 this.props.children[i].props.keys:Number.MAX_VALUE-i} onClick={this.props.children[i].props.onClick} 189 onClickSon={this.props.onClickSon} onMouseEnter={this.props.children[i].props.onMouseEnter} 190 onMouseEnterSon={this.props.onMouseEnterSon} onMouseLeave={this.props.children[i].props.onMouseLeave} 191 onMouseLeaveSon={this.props.onMouseLeaveSon}/>); 192 } 193 } 194 } 195 if(this.props.dataSource !== undefined){ 196 for(let i=0;i<this.props.dataSource.length;i++){ 197 this.state.cacheList.push(<List title={this.props.dataSource[i].title} style={this.props.dataSource[i].style} index={index++} 198 styleSon={this.props.styleSon} animation={defV} formatHeight={formatHeight} formatWidth = {formatWidth} keys= 199 {this.props.dataSource[i].keys}/>); 200 } 201 } 202 //無dom綁定 203 if(defV.domId ===undefined || defV.event ===undefined){ 204 for(let i =0;i<this.state.cacheList.length;i++){ 205 this.state.list.push(this.state.cacheList[i]); 206 } 207 208 }else{ 209 //有dom綁定 210 if(this.props.val!=undefined && this.props.val.hideModel){ 211 hideModel = "hidden"; 212 } 213 //事件綁定 214 const _this = this; 215 //切換菜單後window.onload不會執行,但dom已經重置 216 if(this.props.val != undefined && this.props.val.domId != undefined && this.props.val.event != undefined && 217 document.getElementById(this.props.val.domId)==null){ 218 let interval = window.setInterval(()=>{ 219 let dom:any = null; 220 if(_this.props.val!=undefined && _this.props.val.domId != undefined){ 221 dom = document.getElementById(_this.props.val.domId); 222 } 223 if(dom !== null && dom !==undefined && dom !=="null"){ 224 _this.bindEvent(defV); 225 226 window.clearInterval(interval); 227 } 228 }, 100); 229 } 230 } 231 }else { 232 index = this.state.list.length; 233 } 234 235 //Father預設樣式 236 237 const defFatherStyle:any = { 238 border:"1px solid #91D5FF", 239 backgroundColor: "#E6F7FF", 240 fontSize:"13px", 241 color:"#000", 242 paddimg:`${fontSize}px`, 243 height: `${formatHeight*index+2}px`, 244 width:`${formatWidth+2}px`, 245 visibility:`${hideModel}` 246 } 247 const style = {...defFatherStyle,...this.props.style}; 248 return ( 249 <Fragment> 250 <div style={style} className={styles.fDiv}> 251 <ul className={styles.ul}> 252 {this.state.list} 253 </ul> 254 </div> 255 </Fragment> 256 ); 257 } 258 } 259 export class Son extends React.Component<{style?:any,keys?:any,onClick?:any,onMouseEnter?:any,onMouseLeave?:any}, {}> { 260 } 261 class List extends React.Component<{title:string,style?:any,styleSon?:any,animation:valFrom,keys:any,index:number,formatHeight:number, 262 formatWidth:number,onClick?:any,onClickSon?:any,onMouseEnter?:any,onMouseEnterSon?:any,onMouseLeave?:any,onMouseLeaveSon?:any},{}> { 263 click = (key:any,title:any)=>{ 264 if(this.props.onClick !== undefined){ 265 this.props.onClick(key,title); 266 }else if(this.props.onClickSon !== undefined){ 267 this.props.onClickSon(key,title); 268 } 269 } 270 mouseEnter = (key:any,title:any)=>{ 271 if(this.props.onMouseEnter !== undefined){ 272 this.props.onMouseEnter(key,title); 273 }else if(this.props.onMouseEnterSon !== undefined){ 274 this.props.onMouseEnterSon(key,title); 275 } 276 } 277 mouseLeave = (key:any,title:any)=>{ 278 if(this.props.onMouseLeave !== undefined){ 279 this.props.onMouseLeave(key,title); 280 }else if(this.props.onMouseLeaveSon !== undefined){ 281 this.props.onMouseLeaveSon(key,title); 282 } 283 } 284 285 286 287 render() { 288 const val:valFrom = this.props.animation; 289 const style = {animation:'',animationDelay:'0s'}; 290 291 //載入頁面後直接執行 292 if(val.type === TYPE.FADEIN && val.direction === DIRECTION.TOP || val.type === 'fadeIn' && val.direction === 'top' 293 || val.type === TYPE.FADEIN && val.direction === 'top' || val.type === 'fadeIn' && val.direction === DIRECTION.TOP){ 294 style.animation= `${styles.fadeInTop} ${val.time}s forwards`; 295 }else if(val.type === TYPE.FADEIN && val.direction === DIRECTION.BUTTOM || val.type === 'fadeIn' && val.direction === 'buttom' 296 || val.type === TYPE.FADEIN && val.direction === 'buttom' || val.type === 'fadeIn' && val.direction === DIRECTION.BUTTOM){ 297 style.animation = `${styles.fadeInButtom} ${val.time}s forwards`; 298 }else if(val.type === TYPE.FADEIN && val.direction === DIRECTION.LEFT || val.type === 'fadeIn' && val.direction === 'left' 299 || val.type === TYPE.FADEIN && val.direction === 'left' || val.type === 'fadeIn' && val.direction === DIRECTION.LEFT){ 300 style.animation = `${styles.fadeInLeft} ${val.time}s forwards`; 301 }else if(val.type === TYPE.FADEIN && val.direction === DIRECTION.REGIST || val.type === 'fadeIn' && val.direction === 'regist' 302 || val.type === TYPE.FADEIN && val.direction === 'regist' || val.type === 'fadeIn' && val.direction === DIRECTION.REGIST){ 303 style.animation = `${styles.fadeInRegist} ${val.time}s forwards`; 304 }else if(val.type === TYPE.FADEIN && val.direction === DIRECTION.TOPLEFT || val.type === 'fadeIn' && val.direction === 'topLeft' 305 || val.type === TYPE.FADEIN && val.direction === 'topLeft' || val.type === 'fadeIn' && val.direction === DIRECTION.TOPLEFT){ 306 style.animation = `${styles.fadeInTopLeft} ${val.time}s forwards`; 307 }else if(val.type === TYPE.FADEIN && val.direction === DIRECTION.TOPREGIST || val.type === 'fadeIn' && val.direction === 'topRegist' 308 || val.type === TYPE.FADEIN && val.direction === 'topRegist' || val.type === 'fadeIn' && val.direction === DIRECTION.TOPREGIST){ 309 style.animation = `${styles.fadeInTopRegist} ${val.time}s forwards`; 310 }else if(val.type === TYPE.FADEIN && val.direction === DIRECTION.BUTTOMLEFT || val.type === 'fadeIn' && val.direction === 'buttomLeft' 311 || val.type === TYPE.FADEIN && val.direction === 'buttomLeft' || val.type === 'fadeIn' && val.direction === DIRECTION.BUTTOMLEFT){ 312 style.animation = `${styles.fadeInButtomLeft} ${val.time}s forwards`; 313 }else if(val.type === TYPE.FADEIN && val.direction === DIRECTION.BUTTOMREGIST || val.type === 'fadeIn' && val.direction === 'buttomRegist' 314 || val.type === TYPE.FADEIN && val.direction === 'buttomRegist' || val.type === 'fadeIn' && val.direction === DIRECTION.BUTTOMREGIST){ 315 style.animation = `${styles.fadeInButtomRegist} ${val.time}s forwards`; 316 } 317 if(val.sonDelay !== undefined && val.delay !== undefined){ 318 style.animationDelay = `${this.props.index*val.sonDelay+val.delay}s`; 319 } 320 //Son預設樣式 321 const defStyle:any = { 322 textAlign: "center", 323 width:`${this.props.formatWidth}px`, 324 height:`${this.props.formatHeight}px`, 325 lineHeight:`${this.props.formatHeight}px`, 326 } 327 const sty = {...defStyle,...this.props.styleSon,...this.props.style,...style}; 328 return ( 329 <li className={styles.li} style={sty} key={this.props.keys} onClick={this.click.bind(this,this.props.keys,this.props.title)} 330 onMouseEnter = {this.mouseEnter.bind(this,this.props.keys,this.props.title)} onMouseLeave= 331 {this.mouseLeave.bind(this,this.props.keys,this.props.title)}>{this.props.title}</li> 332 ); 333 } 334 }
index.less文件:
1 @top:200px; 2 @left:400px; 3 .fDiv,.li,.ul,body,div{ 4 padding: 0px; 5 margin: 0px; 6 border: 0px; 7 } 8 .fDiv{ 9 position: relative; 10 } 11 .li{ 12 list-style:none; 13 visibility:hidden; 14 cursor: pointer; 15 } 16 li:hover{ 17 background-color: #A1E5FF; 18 } 19 .ul{ 20 position: absolute; 21 z-index: 999; 22 display: inline-block; 23 } 24 @keyframes fadeInTop{ 25 0%{ 26 opacity: 0; 27 margin-top: @top; 28 visibility:visible; 29 } 30 100%{ 31 opacity: 1; 32 margin-top: 0px; 33 visibility:visible; 34 } 35 } 36 @keyframes fadeInButtom{ 37 0%{ 38 opacity: 0; 39 margin-top: -@top; 40 visibility:visible; 41 } 42 100%{ 43 opacity: 1; 44 margin-top: 0px; 45 visibility:visible; 46 } 47 }