react hooks权限管理系统

脚手架设置

/* npm5.2版本之前,执行npm init会在当前目录创建一个package.json文件
   npm5.2以后,本质上调用npx,自动将react-app补全为create-react-app,继而下载并创建应用 */
npm init react-app my-admin --typescript

/* 这个命令只能执行一次,而且不可逆转,它会把react-scripts封装的一些webpack配置等全部解压到项目目录,项目结构中会多出config和script两个目录*/
npm eject

多环境配置

create-react-app 的官方文档可以发现,create-react-app 默认是支持多个环境配置文件的:
.env:默认
.env.local:本地替代。该文件适用于除测试以外的所有环境
.env.development,.env.test,.env.production:环境特定的设置

// .env.development .env.production
REACT_APP_NODE_ENV='development'
REACT_APP_URL = '/api/'
REACT_APP_TARGET = 'http://192.168.7.221:8080'
REACT_APP_OUTPUT_DIR = 'tyjr-admin'
REACT_APP_PUBLICPATH = './'
REACT_APP_IMG_URL = 'http://192.168.7.221:8080'

// package.json
"scripts": {
    "start": "react-app-rewired start",
    "build:dev": "dotenv -e .env.development react-app-rewired build",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-scripts eject"
}

如果是ts,还要npm i @types/node -D

设置别名

// config/webpack.config.js
alias: {
	// 此时的appSrc 就是项目的src目录
    "@":path.resolve("src"),
},

设置代理

// create-react-app的版本在低于2.0,在package.json增加proxy配置
"proxy":{
    "/api/**":{
        "target":"https://easy-mock.com/mock/5c0f31837214cf627b8d43f0/",   //需要代理的地址
       "changeOrigin": true
    }
}

/* create-react-app的版本高于2.0,在package.json只能配置string类型, 配置成如下:*/
"proxy": "https://easy-mock.com/mock/5c0f31837214cf627b8d43f0/",

// 更好的配置,建立 src/setupProxy.js 文件,安装http-proxy-middleware
const proxy = require("http-proxy-middleware");
module.exports = function(app) {
    app.use(
        proxy("/api", {
            target: "http://localhost:3001/",
            changeOrigin: true,
             pathRewrite: {
		        "^/api": ""
		      }
        })
    )
    // 配置多个代理
    app.use(
        proxy("/test", {
            target: "https://easy-mock.com/mock/5c0f31837214cf627b8d43f0/",
            changeOrigin: true
        })
    );
};

动态生成路由和路由权限判断

先了解react-router-dom:包含了路由组件、路由匹配组件、导航组件

  • 路由组件
    提供了两种路由组件: BrowserRouter, HashRouter其中BrowserRouter 是基于HTML5 history API (pushState, replaceState, popstate)事件
    当然与之对应的还有HashRouter是基于window.location.hash
  • 路由匹配组件
    由匹配组件有两种:Route和Switch,Switch把多个路由组合在一起
    对于一个组件,可以设置三种属性:component、render、children来渲染出对应的内容
  • 导航组件
    有三种常用的导航组件,分别是:<Link>、<NavLink>、<Redirect><NavLink>是一种特殊的Link组件,匹配路径时,渲染的a标签带有active

react-router和react-router-dom不同之处就是后者比前者多出了 这样的 DOM 类组件

生成路由组件

为什么要生成路由组件?
当hash或者history跳转时,只是路径发生变化,内容不会变,所以还需要生成路径对应的组件(又称路由组件,即通知react去构建这个组件内容)

生成动态路由的方法:这三种方法可以一起使用

// 1、通过Route组件的component属性生成
import loadable from '@loadable/component'//动态加载组件,解决import()时变量失效问题
<Route exact path={pathname} component={loadable(() => import(`./${item.componentPath}`))} />

// 2、通过Route组件的render属性生成,比如嵌套路由中使用
genRouter(list){
 let routerList= list.map((item)=>{
      	 // 判断是否有子判断
         if(item.menuChilds.length===0){//无子菜单
             return  <Route exact key={item.menuId} path={item.menuUrl} component={ loadable(() => import(`./${item.componentPath}`))}/>
         }else{
             // 有子菜单
             //判断是否包含子组件
              if(item.isContainChildren){ //嵌套在父级中,记得在在父组件中,添加 {this.props.children}在要嵌套的位置
                  return  <Route key={item.menuId} path={item.menuUrl} render={() =>{
                      let ComponentName =loadable(() => import(`./${item.componentPath}`));
                      return <ComponentName {...this.props}>
                          {this.genRouter(item.menuChilds)}
                      </ComponentName>
                  }}>
                  </Route>
              }else{ //不嵌套显示
                  return [...this.bindRouter(item.menuChilds),<Route key={item.menuId} path={item.menuUrl} component={ loadable(() => import(`./${item.componentPath}`))}/>]
              }


         }
     })
   return routerList;
}


/* 3、通过react-router-config配置静态路由
其源码就是一个高阶函数 利用一个map函数生成静态路由,底层还是用render属性
*/
import { renderRoutes } from 'react-router-config'
const routes = [
    {
        path: '/login',
        component: Login,
    },
]
<Switch>
  {renderRoutes(routes)}
</Switch>

component和render的区别:
this 指向问题,component={组件}组件直接挂载到router下面,render={()={组件}}本身就是个组件,组件内部在引用你定义的组件,相当于又加了一层,this已经不一样了

路由权限判断

vue是通过路由中的全局守卫,进入路由时判断是否登录或注册,是就执行next展示当前页面,否就跳到登录页

react没有路由守卫,需要自己写,react如何判断进入路由呢?使用react-router,在react render的时候通过switch进行路由匹配
思路:判断是否有token,没有就跳到登录页,有就动态生成路由表,跳到目标路由

const RouterAuth: FC<RouterAuthProps> = (props) => {
	// ...省略
	// 在redux中请求接口,所以可以通过store拿到数据生成菜单列表
	useEffect(() => {
	   dispatch(SetMenu())
	   setTimeout(()=>{
	     const arr = store.getState().userReducer.menu
	     setRouterList([...menuList, ...arr])
	   }, 200)
	},[])
	
	// 动态生成路由
	const generateRoute = (list:any) =>{
	    return list.map((item:any, index:number)=>{
	      return <Route exact key={`${index}_${item.menuId}`} path={item.menuPath} component={ loadable(() => import(`@/pages${item.menuPath}/index`))}/>
	    })
	}
	const renderRouter=()=>{
	    // 如果是登录状态
	    if(!!token){
	      // 如果进入登录页面,则直接重定向至首页
	      if(pathname === '/login' || pathname === '/'){
	        return <Redirect to='/dashboard' />
	      }else{ 
	        // 动态生成路由表,跳到目标路由
	        return <Layout>{generateRoute(routerList)}</Layout>
	      }
	    }else{ //非登录状态,如果是白名单直接进入,否则跳转到登录页
	        return <Route path="/login" component={LoginPage}/>
	    }
	}
	
	return (
	 <Router> 
	   <Switch> 
	     <Route path="/" exact render={()=><Redirect to="/login"/>} />
	     <Route path="/404" component={NotFoundPage}/>
	     <Route path="/" render={()=> renderRouter()}/> 
	   </Switch>
	</Router>
	)
}

也可以给每一个用户权限设定一个可以访问的路径数组,通过比较跳转的地址是否存在这个数组当中来进行相应的展示

<Switch>
   {routes.map(item => {
        return (
            <Route
                key={item.path}
                path={item.path}
                exact={item.exact}
                render={props =>
                    !auth ? (
                        <item.component {...props} />
                    ) : item.auth && item.auth.indexOf(auth) !== -1 ? (
                        <item.component {...props} />
                    ) : (
                        // 这里也可以跳转到 403 页面
                        <Redirect to='/404' {...props} />
                    )
                }></Route>
        )
    })}
    <Redirect to='/404' />
</Switch>

其他方案

登录时路由重定向

登录时判断location有没有search,有的话获取search,跳转到重定向地址,否则跳到系统首页

动态生成菜单

思路:动态生成路由组件时已经请求到菜单列表,存放在store里,所以只需要根据返回的菜单数据把菜单转成ant框架的菜单

兼容ie问题

1、使用阿里妈妈字体图标库,ie10报错,无法获取未定义或 null 引用的属性“firstChild”
解决:把引用的js移到body标签代码结束之后。因为console.log(target)为null,找到document.body是null

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值