scratch3.0系列章节列表
scratch3.0二次开发scratch3.0基本介绍(第一章)
scratch3.0二次开发运行scratch-gui项目并了解工程结构(第二章)
scratch3.0二次自定义品牌logo(第三章)
scratch3.0 scratch-gui中集成自定义用户系统1(第四章)
scratch3.0 scratch-gui中集成自定义用户系统2(第五章)
scratch3.0 scratch-gui中集成自定义用户系统3(第六章)
scratch3.0 scratch-gui中集成自定义用户系统4(第七章)
scratch3.0 scratch-gui中集成自定义用户系统5(第八章)
scratch3.0 scratch-gui中集成自定义用户系统6(第九章)
scratch3.0 scratch-gui中集成作品系统1(第九章)
scratch3.0 scratch-gui中集成作品系统2(第十章)
scratch3.0 scratch-gui中集成作品系统3(第十一章)
scratch3.0 scratch-gui加载自定义初始化角色(第十二章)
scratch3.0 scratch-gui打开自己平台云端作品(第十三章)
写在前面
该系列文章是为具有开发能力的朋友写作的,目的是帮助他们在刮擦3.0的基础上开发一套完整的集刮擦3.0编程工具,用户社区和作品云端存储及分享,品牌集成于一体的刮擦编程平台。如果您不是开发者,但想要拥有自己的教育平台和品牌,也欢迎学习交流和洽谈合作。
所以如果您是想学习scratch少儿编程课程,那请忽略该系列的文章。
前言
前面我们将scratch-gui工程成功建造运行起来,并且成功植入了我们的品牌徽标,这让我们对整个项目有了初步的认识。
现在我们已经有了scratch编程工具,但是我们还剩下两个主要的后台,用户社区后台和GUI的存储后台。目前Scratch3.0团队还没有发现社区替换和GUI的存储部分是否有开源计划,考虑到Scratch2.0的重新初始化开源,3.0社区初始化开源的可能也不大。
scratch-www项目提供了用户社区的功能,但是需要通过接口去分析它的后台的数据存储的结构,我觉得比较麻烦,不如我们自己来开发一个,集成到我们的编程工具scratch-gui中。
所以接下来我们的工作是自己来提供相关的两个前提平台,并与GUI集成到一起。
约会用户登录状态
我们先一步一步来,先做一个比较简单的用户系统,再一步一步迭代。
这一章,我们先来改造一下前面的scratch-gui,约会用户登录状态的检测。
在进入项目时,检测用户是否登录,如果用户未登录,则在右上角显示登录按钮,否则显示用户头像和姓名等基本信息。
先在reduser目录中创建user-state.js文件,用作记录用户的信息。
添加如下内容:
import keyMirror from 'keymirror';
const UserState = keyMirror({
NOT_LOGINED: null,
LOGINED: null
});
const UserStates = Object.keys(UserState)
const initialState = {
error: null,
userData: null,
loginState: UserState.NOT_LOGINED
};
const getIsLogined = loginState => (
loginState === UserState.LOGINED
);
const reducer = function (state, action) {
if (typeof state === 'undefined') state = initialState;
}
export {
reducer as default,
initialState as userStateInitialState,
UserState,
UserStates,
getIsLogined
};
在reducers/gui.js中,作为项目的用户相关的初始化信息。
在reducer/gui.js中日期用户状态:
import userStateReducer, {userStateInitialState} from './user-state';
```
加入到initialState中:
```
const guiInitialState = {
alerts: alertsInitialState,
assetDrag: assetDragInitialState,
blockDrag: blockDragInitialState,
cards: cardsInitialState,
colorPicker: colorPickerInitialState,
connectionModal: connectionModalInitialState,
customProcedures: customProceduresInitialState,
editorTab: editorTabInitialState,
mode: modeInitialState,
hoveredTarget: hoveredTargetInitialState,
stageSize: stageSizeInitialState,
menus: menuInitialState,
micIndicator: micIndicatorInitialState,
modals: modalsInitialState,
monitors: monitorsInitialState,
monitorLayout: monitorLayoutInitialState,
projectChanged: projectChangedInitialState,
projectState: projectStateInitialState,
projectTitle: projectTitleInitialState,
fontsLoaded: fontsLoadedInitialState,
restoreDeletion: restoreDeletionInitialState,
targets: targetsInitialState,
timeout: timeoutInitialState,
toolbox: toolboxInitialState,
vm: vmInitialState,
vmStatus: vmStatusInitialState,
userState: userStateInitialState
};
```
将reducer加入到guiReducer中:
```
const guiReducer = combineReducers({
alerts: alertsReducer,
assetDrag: assetDragReducer,
blockDrag: blockDragReducer,
cards: cardsReducer,
colorPicker: colorPickerReducer,
connectionModal: connectionModalReducer,
customProcedures: customProceduresReducer,
editorTab: editorTabReducer,
mode: modeReducer,
hoveredTarget: hoveredTargetReducer,
stageSize: stageSizeReducer,
menus: menuReducer,
micIndicator: micIndicatorReducer,
modals: modalReducer,
monitors: monitorReducer,
monitorLayout: monitorLayoutReducer,
projectChanged: projectChangedReducer,
projectState: projectStateReducer,
projectTitle: projectTitleReducer,
fontsLoaded: fontsLoadedReducer,
restoreDeletion: restoreDeletionReducer,
targets: targetReducer,
timeout: timeoutReducer,
toolbox: toolboxReducer,
vm: vmReducer,
vmStatus: vmStatusReducer,
userState: userStateReducer
});
下面去container / gui.jsx中为里面定义的GUI Component添加loginState这个道具,使用标识用户是否登录:
GUI.propTypes = {
assetHost: PropTypes.string,
children: PropTypes.node,
cloudHost: PropTypes.string,
error: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
fetchingProject: PropTypes.bool,
intl: intlShape,
isError: PropTypes.bool,
isLoading: PropTypes.bool,
isScratchDesktop: PropTypes.bool,
isShowingProject: PropTypes.bool,
loadingStateVisible: PropTypes.bool,
onProjectLoaded: PropTypes.func,
onSeeCommunity: PropTypes.func,
onStorageInit: PropTypes.func,
onUpdateProjectId: PropTypes.func,
onUpdateProjectTitle: PropTypes.func,
onUpdateReduxProjectTitle: PropTypes.func,
onVmInit: PropTypes.func,
projectHost: PropTypes.string,
projectId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
projectTitle: PropTypes.string,
telemetryModalVisible: PropTypes.bool,
vm: PropTypes.instanceOf(VM).isRequired,
loginState: PropTypes.bool
};
这个`loginState`道具的状态值来自于user-state.js中getIsLogined中检测当前的loginState(指状态中的)是否等于UserState.LOGINED:
const mapStateToProps = state => {
const loadingState = state.scratchGui.projectState.loadingState;
const loginState = state.scratchGui.userState.loginState;
return {
activeTabIndex: state.scratchGui.editorTab.activeTabIndex,
alertsVisible: state.scratchGui.alerts.visible,
backdropLibraryVisible: state.scratchGui.modals.backdropLibrary,
blocksTabVisible: state.scratchGui.editorTab.activeTabIndex === BLOCKS_TAB_INDEX,
cardsVisible: state.scratchGui.cards.visible,
connectionModalVisible: state.scratchGui.modals.connectionModal,
costumeLibraryVisible: state.scratchGui.modals.costumeLibrary,
costumesTabVisible: state.scratchGui.editorTab.activeTabIndex === COSTUMES_TAB_INDEX,
error: state.scratchGui.projectState.error,
isError: getIsError(loadingState),
isFullScreen: state.scratchGui.mode.isFullScreen,
isPlayerOnly: state.scratchGui.mode.isPlayerOnly,
isRtl: state.locales.isRtl,
isShowingProject: getIsShowingProject(loadingState),
loadingStateVisible: state.scratchGui.modals.loadingProject,
projectId: state.scratchGui.projectState.projectId,
soundsTabVisible: state.scratchGui.editorTab.activeTabIndex === SOUNDS_TAB_INDEX,
targetIsStage: (
state.scratchGui.targets.stage &&
state.scratchGui.targets.stage.id === state.scratchGui.targets.editingTarget
),
telemetryModalVisible: state.scratchGui.modals.telemetryModal,
tipsLibraryVisible: state.scratchGui.modals.tipsLibrary,
vm: state.scratchGui.vm,
loginState: getIsLogined(loginState)
};
};
现在container / gui.jsx中定义的Component GUI具有登录状态属性了,我们要把它传到menu-bar中,因为我们要在menu-bar中去控制右上角的显示状态。
在这个GUI组件中使用了components / gui / gui.jsx定义的GUIComponent这个组件,GUIComponent定义了整个项目的基本样式结构中,可以找到对MenuBar的使用。
首先,在GUIComponent的定义中日期之前定义的`loginState`:
const GUIComponent = props => {
const {
accountNavOpen,
activeTabIndex,
alertsVisible,
authorId,
authorThumbnailUrl,
authorUsername,
basePath,
backdropLibraryVisible,
backpackHost,
backpackVisible,
blocksTabVisible,
cardsVisible,
canCreateNew,
canEditTitle,
canRemix,
canSave,
canCreateCopy,
canShare,
canUseCloud,
children,
connectionModalVisible,
costumeLibraryVisible,
costumesTabVisible,
enableCommunity,
intl,
isCreating,
isFullScreen,
isPlayerOnly,
isRtl,
isShared,
loading,
renderLogin,
onClickAccountNav,
onCloseAccountNav,
onLogOut,
onOpenRegistration,
onToggleLoginOpen,
onUpdateProjectTitle,
onActivateCostumesTab,
onActivateSoundsTab,
onActivateTab,
onClickLogo,
onExtensionButtonClick,
onProjectTelemetryEvent,
onRequestCloseBackdropLibrary,
onRequestCloseCostumeLibrary,
onRequestCloseTelemetryModal,
onSeeCommunity,
onShare,
onTelemetryModalCancel,
onTelemetryModalOptIn,
onTelemetryModalOptOut,
showComingSoon,
soundsTabVisible,
stageSizeMode,
targetIsStage,
telemetryModalVisible,
tipsLibraryVisible,
vm,
loginState,
...componentProps
} = omit(props, 'dispatch');
...
再在使用MenuBar的地方也为MenuBar定义`loginState`属性,它的值就是GUIComponent传进来的`loginState`的值:
accountNavOpen={accountNavOpen}
authorId={authorId}
authorThumbnailUrl={authorThumbnailUrl}
authorUsername={authorUsername}
canCreateCopy={canCreateCopy}
canCreateNew={canCreateNew}
canEditTitle={canEditTitle}
canRemix={canRemix}
canSave={canSave}
canShare={canShare}
className={styles.menuBarPosition}
enableCommunity={enableCommunity}
isShared={isShared}
renderLogin={renderLogin}
showComingSoon={showComingSoon}
onClickAccountNav={onClickAccountNav}
onClickLogo={onClickLogo}
onCloseAccountNav={onCloseAccountNav}
onLogOut={onLogOut}
onOpenRegistration={onOpenRegistration}
onProjectTelemetryEvent={onProjectTelemetryEvent}
onSeeCommunity={onSeeCommunity}
onShare={onShare}
onToggleLoginOpen={onToggleLoginOpen}
onUpdateProjectTitle={onUpdateProjectTitle}
loginState={loginState}
/>
最后修改components / menu-bar.jsx中的MenuBar组件的显示,将右上角替换成:
{this.props.loginState ? (
className={classNames(
styles.menuBarItem,
styles.hoverable,
styles.mystuffButton
)}
>
className={styles.mystuffIcon}
src={mystuffIcon}
/>
id="account-nav"
place={this.props.isRtl ? 'right' : 'left'}
>
className={classNames(
styles.menuBarItem,
styles.hoverable,
styles.accountNavMenu
)}
>
className={styles.profileIcon}
src={profileIcon}
/>
{'scratch-cat'}
className={styles.dropdownCaretIcon}
src={dropdownCaret}
/>
) : }
如果用户已登录,就显示头像和姓名的样式(具体的用户信息需要跟后台打通,我们后面再实现):
否则显示登录按钮:
我们可以通过修改reducers / user-state.js中的loginState的初始值来查看效果:
loginState: UserState.NOT_LOGINED
loginState: UserState.LOGINED
这个值我们会在后面根据用户登录的token去获取。
为了与项目整体风格一致,我们修改这个登录按钮的样式,在菜单栏目录中添加login-button.css和login-button.jsx文件,内容分别如下:
@import "../../css/colors.css";
.login-button {
background: $data-primary;
}
import classNames from 'classnames';
import {FormattedMessage} from 'react-intl';
import PropTypes from 'prop-types';
import React from 'react';
import Button from '../button/button.jsx';
import styles from './login-button.css';
const LoginButton = ({
className,
onClick
}) => (
);
LoginButton.propTypes = {
className: PropTypes.string,
onClick: PropTypes.func
};
LoginButton.defaultProps = {
onClick: () => {}
};
export default LoginButton;
然后在menu-bar.jsx中如下使用:
这样看起来就好看多了:
好了,这里接收完成后,我们接下来就可以实现一个后台系统,然后对接后台系统登录和获取用户信息了。
上一章节链接:https://blog.csdn.net/tank_ft/article/details/104039006
下一章节链接:https://blog.csdn.net/tank_ft/article/details/104197077有不懂的欢迎访问我的博客获取我的联系方式,手把手教哈,博客地址:http://www.liyblog.top/p/1.html