OHIF Viewer 开发笔记(一):添加登录页面
项目组件概览
在添加启动页面之前,需要对项目的框架结构有一个大致的了解。使用 React 官方提供的 React Developer Tools 可以在浏览器的调试窗口中看到StudyList页面的Component Tree:
图中左侧显示的是组件树,右侧显示组件的props属性。
上图的组件树中,App组件是项目的顶层组件,它的render方法返回的内容如下:
<Provider store={store}>
<AppProvider config={this._appConfig}>
<I18nextProvider i18n={i18n}>
<Router basename={routerBasename}>
<WhiteLabelingContext.Provider value={whiteLabeling}>
<SnackbarProvider service={UINotificationService}>
<DialogProvider service={UIDialogService}>
<ModalProvider modal={OHIFModal} service={UIModalService}>
<OHIFStandaloneViewer />
</ModalProvider>
</DialogProvider>
</SnackbarProvider>
</WhiteLabelingContext.Provider>
</Router>
</I18nextProvider>
</AppProvider>
</Provider>
组件嵌套最内层的OHIFStandaloneViewer组件是非常重要的组件,它使用react-router 提供的路由(Route)功能根据当前url返回对应的页面(组件)。
const routes = RoutesUtil.getRoutes(appConfig);
const currentPath = this.props.location.pathname;
const noMatchingRoutes = !routes.find(r =>
matchPath(currentPath, {
path: r.path,
exact: true,
})
);
console.log(routes);
return (
<>
<NProgress isAnimating={this.state.isLoading}>
{({ isFinished, progress, animationDuration }) => (
<Container
isFinished={isFinished}
animationDuration={animationDuration}
>
<Bar progress={progress} animationDuration={animationDuration} />
</Container>
)}
</NProgress>
<Route exact path="/silent-refresh.html" onEnter={RoutesUtil.reload} />
<Route exact path="/logout-redirect.html" onEnter={RoutesUtil.reload} />
{!noMatchingRoutes &&
routes.map(({ path, Component }) => (
<Route key={path} exact path={path}>
{({ match }) => (
<CSSTransition
in={match !== null}
timeout={300}
classNames="fade"
unmountOnExit
onEnter={() => {
this.setState({
isLoading: true,
});
}}
onEntered={() => {
this.setState({
isLoading: false,
});
}}
>
{match === null ? (
<></>
) : (
<Component match={match} location={this.props.location} />
)}
</CSSTransition>
)}
</Route>
))}
{noMatchingRoutes && <NotFound />}
</>
);
上述代码使用routes.map()方法将Route path和组件映射对应起来,我们使用console.log()方法查看routes的值:
routes数组中存储了5个元素,对应6个路径。其中根路径"/“和”/studylist"对应的都是studylist页面;"/local"页面功能为Drag and Drop DICOM files here to load them in the Viewer,Or click to Load files or Load folders from dialog。
修改思路&实现
- React项目默认会从localhost:3000启动,也就是根目录"/"。为了添加启动或登录页面,必须首先渲染一个我们自己定义的Home组件,然后在Home组件中设置链接跳转到studylist页面。
import React from 'react';
import { BrowserRouter as Router, Switch, Route, Link } from 'react-router-dom';
import App from './App.js';
export default function Home(props) {
return (
<Router>
<Switch>
<Route exact path="/studylist">
<App {...props} />
</Route>
<Route exact path="/about">
<About />
</Route>
<Route exact path="/">
<Welcome />
</Route>
</Switch>
</Router>
);
}
function About() {
return (
<div>
<h2 color="blue">About</h2>
</div>
);
}
function Welcome() {
return (
<div>
<h2 color="blue" align="center">
欢迎来到直结肠癌诊断一体化平台!
</h2>
<ul>
<li>
<Link to="/studylist">Studylist</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
</ul>
<hr />
</div>
);
}
上述代码使用react-router 提供的路由功能实现了页面间的跳转。Home组件并不是真正的“首页”,它的功能只是根据当前URL渲染不同的组件。当URL为"/"时,渲染自定义的Welcome组件,Welcome组件包含两个链接(Link将在渲染时被替换成a标签)。
- 之后,我们需要在OHIFStandaloneViewer的路由表中将“/”和Home组件对应,"/studylist"和原StudylistRouting组件对应。
我们找到获取routes的RoutesUtil.getRoutes()方法,其中定义的默认route为:
const ROUTES_DEF = {
default: {
viewer: {
path: '/viewer/:studyInstanceUIDs',
component: ViewerRouting,
},
standaloneViewer: {
path: '/viewer',
component: StandaloneRouting,
},
list: {
path: ['/studylist', '/'],
component: StudyListRouting,
condition: appConfig => {
return appConfig.showStudyList;
},
},
local: {
path: '/local',
component: ViewerLocalFileData,
},
IHEInvokeImageDisplay: {
path: '/IHEInvokeImageDisplay',
component: IHEInvokeImageDisplay
},
}
将list对象替换为:
// list: {
// path: ['/studylist', '/'],
// component: StudyListRouting,
// condition: appConfig => {
// return appConfig.showStudyList;
// },
// },
home: {
path: '/',
component: Home,
},
list: {
path: '/studylist',
component: StudyListRouting,
condition: appConfig => {
return appConfig.showStudyList;
},
},
即可在OHIFStandaloneViewer组件中实现路由,url为"/“时导向Home组件,url为”/studylist"时导向StudyingRouting组件。
此时重启项目,首先会进入Home组件渲染的页面,点击Studylist链接就进入了Studylist页面。
但如果进入study viewer页面,页面左上角的“Study List”链接会返回到"/",需要把它修改为“/studylist”。使用React Development Tools定位到该链接由Header组件渲染,它的LinkPath prop由Viewer组件提供。
找到Viewers\platform\viewer\src\connectedComponents目录下的Viewer.js文件,将render方法return中 ConnectedHeader 元素的LinkPath prop由/改为/studylist。(原有代码被注释掉)
linkPath={
// appContext.appConfig.showStudyList ? '/' : undefined
appContext.appConfig.showStudyList ? '/studylist' : undefined
}
这样我们就将一个简单的页面添加到了OHIF Viewer的最前面,可以实现用户登录的功能。
简化的修改过程
- 在Viewers\platform\viewer\src目录(App.js和OHIFStandaloneViewer.js的同级目录)下添加Home.js文件(为简化只粘贴必要代码):
import React from 'react';
import { BrowserRouter as Router, Switch, Route, Link } from 'react-router-dom';
import App from './App.js';
export default function Home(props) {
return (
<Router>
<Switch>
<Route exact path="/studylist">
<App {...props} />
</Route>
<Route exact path="/about">
<About />
</Route>
<Route exact path="/">
<Welcome />
</Route>
</Switch>
</Router>
);
}
function About() {
return (
<div>
<h2 color="blue">About</h2>
</div>
);
}
function Welcome() {
return (
<div>
<h2 color="blue">
欢迎来到直结肠癌诊断一体化平台!
</h2>
<ul>
<li>
<Link to="/studylist">Studylist</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
</ul>
<hr />
</div>
);
}
- 找到Viewers\platform\viewer\src\routes\RoutesUtil.js文件,在顶部引入Home组件:
import Home from '../Home.js';
将ROUTES_DEF常量修改为:
// list: {
// path: ['/studylist', '/'],
// component: StudyListRouting,
// condition: appConfig => {
// return appConfig.showStudyList;
// },
// },
home: {
path: '/',
component: Home,
},
list: {
path: '/studylist',
component: StudyListRouting,
condition: appConfig => {
return appConfig.showStudyList;
},
},
注释中为原有代码,未注释部分为新添加的部分。
- 找到Viewers\platform\viewer\src\connectedComponents目录下的Viewer.js文件,将render方法return中 ConnectedHeader 元素的LinkPath prop由/改为/studylist。(原有代码被注释掉)
linkPath={
// appContext.appConfig.showStudyList ? '/' : undefined
appContext.appConfig.showStudyList ? '/studylist' : undefined
}