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, 6 cacheList:Array , 7 eventIF:boolean, 8 } 9 export interface Props { 10 style?:any, 11 styleSon?:any, 12 val?:valFrom, 13 dataSource?:Array , 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 { 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 ):number=>{ 76 let str : Array<string> = []; 77 for(let i=0;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 ){ 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 ):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 ){ 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 ){ 184 if(sonStr[i].type!==undefined && sonStr[i].type===Son){ 185 this.state.cacheList.push( 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(
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
250 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 ( 329251255252 {this.state.list} 253
254this.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} 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 } 48 @keyframes fadeInLeft{ 49 0%{ 50 opacity: 0; 51 margin-left: @left; 52 visibility:visible; 53 } 54 100%{ 55 opacity: 1; 56 margin-left: 0px; 57 visibility:visible; 58 } 59 } 60 @keyframes fadeInRegist{ 61 0%{ 62 opacity: 0; 63 margin-left: -@left; 64 visibility:visible; 65 } 66 100%{ 67 opacity: 1; 68 margin-left: 0px; 69 visibility:visible; 70 } 71 } 72 @keyframes fadeInTopLeft{ 73 0%{ 74 opacity: 0; 75 margin-top: @top; 76 margin-left: @left; 77 visibility:visible; 78 } 79 100%{ 80 opacity: 1; 81 margin-top: 0px; 82 margin-left: 0px; 83 visibility:visible; 84 } 85 } 86 @keyframes fadeInTopRegist{ 87 0%{ 88 opacity: 0; 89 margin-top: @top; 90 margin-left: -@left; 91 visibility:visible; 92 } 93 100%{ 94 opacity: 1; 95 margin-top: 0px; 96 margin-left: 0px; 97 visibility:visible; 98 } 99 } 100 @keyframes fadeInButtomLeft{ 101 0%{ 102 opacity: 0; 103 margin-top: -@top; 104 margin-left: @left; 105 visibility:visible; 106 } 107 100%{ 108 opacity: 1; 109 margin-top: 0px; 110 margin-left: 0px; 111 visibility:visible; 112 } 113 } 114 @keyframes fadeInButtomRegist{ 115 0%{ 116 opacity: 0; 117 margin-top: -@top; 118 margin-left: -@left; 119 visibility:visible; 120 } 121 100%{ 122 opacity: 1; 123 margin-top: 0px; 124 margin-left: 0px; 125 visibility:visible; 126 } 127 }
API如下:
注意:动画进入选择的类型目前只有fadeIn(渐入),有人可能会说这个可以不要,但是如果要继续拓展的话这个属性就必不可少了,比如拓展增强、轨迹、旋转、无效果等。这些拓展稍显有些麻烦,由于我只是当练习react与typescript来写就没有拓展,但不是不能拓展。