opennft-front 开源 NFT 前端平台开源项目

我要开发同款
匿名用户2022年03月24日
176阅读
开发技术JavaScript
所属分类Web3、开源货币/比特币
授权协议Apache

作品详情

项目开始BEGIN项目说明基于React16.x、AntDesign4.x,react-admin

目录结构├──config//项目构建配置├──public//不参与构建的静态文件├──scripts//构建脚本├──src│├──assets//全项目通用图片文件等│├──commons//全项目通用js,业务相关│├──components//全项目通用组件,业务相关│├──config//项目构建补充配置│├──layouts//页面框架布局组件+│├──mock//模拟数据│├──models//模块封装,基于redux,提供各组件共享数据、共享逻辑│├──pages//主项目页面目录│├──├──Project//子项目顶级目录│├──├──├──nft//NFT--PC版本项目目录│├──├──├──├──assets//NFT--PC版本公共图片文件│├──├──├──├──components//NFT--PC版本公共组件库│├──├──├──├──pages//NFT--PC版本页面目录│├──├──├──mobile//移动端项目目录│├──├──├──├──nft-mobile//NFT--微信版本项目目录│├──├──├──├──├──assets//NFT--微信版本公共图片文件│├──├──├──├──├──components//NFT--微信版本公共组件库│├──├──├──├──├──pages//NFT--微信版本页面目录│├──router//路由│├──ant.less//主体配置│├──App.js//根组件│├──index.css//全局样式慎用│├──index.dark.css//全局样式慎用│├──index.js//项目入口│├──menus.js//菜单配置│├──setupProxy.js//后端联调代理配置│└──theme.less//主题变量├──package.json├──README.md└──yarn.lock安装依赖$yarn启动注意事项依赖安装完成后,src/setupProxy.js为项目本地代理文件,请及时更改您需要代理的接口地址!

!!!微信版本只可以在微信打开运行,并直接在router/AuthRoute.jsx中填入自己申请的appid,目前为''

此为两个项目依托同一底层框架,PC及微信端口分离,如需切换请在router/app.router.js中更换路由,router/AppRoute.jsx中切换引入的AuthRoute(分别为微信版本:AuthRoute.jsx,PC版本:AuthRoutePC.jsx)并在src/commons/PRE_ROUTER.js中进行相关配置,以及package.json中更改homepage为相应的项目名称。

两套PRE_ROUTER.js中配置分别如下:

微信版本:路由前缀----/front_nft_mobile请求地址前缀----/api/nft登录页面----/nft_mobile_home

PC版本:路由前缀----/front_nft_pc请求地址前缀----/api/nft登录页面----/nft_home

开发启动$yarnstart#指定端口$PORT=8080yarnstart#HTTPS方式启动$HTTPS=trueyarnstart生产构建$yarnbuild//构建输入到指定目录$BUILD_PATH=../distyarnbuild域名子目录发布项目//开发启动$BASE_NAME=/synext-adminyarnstart//开发访问'https://localhost:XXXX/synext-admin/'//生产环境同上$BASE_NAME=/synext-adminyarnstart//访问'https://xxx.com/synext-admin'菜单配置//在/src/menus.js文件中配置菜单数据,前端硬编码或异步加载菜单数据。//菜单支持头部、左侧、头部+左侧三种布局方式,默认左侧菜单。如需放开设置,请到'src/layouts/index.jsx'放开注释//菜单字段说明。字段必须说明key是//需要唯一parentKey否//用于关联父级path是//菜单对应的路由地址text是//菜单标题icon否//菜单图标配置url否//菜单对应会打开url对应的iframe页面,如果配置了url,path将无效target否//配合url使用,菜单将为a标签<ahref={url}target={target}>{text}</a>order否//菜单排序,数值越大越靠前显示type否//如果菜单数据中携带功能权限配置,type==='1'为菜单,type==='2'为功能code否//功能码,如果是type==='2',会用到此字段页面开发//配置组件importReact,{Component}from'react';importconfigfrom'src/commons/config-hoc';@config({title:'页面title',ajax:true,...})exportdefaultclassSomePageextendComponent{componentDidMount(){this.props.ajax.get(...).then(...)}...}参数类型默认值说明noFramebooleanfalse标记当前页面为不需要导航框架的页面,比如登录页,通过脚本抓取实现noAuthbooleanfalse标记当前页面为不需要登录即可访问的页面,通过脚本抓取实现keepAliveboolean-标记当前页面内容在页面切换之后是否保持titleboolean或string或ReactNode或object或function(props)truetrue:当前页面显示通过菜单结构自动生成的title;false:当前页面不显示title;string:自定义title;object:{text,icon}text为显示的名称,icon为图标;function(props):返回值作为titlebreadcrumbsboolean或array或function(props)truetrue:当前页面显示通过菜单结构自动生成的面包屑;false:当前页面不显示面包屑;object:[{icon,text,...}];function(props):返回值作为面包屑appendBreadcrumbsarray或function(props)[]在当前面包屑基础上添加;function(props):返回值作为新添加的面包屑pageHeadboolean-页面头部是否显示sideboolean-页面左侧是否显示sideCollapsedboolean-左侧是否收起ajaxbooleantrue是否添加ajax高阶组件,内部可以通过this.props.ajax使用ajaxAPI,组件卸载时,会自动打断未完成的请求routerbooleanfalse是否添加withRouter装饰器,组件内部可以使用this.props.history等APIquerybooleanfalse是否添加地址查询字符串转换高阶组件,内部可以通过this.props.query访问查询字符串connectboolean或function(state)false是否与redux进行连接,true:只注入了this.props.action相关方法;false:不与redux进行连接;(state)=>({title:state.page.title}):将函数返回的数据注入this.propseventbooleanfalse是否添加event高阶组件,可以使用this.props.addEventListener添加dom事件,并在组件卸载时会自动清理;通过this.props.removeEventListener移出dom事件pubSubbooleanfalse是否添加发布订阅高阶组件,可以使用this.props.subscribe(topic,(msg,data)=>{...})订阅事件,并在组件卸载时,会自动取消订阅;通过this.props.publish(topic,data)发布事件modalstring或objectfalse当前组件是否是modal。string:弹框标题;object:弹框配置注:

noFrame、noAuth、keepAlive 只有配置了path才有效!config装饰器可以用于任何组件,但是title、breadcrumbs、appendBreadcrumbs、pageHead、side、sideCollapsed最好在路由对应的页面组件中使用//页面保持//页面渲染一次之后会保持状态,再次跳转到此页面不会重新创建或重新渲染开启方式:1./src/models/system.jsinitState.keepAlive属性修改默认值2.config装饰器keepAlive属性页面显示/隐藏事件config 装饰器为组件注入了两个事件 onComponentWillShow、onComponentWillHide ,如果页面使用了KeepAlive功能,切换显示/隐藏时会触发

@config({...})exportdefaultclassSomePageextendsReact.Component{constructor(...props){super(...props);this.props.onComponentWillShow(()=>{//dosomething});this.props.onComponentWillHide(()=>{//dosomething});}...}页面容器PageContent系统提供了页面的跟节点PageContent,有如下特性:

添加了marginpadding样式;添加了footer;支持页面loading;自动判定是否有底部工具条FixBottom组件,为底部工具条腾出空间;是否显示footer,默认true

<PageContentfooter={false}>...</PageContent>显示loading,有两种方式。

model方式

this.props.action.page.showLoading();this.props.action.page.hideLoading(); props方式

const{loading}=this.state;<PageContentloading={loading}>...</PageContent>;弹框页面开发添加、修改等场景,往往会用到弹框,antdModal组件使用不当会产生脏数据问题(两次弹框渲染数据互相干扰)

系统提供了基于modal封装的高阶组件,每次弹框关闭,都会销毁弹框内容,避免互相干扰

modal高阶组件modal高阶组件集成到了config中,也可以单独引用:import{ModalContent}from'src/commons/ra-lib';

importReactfrom"react";importconfigfrom"src/commons/config-hoc";import{ModalContent}from"src/commons/ra-lib";exportdefaultconfig({modal:{title:"弹框标题",},})((props)=>{const{onOk,onCancel}=props;return(<ModalContentonOk={onOk}onCancel={onCancel}>弹框内容</ModalContent>);});modal所有参数说明如下:

如果是string,作为modal的title如果是函数,函数返回值作为Modal参数如果是对象,为Modal相关配置,具体参考 antdModal组件options.fullScreenboolean默认false,是否全屏显示弹框ModalContent组件弹框内容通过ModalContent包裹,具体参数如下:

参数类型默认值说明surplusSpacebooleanfalse是否使用屏幕垂直方向剩余空间otherHeightnumber-除了主体内容之外的其他高度,用于计算主体高度;loadingbooleanfalse加载中loadingTip--加载提示文案footer--底部okTextstring-确定按钮文案onOkfunction-确定按钮事件cancelTextstring-取消按钮文案onCancelfunction-取消按钮事件resetTextstring-重置按钮文案onResetfunction-重置按钮事件styleobject-最外层容器样式bodyStyleobject-内容容器样式系统路由系统路由使用react-router,通过route-loader将路由内容填充到/src/pages/page-routes.js文件,支持两种写法:

常量方式exportconstPAGE_ROUTE="/path"; 页面config装饰器(推荐)@config({path:'/path',})exportdefaultclassSomePageextendsReact.Component{...}二级页面二级页面如果要保持父级菜单的选中状态,以父级path开始并以/_/作为分隔符即可:parent/path/_/child/path

//parentpage@config({path:'/parent/path'})exportdefaultclassParentextendsReact.Component{...}//childpage@config({path:'/parent/path/_/child/path'})exportdefaultclassParentextendsReact.Component{...}AJAX请求系统的ajax请求基于axios封装。基于restful规范,提供了5个方法:

get获取服务端数据,参数拼接在url上,以querystring方式发送给后端post新增数据,参数以body形式发送给后端put修改数据,参数以body形式发送给后端del删除数据,参数拼接在url上,以querystring方式发送给后端patch修改部分数据,参数以body形式发送给后端调用方式三种//第一种config装饰器ajax属性(推荐)importReact,{Component}from'react';importconfigfrom'src/commons/config-hoc';@config({ajax:true,...})exportdefaultclassSomePageextendComponent{componentDidMount(){this.props.ajax.get(...).then(...)}...}//第二种ajax装饰器importReact,{Component}from'react';import{ajaxHoc}from'src/commpons/ajax';@ajaxHoc()exportdefaultclassSomePageextendComponent{componentDidMount(){this.props.ajax.get(...).then(...)}...}//第三种直接引入ajax对象importReact,{Component}from'react';import{sxAjax}from'src/commpons/ajax';exportdefaultclassSomePageextendComponent{componentDidMount(){sxAjax.post(...).then(...);//组件卸载或者其他什么情况,需要打算ajax请求,可以用如下方式constajax=sxAjax.get(...);ajax.then(...).finally(...);ajax.cancel();}...}注:config、ajaxHoc方式做了封装,页面被卸载之后会自动打断未完成的请求

接收参数所有的ajax方法参数统一,都能够接受三个参数:参数|说明---|---url|请求地址params|请求传递给后端的参数options|请求配置,即axios的配置。

options配置参数说明axios配置可以接受axios参数successTip扩展的参数,成功提示errorTip扩展的参数,失败提示noEmpty扩展的参数,过滤掉''、null、undefined的参数,不提交给后端originResponse扩展参数,.then中可以拿到完整的response,而不只是response.data注:全局默认参数可以在src/commons/ajax.js中进行配置,默认baseURL='/api'、timeout=1000*60。

请求结果提示系统对ajax失败做了自动提示,开发人员可通过src/commons/handle-error.js进行配置;成功提示默认不显示,如果需要成功提示,可以配置successTip参数,或者.then()中自行处理;成功提示在src/commons/handle-success.js中配置;this.props.ajax.del("/user/1",null,{successTip:"删除成功!",errorTip:"删除失败!",noEmpty:true,});loading处理系统扩展了promise,提供了finally方法,用于无论成功还是失败,都要进行的处理。一般用于关闭loading

this.setState({loading:true});this.props.ajax.get('/url').then(...).finally(()=>this.setState({loading:false}));Mock模拟数据前后端并行开发,为了方便后端快速开发,不需要等待后端接口,系统提供了mock功能。基于mockjs

编写模拟数据在/src/mock目录下进行mock数据编写,比如:

import{getUsersByPageSize}from"./mockdata/user";exportdefault{"post/mock/login":(config)=>{const{userName,password}=JSON.parse(config.data);returnnewPromise((resolve,reject)=>{if(userName!=="test"||password!=="111"){setTimeout(()=>{reject({code:1001,message:"用户名或密码错误",});},1000);}else{setTimeout(()=>{resolve([200,{id:"1234567890abcde",name:"MOCK用户",loginName:"MOCK登录名",},]);},1000);}});},"post/mock/logout":{},"get/mock/user-center":(config)=>{const{pageSize,pageNum}=config.params;returnnewPromise((resolve)=>{setTimeout(()=>{resolve([200,{pageNum,pageSize,total:888,list:getUsersByPageSize(pageSize),},]);},1000);});},"getre:/mock/user-center/.+":{id:1,name:"熊大",age:22,job:"前端",},"post/mock/user-center":true,"put/mock/user-center":true,"deletere:/mock/user-center/.+":"id",};简化为了方便mock接口编写,系统提供了简化脚本(/src/mock/simplify.js),上面的例子就是简化写法

对象的key由methodurldelay,各部分组成,以空格隔开

字段说明method请求方法getpost等url请求的urldelay模拟延迟,毫秒默认1000调用系统封装的ajax可以通过以下两种方式,自动区分是mock数据,还是真实后端数据,无需其他配置

mock请求:

url以/mock/开头的请求/src/mock/url-config.js中配置的请求this.props.ajax.get('/mock/users').then(...);如果后端真实接口准备好之后,去掉url中的/mock即可

注:mock功能只有开发模式下开启了,生产模式不会开启mock功能,如果其他环境要开启mock使用MOCK=true参数,比如 MOCK=trueyarnbuild

样式系统使用less进行样式的编写。为了避免多人合作样式冲突,系统对src下的less文件启用了CssModule,css文件没有使用CssModule。

style.less

.root{width:100%;height:100%;}Some.jsx

import"/path/to/style.less";exportdefaultclassSomeextendsReact.Component{render(){return<divstyleName="root"></div>;}} 注:基础组件不使用CssModule,不利于样式覆盖;

主题使用less,通过样式覆盖来实现。

编写主题less文件中使用主题相关变量;编写/src/theme.less通过less-loader的modifyVars覆盖less中的变量;注:目前每次修改了theme.less需要重新yarnstart才能生效

参考AntDesign主题参考:https://ant-design.gitee.io/docs/react/customize-theme-cn导航布局为了满足不同系统的需求,提供了四种导航布局:

头部菜单左侧菜单头部+左侧菜单tab页方式更改方式用户可以通过页面有上角用户头像->设置页面进行选择(如果您为用户提供了此页面);开发人员可以通过修改src/models/index.js指定布局方式;不需要导航有些页面可能不需要显示导航,可以通过如下任意一种方式进行设置:

页面配置高级组件@config({noFrame:true,}) 浏览器url中noFrame=true参数/path/to?noFrame=trueTab标签页页面头部标签,有如下特性:

在当前tab标签之后打开新的tab标签;记录并恢复滚动条位置;保持页面状态(需要开启KeepPageAlive);tab标签右键操作;tab页操作API;tab标签拖拽排序;关闭一个二级页面tab,尝试打开它的父级;Tab操作APIsystemmodel(redux)中提供了如下操作tab页的方法:

API说明setCurrentTabTitle(title)设置当前激活的tab标题title:stirng或{text,icon}
声明:本文仅代表作者观点,不代表本站立场。如果侵犯到您的合法权益,请联系我们删除侵权资源!如果遇到资源链接失效,请您通过评论或工单的方式通知管理员。未经允许,不得转载,本站所有资源文章禁止商业使用运营!
下载安装【程序员客栈】APP
实时对接需求、及时收发消息、丰富的开放项目需求、随时随地查看项目状态

评论