2021SC@SDUSC
继上次分析了主要根组件MarkDownEditor之后,我发现seafile首页还是与App.js里的内容极为相似只是App.js最终是以id="wrapper"被渲染到页面,让人误以为App.js并没有用。这里展开对App.js文件下源码的分析。
在这里第一次遇到了以下的代码形式:
return (
<React.Fragment>
………………
</React.Fragment>
);
这里先了解以下React Fragment的用法。
React.Fragment 组件能够在不额外创建 DOM 元素的情况下,让 render()
方法中返回多个元素。一个常见模式是一个组件返回多个元素。Fragments 允许你将子列表分组,而无需向 DOM 添加额外节点。理解起来就是在我们定义组件的时候return里最外层包裹的div往往不想渲染到页面,那么就要用到我们的Fragment组件了。
因为我之前接触过Vue框架,这意思应该就和vue的<template ></ template >一样不会被渲染到页面。会被框架自动剔除。
详细用法可以参考博客:
https://blog.csdn.net/weixin_43720095/article/details/104943812
接下来看代码,先从以下引入的依赖看起,主要是src文件夹下components和pages子文件夹下的组件,因此猜测App.js是集合了各个组件功能的主要面板。首先先从组件的命名来进行初步猜测各个组件对应的功能。
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Router, navigate } from '@reach/router';
import MediaQuery from 'react-responsive';
import { Modal } from 'reactstrap';
import { siteRoot, canAddRepo, isDocs } from './utils/constants';
import { Utils } from './utils/utils';
import SystemNotification from './components/system-notification';
import SidePanel from './components/side-panel'; //引入侧边栏组件
import MainPanel from './components/main-panel'; //引入主面板组件
import DraftsView from './pages/drafts/drafts-view'; //引入草稿查看组件
import DraftContent from './pages/drafts/draft-content';
import FilesActivities from './pages/dashboard/files-activities';
import Starred from './pages/starred/starred';
import LinkedDevices from './pages/linked-devices/linked-devices';
import editUtilities from './utils/editor-utilities'; //引入文本编辑工具
import ShareAdminLibraries from './pages/share-admin/libraries'; //引入共享库页面
import ShareAdminFolders from './pages/share-admin/folders'; //引入共享文件夹
import ShareAdminShareLinks from './pages/share-admin/share-links'; //引入共享链接
import ShareAdminUploadLinks from './pages/share-admin/upload-links'; //引入共享上传链接
import SharedLibraries from './pages/shared-libs/shared-libs'; //引入公共库
import ShareWithOCM from './pages/share-with-ocm/shared-with-ocm';
import OCMRepoDir from './pages/share-with-ocm/remote-dir-view';
import MyLibraries from './pages/my-libs/my-libs'; //引入私人库
import MyLibDeleted from './pages/my-libs/my-libs-deleted'; //引入已删除的库
import PublicSharedView from './pages/shared-with-all/public-shared-view'; //猜测应该是公共视图
import LibContentView from './pages/lib-content-view/lib-content-view';
import Group from './pages/groups/group-view'; //引入组
import Groups from './pages/groups/groups-view';
import InvitationsView from './pages/invitations/invitations-view';
import Wikis from './pages/wikis/wikis';
import MainContentWrapper from './components/main-content-wrapper';
再来看App.js中与React组件生命周期有关的函数:
componentWillMount() { //组件将要挂载时先设置侧边栏关闭。避免组件覆盖。
if (!Utils.isDesktop()) {
this.setState({
isSidePanelClosed: true
});
}
}
componentDidMount() { //组件挂载后,将客户端URL导航到库 主要是初始化页面内容
// url from client e.g. http://127.0.0.1:8000/#common/lib/34e7fb92-e91d-499d-bcde-c30ea8af9828/
// navigate to library page http://127.0.0.1:8000/library/34e7fb92-e91d-499d-bcde-c30ea8af9828/
this.navigateClientUrlToLib();
// e.g. from http://127.0.0.1:8000/drafts/reviews/
// get reviews
// TODO: need refactor later
let href = window.location.href.split('/');
if (isDocs) {
this.getDrafts();
}
this.setState({currentTab: href[href.length - 2]});
}
navigateClientUrlToLib = () =>{ //导航的实现
if(window.location.hash && window.location.hash.indexOf('common/lib') != -1){ //进行位置判定
let splitUrlArray = window.location.hash.split('/'); //将位置拆分成数组,分解符是‘/’
let repoID = splitUrlArray[splitUrlArray.length - 2];//取出数组最后一个元素作为repoID
let url = siteRoot + 'library/' + repoID + '/'; //拼接url
navigate(url, {repalce: true});
}
}
以下是通过修改类组件的状态进行面板操作。
getDrafts = () => { //直接通过设对象的方式进行状态的设置
editUtilities.listDrafts().then(res => {
this.setState({
draftCounts: res.data.draft_counts,
draftList: res.data.data,
isLoadingDraft: false,
});
});
}
onCloseSidePanel = () => { //关闭侧边面板
this.setState({
isSidePanelClosed: !this.state.isSidePanelClosed
});
}
onShowSidePanel = () => { //开启侧边栏
this.setState({
isSidePanelClosed: !this.state.isSidePanelClosed
});
}
这一部分的函数通过获取url,拆分,拼接的过程值得学习,分析仍以注释的形式展现。
onSearchedClick = (selectedItem) => {
if (selectedItem.is_dir === true) {
this.setState({currentTab: '', pathPrefix: []});
let url = siteRoot + 'library/' + selectedItem.repo_id + '/' + selectedItem.repo_name + selectedItem.path;
//拼接站点根地址,选中项目的repo_id,repo_name以及选中项的path
navigate(url, {repalce: true}); //拼接后实现地址跳转
} else {
let url = siteRoot + 'lib/' + selectedItem.repo_id + '/file' + Utils.encodePath(selectedItem.path);
let isWeChat = Utils.isWeChat();
if (!isWeChat) { //失败跳转到空页面
let newWindow = window.open('about:blank');
newWindow.location.href = url;
} else {
location.href = url;
}
}
}
通过文章开头的方式进行组件的渲染: <React.Fragment>
render() {
let { currentTab, isSidePanelClosed } = this.state;
const home = canAddRepo ?
<MyLibraries path={ siteRoot } onShowSidePanel={this.onShowSidePanel} onSearchedClick={this.onSearchedClick} /> :
<SharedLibrariesWrapper path={ siteRoot } onShowSidePanel={this.onShowSidePanel} onSearchedClick={this.onSearchedClick} />;
return (
<React.Fragment>
<SystemNotification />
<div id="main">
<SidePanel isSidePanelClosed={this.state.isSidePanelClosed} onCloseSidePanel={this.onCloseSidePanel} currentTab={currentTab} tabItemClick={this.tabItemClick} draftCounts={this.state.draftCounts} />
<MainPanel>
<Router className="reach-router">
{home}
<FilesActivitiesWrapper path={siteRoot + 'dashboard'} onShowSidePanel={this.onShowSidePanel} onSearchedClick={this.onSearchedClick} />
<DraftsViewWrapper path={siteRoot + 'drafts'}
onShowSidePanel={this.onShowSidePanel}
onSearchedClick={this.onSearchedClick}
>
<DraftContent
path='/'
getDrafts={this.getDrafts}
isLoadingDraft={this.state.isLoadingDraft}
draftList={this.state.draftList}
updateDraftsList={this.updateDraftsList}
/>
</DraftsViewWrapper>
<StarredWrapper path={siteRoot + 'starred'} onShowSidePanel={this.onShowSidePanel} onSearchedClick={this.onSearchedClick} />
<LinkedDevicesWrapper path={siteRoot + 'linked-devices'} onShowSidePanel={this.onShowSidePanel} onSearchedClick={this.onSearchedClick} />
<ShareAdminLibrariesWrapper path={siteRoot + 'share-admin-libs'} onShowSidePanel={this.onShowSidePanel} onSearchedClick={this.onSearchedClick} />
<ShareAdminFoldersWrapper path={siteRoot + 'share-admin-folders'} onShowSidePanel={this.onShowSidePanel} onSearchedClick={this.onSearchedClick} />
<ShareAdminShareLinksWrapper path={siteRoot + 'share-admin-share-links'} onShowSidePanel={this.onShowSidePanel} onSearchedClick={this.onSearchedClick} />
<ShareAdminUploadLinksWrapper path={siteRoot + 'share-admin-upload-links'} onShowSidePanel={this.onShowSidePanel} onSearchedClick={this.onSearchedClick} />
<SharedLibrariesWrapper path={siteRoot + 'shared-libs'} onShowSidePanel={this.onShowSidePanel} onSearchedClick={this.onSearchedClick} />
<SharedWithOCMWrapper path={siteRoot + 'shared-with-ocm'} onShowSidePanel={this.onShowSidePanel} onSearchedClick={this.onSearchedClick} />
<OCMViaWebdavWrapper path={siteRoot + 'ocm-via-webdav'} onShowSidePanel={this.onShowSidePanel} onSearchedClick={this.onSearchedClick} />
<MyLibraries path={siteRoot + 'my-libs'} onShowSidePanel={this.onShowSidePanel} onSearchedClick={this.onSearchedClick} />
<MyLibDeleted path={siteRoot + 'my-libs/deleted/'} onSearchedClick={this.onSearchedClick} />
<LibContentView path={siteRoot + 'library/:repoID/*'} pathPrefix={this.state.pathPrefix} onMenuClick={this.onShowSidePanel} onTabNavClick={this.tabItemClick}/>
<OCMRepoDir path={siteRoot + 'remote-library/:providerID/:repoID/*'} pathPrefix={this.state.pathPrefix} onMenuClick={this.onShowSidePanel} onTabNavClick={this.tabItemClick}/>
<Groups path={siteRoot + 'groups'} onShowSidePanel={this.onShowSidePanel} onSearchedClick={this.onSearchedClick}/>
<Group
path={siteRoot + 'group/:groupID'}
onShowSidePanel={this.onShowSidePanel}
onSearchedClick={this.onSearchedClick}
onTabNavClick={this.tabItemClick}
onGroupChanged={this.onGroupChanged}
/>
<Wikis path={siteRoot + 'published'} onShowSidePanel={this.onShowSidePanel} onSearchedClick={this.onSearchedClick}/>
<PublicSharedView path={siteRoot + 'org/'} onShowSidePanel={this.onShowSidePanel} onSearchedClick={this.onSearchedClick} onTabNavClick={this.tabItemClick}/>
<InvitationsView path={siteRoot + 'invitations/'} onShowSidePanel={this.onShowSidePanel} onSearchedClick={this.onSearchedClick} />
</Router>
</MainPanel>
<MediaQuery query="(max-width: 767.8px)">
<Modal zIndex="1030" isOpen={!isSidePanelClosed} toggle={this.toggleSidePanel} contentClassName="d-none"></Modal>
</MediaQuery>
</div>
</React.Fragment>
);
}
}
最后将App组件render到id为’wrapper’的元素上。
ReactDOM.render(
<App />,
document.getElementById('wrapper')
);
其余一些重要组件的实现也会同步更新到此篇博客。未完……