父传子
使用props传值:子组件通过this.props进行接收就可以了
父组件
import { PureComponent, Fragment } from 'react'import DocumentTitle from 'react-document-title'import router from 'umi/router'import styled from 'styled-components'import withStyled from '@@/styles/withStyled'import MineList from '../widgets/MineList' // 子组件const MineInfo = withStyled(styled.div`position: relative;z-index: 10;margin: -20px 0 0;padding: 20px 20px 0;width: 100%;// backgroundColor是withStyled里面的变量background-color: ${(props) => props.theme.backgroundColor};border-radius: 20px 20px 0 0;`)const list = [{icon: iconPlay,title: '我的课程',rightIcon: iconRight,onClick: () => router.replace({ pathname: '/lesson' })},{icon: iconLogo,title: '关于小帮',rightIcon: iconRight,onClick: () => router.push({ pathname: '/document/about' })}]class MinePage extends PureComponent {constructor(props) {super(props)}render() {const { account: { account = {} } } = this.propsreturn (<DocumentTitle title='我的'><Fragment><MineInfo>{list.map((item, index) => (// {...item} 向子组件传递参数// {...item} 向子组件传递参数// {...item} 向子组件传递参数<MineList {...item} key={index} /> // 子组件))}</MineInfo></Fragment></DocumentTitle>)}}export default MinePage
子组件
import PropTypes from 'prop-types'import styled from 'styled-components'import withStyled from '@@/styles/withStyled'const Container = withStyled(styled.div`width: 100%;height: 76px;display: flex;align-items: center;img:nth-of-type(1) {width: 28px;height: 28px;margin: 0 16px 0 0;}span {flex: 1;}img:nth-of-type(2) {width: 20px;height: 20px;}`)const MineList = ({ title, icon, rightIcon, onClick }) => {return (<Container onClick={onClick}><img src={icon} /><span>{title}</span><img src={rightIcon} /></Container>)}MineList.propTypes = {title: PropTypes.string.isRequired,icon: PropTypes.string.isRequired,rightIcon: PropTypes.string.isRequired,onClick: PropTypes.func}export default MineList
子传父—不带参数
子组件向父组件传值需要绑定一个事件,然后事件是父组件传递过来的this.props.event来进行值的更替
**
父组件
import { PureComponent } from 'react'import router from 'umi/router'import PropTypes from 'prop-types'import styled, { createGlobalStyle } from 'styled-components'import withStyled from '@@/styles/withStyled'import GlobalModalRich from '@@/components/Modal/Rich'import FeedBack from '../FeedBack' // 子组件const NavbarPaddingSafe = createGlobalStyle`#app {padding-bottom: 49px;}`const NavbarContainer = withStyled(styled.div`position: fixed;left: 0;right: 0;bottom: 0;margin: 0 auto;width: 100%;height: auto;max-width: ${(props) => props.theme.maxWidth};box-shadow: 0 -6px 12px 0 rgba(0, 0, 0, 0.04);background-color: #ffffff;`)const NavbarGroup = withStyled(styled.div`display: flex;align-items: center;padding: 7px 0 6px;`)const NavbarButton = withStyled(styled.div`flex: 25;padding: 22px 0 0;font-size: 10px;line-height: 14px;color: ${(props) => props.theme.font400};text-align: center;background-size: 20px 20px;background-repeat: no-repeat;background-position: top center;background-image: url(${(props) => props.image});`)class ResourceNavbarButton extends PureComponent {constructor(props) {super(props)// uniqueId、feedbackStatus是父组件传递进来的值const { uniqueId, feedbackStatus } = this.propsthis.uniqueId = uniqueIdthis.state = {feedbackStatus: feedbackStatus}}componentWillUnmount() {GlobalModalRich.hide()}action = {handleShowFeedback: () => {const feedback = {title: '评价本节',// 调用子组件// handleConfirm接收子组件的事件或参数// handleConfirm接收子组件的事件或参数// handleConfirm接收子组件的事件或参数children: <FeedBack uniqueId={this.uniqueId} handleConfirm={() => { this.action.handleFeedback() }} />,onClick: GlobalModalRich.hide}GlobalModalRich.show(feedback)},// 接收到子组件到事件或状态后,触发到事件// 接收到子组件到事件或状态后,触发到事件// 接收到子组件到事件或状态后,触发到事件handleFeedback: () => {this.setState({ feedbackStatus: true })this.props.handleConfirm()}}render() {const { feedbackStatus } = this.stateconst { noteListStatus } = this.propsreturn (<NavbarContainer className='ios-padding-safe'><NavbarPaddingSafe /><NavbarGroup><NavbarButton image={iconFeedback} onClick={() => this.action.handleShowFeedback()}><span>评价本节</span></NavbarButton></NavbarGroup></NavbarContainer>)}}ResourceNavbarButton.propTypes = {uniqueId: PropTypes.string.isRequired,feedbackStatus: PropTypes.bool.isRequired,noteListStatus: PropTypes.bool.isRequired}export default ResourceNavbarButton
子组件
import { PureComponent } from 'react'import PropTypes from 'prop-types'import styled from 'styled-components'import classnames from 'classnames'import withStyled from '@@/styles/withStyled'import resourceService from '@@/services/resource'import GlobalModalRich from '@@/components/Modal/Rich'import iconBad from './icon-bad.png'import iconBadChecked from './icon-bad-checked.png'import iconGood from './icon-good.png'import iconGoodChecked from './icon-good-checked.png'import iconSimple from './icon-simple.png'import iconSimpleChecked from './icon-simple-checked.png'const Container = withStyled(styled.div`display: flex;align-items: center;justify-content: center;`)const Item = withStyled(styled.div`flex: 1;font-size: 14PX;display: flex;flex-direction: column;align-items: center;color: ${(props) => props.theme.font100};padding: 28px 0 0;background-size: 24px 24px;background-repeat: no-repeat;background-position: top center;span {font-size: 10PX;color: ${(props) => props.theme.font400};}&.focus {span {color: #FFC300;}}&.bad {background-image: url(${iconBad});&.focus {background-image: url(${iconBadChecked});}}&.good {background-image: url(${iconGood});&.focus {background-image: url(${iconGoodChecked});}}&.simple {background-image: url(${iconSimple});&.focus {background-image: url(${iconSimpleChecked});}}`)class FeedBack extends PureComponent {constructor(props) {super(props)this.state = {checkedValue: ''}}action = {handleFetch: async (type, name) => {const { checkedValue } = this.stateif (checkedValue) {return false}const { uniqueId } = this.propsthis.setState({checkedValue: name})try {await resourceService.feedback(uniqueId, { feedBackType: type })} catch (error) {console.warn(error.message)} finally {setTimeout(GlobalModalRich.hide, 500)// 向父组件发送事件,也可以传递参数// 向父组件发送事件,也可以传递参数// 向父组件发送事件,也可以传递参数this.props.handleConfirm()}}}render() {const { checkedValue } = this.stateconst badClassName = classnames('bad', { focus: checkedValue === 'bad' })const goodClassName = classnames('good', { focus: checkedValue === 'good' })const simpleClassName = classnames('simple', { focus: checkedValue === 'simple' })return (<Container><Item className={badClassName} onClick={() => this.action.handleFetch(1, 'bad')}><span>没听懂</span></Item><Item className={goodClassName} onClick={() => this.action.handleFetch(2, 'good')}><span>有收获</span></Item><Item className={simpleClassName} onClick={() => this.action.handleFetch(0, 'simple')}><span>太简单</span></Item></Container>)}}FeedBack.propTypes = {uniqueId: PropTypes.string.isRequired}export default FeedBack
子传父—带参数
父组件
import { PureComponent, Fragment } from 'react'import DocumentTitle from 'react-document-title'import ExerciseCard from '../widgets/ExerciseCard'class DetailPage extends PureComponent {constructor(props) {super(props)}action = {handleChangeDate: (exerciseId, type, value) => {console.log(exerciseId, type, value)// 获取子组件传递过来的值},}render(){return (<DocumentTitle title={title}><Fragment>{exerciseList.map(item => (<ExerciseCard{...item}isFinished={isFinished}handleChangeDate={(exerciseId, type, value) => this.action.handleChangeDate(exerciseId, type, value)}key={item.rowKey}/>))}</Fragment></DocumentTitle>)}}
子组件
import PropTypes from 'prop-types'import styled from 'styled-components'import withStyled from '@@/styles/withStyled'import classnames from 'classnames'import iconRadio from './icon-radio.png'import iconRadioCorrect from './icon-radio-correct.png'import iconCheckout from './icon-checkout.png'import iconCheckoutCorrect from './icon-checkout-correct.png'import iconCorrect from './icon-correct.png'import iconWrong from './icon-wrong.png'const Container = withStyled(styled.div`position: relative;padding: 16px 0 8px;width: 100%;`)const Result = withStyled(styled.img`position: absolute;top: 0;right: 0;width: 72px;height: 72px;`)const Order = withStyled(styled.div`height: 20px;font-size: 16px;font-weight: bold;color: ${props => props.theme.font100};line-height: 20px;`)const Title = withStyled(styled.div`margin: 8px 0 4px;font-size: 16px;text-align: justify;text-align-last: left;line-height: 24px;color: ${props => props.theme.font100};`)const Answer = withStyled(styled.div`position: relative;display: flex;align-items: center;margin: 0 0 8px;padding: 0 0 0 40px;height: 41px;background-color: #f5f7fa;border-radius: 8px;&:before {position: absolute;left: 12px;top: 50%;transform: translateY(-50%);display: inline-block;content: '';width: 20px;height: 20px;background: url(${props => props.icon});background-repeat: no-repeat;background-size: cover;}&:last-of-type {margin: 0 0 24px;}&.selected {background-color: rgba(255, 221, 0, 0.1);}`)const Analysis = withStyled(styled.div`margin: 0 0 40px;padding: 16px 12px;background-color: #e5e9f2;border-radius: 8px;border: 1px solid rgba(229, 233, 242, 1);`)const CorrectAnswer = withStyled(styled.div`font-size: 14px;line-height: 18px;color: ${props => props.theme.font100};`)const AnswerAnalysis = withStyled(styled.div`margin: 4px 0 0;font-size: 14px;line-height: 22px;color: ${props => props.theme.font100};`)const judgeResult = status => {switch (+status) {case 0:return ''case 1:return iconCorrectcase 2:return iconWrongdefault:return ''}}const judgeType = type => {if (type === 0) {const typeDescription = '单选题'const iconType = iconRadioconst iconSelect = iconRadioCorrectreturn { typeDescription, iconType, iconSelect }} else if (type === 1) {const typeDescription = '多选题'const iconType = iconCheckoutconst iconSelect = iconCheckoutCorrectreturn { typeDescription, iconType, iconSelect }}}const judgeLabel = index => {return String.fromCharCode(65 + index)}const ExerciseCard = ({ isFinished, exerciseId, title, type, status, content, options, analysis, handleChangeDate }) => {const iconResult = judgeResult(status)const { typeDescription, iconType, iconSelect } = judgeType(type)let rightResult = ''return (<Container>{iconResult && <Result src={iconResult} />}<Order>{title}【{typeDescription}】</Order><Title>{content}</Title><div>{options.map((item, index) => {const { content, isUserAnswer, isCorrect } = itemconst label = judgeLabel(index)if (isCorrect) {rightResult += label}const changeResult = isFinished ? () => { } : () => handleChangeDate(exerciseId, type, index)const icon = isUserAnswer ? iconSelect : iconTypereturn (<Answer className={classnames({ selected: isUserAnswer })} icon={icon} onClick={changeResult} key={index}>{label}.{content}</Answer>)})}</div>{isFinished && (<Analysis><CorrectAnswer>正确答案:{rightResult}</CorrectAnswer><AnswerAnalysis>解析:{analysis}</AnswerAnalysis></Analysis>)}</Container>)}ExerciseCard.propTypes = {isFinished: PropTypes.bool,exerciseId: PropTypes.number,title: PropTypes.string,type: PropTypes.number,status: PropTypes.number,content: PropTypes.string,options: PropTypes.array,analysis: PropTypes.string,handleChangeDate: PropTypes.func,}export default ExerciseCard
中间件
withStyled.js—基础颜色组件
import { forwardRef } from 'react'import { ThemeProvider, keyframes } from 'styled-components'export const theme = {// 基础颜色primaryColor: 'rgba(255, 221, 0, 1)',secondaryColor: 'rgba(255, 196, 1, 1)',linkColor: 'rgba(24, 170, 242, 1)',borderColor: 'rgba(229, 233, 242, 1)',backgroundColor: 'rgba(245, 247, 250, 1)',maskColor: 'rgba(0, 0, 0, 0.5)',shadowColor: 'rgba(200, 200, 200, 0.05)',highLightColor: 'rgba(34, 34, 34, 1);',// 基金相关increaseColor: '#FC4447',decreaseColor: '#3CC86B',// 层级maskZindex: 100,popupZindex: 200,dialogZindex: 300,// 字体颜色font100: '#324057',font200: '#475669',font300: '#5E6D82',font400: '#8492A6',font500: '#99A9BF',font600: '#C0CCDA',importantfont: '#FF8026',// 宽度maxWidth: '480PX',// 加载器loaderPrimaryColor: 'rgba(239, 242, 247, 1)',loaderSecondaryColor: 'rgba(239, 242, 247, 0.6)'}export const autofill = keyframes`from {background - color: transparent;}to {background - color: transparent;}`export const popupCenter = keyframes`0% {transform: translateY(-50%) scale(0.8);}100% {transform: translateY(-50%) scale(1);}`export const riseNavbar = keyframes`0% {bottom: -64px;}100% {bottom: 0;}`const withStyled = (Component) => {const StyledComponent = (props, ref) => (<ThemeProvider theme={theme}><Component ref={ref} {...props} /></ThemeProvider>)return forwardRef(StyledComponent)}export default withStyled
GlobalModalRich.js—模态框组件
import PropTypes from 'prop-types'import styled from 'styled-components'import withStyled from '@@/styles/withStyled'import { MountPoint } from '@@/utils/dom'import iconClose from '@@/assets/icons/icon-close.png'const MaskBasic = withStyled(styled.div`position: fixed;left: 0;right: 0;top: 0;bottom: 0;background-color: ${(props) => props.theme.maskColor};z-index: ${(props) => props.theme.maskZindex};`)const MaskCenter = withStyled(styled.div`position: absolute;left: 0;right: 0;top: 45%;transform: translateY(-50%);padding: 20px;text-align: center;z-index: ${(props) => props.theme.dialogZindex};animation: ${popupCenter} 200ms linear forwards;`)const ModalContainer = withStyled(styled.div`display: inline-block;margin: 0 auto;padding: 25px 20px;max-width: 360px;min-width: 240px;width: 86%;text-align: center;border-radius: 10px;background-color: #ffffff;`)const ModalTitle = withStyled(styled.h4`font-size: 20px;font-weight: bold;line-height: 1.5;color: ${(props) => props.theme.font100};text-align: center;`)const ModalContent = withStyled(styled.div`padding: 30px 0 25px;`)const ModalClose = styled.div`margin: 40px auto 0;width: 26px;height: 26px;background-size: 100% 100%;background-repeat: no-repeat;background-image: url(${iconClose});`const ModalComponent = ({ title, children, onClick }) => (<MaskBasic onClick={onClick}><MaskCenter><ModalContainer onClick={(e) => e.stopPropagation()}><ModalTitle>{title}</ModalTitle><ModalContent>{children}</ModalContent></ModalContainer><ModalClose /></MaskCenter></MaskBasic>)ModalComponent.defaultProps = {title: '提示',children: '请输入提示内容',onClick: () => { }}ModalComponent.propTypes = {title: PropTypes.string.isRequired,children: PropTypes.node.isRequired,onClick: PropTypes.func.isRequired}class GlobalModalRich extends MountPoint {hide = () => {this.removeMountPoint()}show = (options) => {this.render(<ModalComponent onClick={this.hide} {...options} />)}}export default new GlobalModalRich()
