【花般绽放】balibali

先放项目地址:https://github.com/1067011734/balibali
感谢无私的程序员们分享
我们边看效果边看代码
项目运行出来的效果
1037363-20190522172457162-2087453827.png
先看Home页面
轮播
1037363-20190522172949893-31806968.png

//src\pages\Home\model\Carousel.js
import React, { Component } from 'react'
import { Carousel } from 'antd-mobile'
import img from '@/images/banner/1.jpg'
import img2 from '@/images/banner/2.jpg'
import img3 from '@/images/banner/3.jpg'

class app extends Component {
  state = {
    data: ['1', '2', '3'],
    imgHeight: 176,
  }

  componentDidMount() {
    // simulate img loading
    setTimeout(() => {
      this.setState({
        data: [img, img2, img3],
      });
    }, 100);
  }

  render() {
    return (
      <Carousel
        autoplay={false}
        infinite
        beforeChange={(from, to) => console.log(`slide from ${from} to ${to}`)}
        afterChange={index => console.log('slide to', index)}
      >
        {this.state.data.map((val, index) => (
          <a
            key={index}
            style={{ display: 'inline-block', width: '100%', height: this.state.imgHeight }}
          >
            <img
              src={val}
              alt="val"
              style={{ width: '100%', verticalAlign: 'top', height: this.state.imgHeight }}
              onLoad={() => {
                // fire window resize event to change height
                // 若用非手机模式打开,imgheight会因为整个浏览器的长度100%自适应造成100%全屏,手机模式加载则没影响
                window.dispatchEvent(new Event('resize'));
                this.setState({ imgHeight: 'auto' })
              }}
            />
          </a>
        ))}
      </Carousel>
    )
  }
}

export default app

1037363-20190522173200469-2078866162.png
这里也是封装成组件做的

//src\components\Card\index.js
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import style from './index.less'

class app extends Component {
  PropTypes={
    list: PropTypes.array,
    className:PropTypes.string,
  }
  static defaultProps ={
    list :[],
  }

  state = {
  }
componentDidMount(){
}
componentWillReceiveProps(nextProps){
}

close=()=>{
  this.setState({open:false})
  this.props.onClose()
}

  render() {
    const {list,className} = this.props
      return (
        <div className={`${style["card-wrap"]} ${className}`}>
          {
          list.map((x,index)=>(
            <div className={style.card} key={index}>
              <div className="card-img">
                <img src={x.src} alt="" />
              </div>
              <div className="title">
                {x.title}
              </div>
            </div>
          ))
        }
        </div>
      )
  }
}

export default app

看整体的代码是这个

//src\pages\Home\index.js
import React, { Component } from 'react'
import { InputItem, Button, WhiteSpace, WingBlank, NoticeBar } from 'antd-mobile'
//轮播组件
import Carousel from './model/Carousel'
import Card from '@/components/Card'
import img from '@/images/moon.png'

class app extends Component {
  state = {
    title: '欢迎来到叭哩叭哩,github-https://github.com/1067011734/balibali!!!!'
  }
  cardList = [
    { title: '团员中秋', src: img },
    { title: '团员中秋', src: img },
    { title: '团员中秋', src: img },
    { title: '团员中秋', src: img },
    { title: '团员中秋', src: img },
    { title: '团员中秋', src: img },
    { title: '团员中秋', src: img },
    { title: '团员中秋', src: img },
    { title: '团员中秋', src: img },
    { title: '团员中秋', src: img },
    { title: '团员中秋', src: img },
    { title: '团员中秋', src: img },
  ]
  render() {
    const { title } = this.state
    return (
      <div className="page">
        <NoticeBar marqueeProps={{ loop: true, style: { padding: '0 7.5px' } }}>
          {title}
        </NoticeBar>
        <Carousel />
        <Card list={this.cardList}/>
      </div>
    )
  }
}

export default app

在index.js中我们引用app

//src\pages\index.js
import React, { Component } from 'react'
import { connect } from 'dva'
import Transiton from '@/components/Transition'
import '@/styles/base.less'

class app extends Component {
  state = {
  }

  componentDidMount(){
    
  }


  render() {
    return (
      <Transiton {...this.props}>
        {this.props.children}
      </Transiton>
    )
  }
}

export default app
//src\components\Transition\index.js
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import ReactCSSTransitionGroup from 'react-addons-css-transition-group'
import StaticContainer from 'react-static-container'
import style from './index.less'

class app extends Component {
  PropTypes={
    open: PropTypes.bool,
    onClose: PropTypes.func,
  }

  state = {
    previousPathname:null,
  }

componentWillMount() {
  document.body.style.margin = "0px";
  // 这是防止页面被拖拽
  document.body.addEventListener('touchmove', (ev) => {
    ev.preventDefault();
  });
}

componentWillReceiveProps(nextProps, nextContext) {
  if (nextProps.location.pathname !== this.props.location.pathname) {
      this.setState({ previousPathname: this.props.location.pathname })
  }
}

componentDidUpdate() {
    if (this.state.previousPathname) {
        this.setState({ previousPathname: null })
    }
}

  render() {
    const {location,children,history} =this.props
    const {action} =history
    //goback:pop,push:push
    const className = action==='POP'?'translation-arrow-right':'translation-arrow-left'
    // const className = 'translation-arrow-left'
    const {pathname} =location
    const key = (pathname!=="/user")?'':"pathname"
      return (
        <ReactCSSTransitionGroup
          component="div"
          className={`translation-wrap ${className}`}
          transitionName="translation"
          transitionEnterTimeout={300}
          transitionLeaveTimeout={300}
          // transitionLeave={false}
        >
          {/* 用key控制滑动权限----- 苍天啊 */}
          <div key={key} className={`${pathname} translation-content`}>
            {children}
          </div>
        </ReactCSSTransitionGroup>
      )
  }
}

export default app

其实我很好奇,下面的切换页面在哪里
下面的是login页面
1037363-20190522174052112-1537614395.png

//src\pages\Login.js
import React, { Component } from 'react'
import { InputItem, Button, WhiteSpace, Toast } from 'antd-mobile'
import { createForm } from 'rc-form'
import { connect } from 'dva'
import { loginReg } from '@regularConfig'
import style from '@/styles/login.less'
import avataSrc from '@/images/icon/avatar.png'
import loginUserSrc from '@/images/icon/login_user.png'
import loginPassSrc from '@/images/icon/login_pass.png'
@createForm()
@connect(({ login, loading }) => ({
  login,
  submitting: loading.effects['login/login'],
}))
class app extends Component {
  state = {
  }

  submit = () => {
    const { getFieldProps, getFieldError } = this.props.form
    this.props.form.validateFields((error, values) => {
      if (error) {
        const msg = `请输入${getFieldError('user') || ''}${getFieldError('password') || ''}`
        Toast.info(msg, 1);
        return
      }
      // this.props.history.push({ pathname: '/home' })
      const { dispatch } = this.props
      dispatch({
          type: 'common/login',
          payload: {
            ...values,
          },
        })
    })
  }
  normalize = (val, prev) => {
    if (!loginReg.test(val)) {
      Toast.info('不能包含中文和大写', 1);
      return prev
    }
    return val
  }
  render() {
    let errors
    const { getFieldProps } = this.props.form
    return (
      <div className={`page ${style.login}`}>
        <div className={`${style["page-header"]}`}>
          <label>进入叭哩叭哩</label><img src={avataSrc} alt=""/>
        </div>
        <InputItem
          type="text"
          placeholder="账号为admin"
          maxLength="10"
          minLength="4"
          clear
          {...getFieldProps('user', {
            rules: [{ required: true, message: '账号', }],
            normalize: this.normalize,
          })}
        >
        <img src={loginUserSrc} className='icon' />
            </InputItem>
        <InputItem
          type="password"
          placeholder="密码为admin"
          maxLength="10"
          clear
          {...getFieldProps('password', {
            rules: [{ required: true, message: '密码', }],
            normalize: this.normalize
          })}
        >
        <img src={loginPassSrc} className='icon' />
            </InputItem>
        <WhiteSpace size="xl"/>
        <WhiteSpace size="xl"/>
        <Button type="primary" onClick={this.submit}>确定</Button>
        <WhiteSpace />
      </ div>
    )
  }
}

export default app

路由也是会骗人的
1037363-20190522174817609-1142816016.png

//src\pages\404.js
import React from 'react';
import Link from 'umi/link';
import Exception from '@/components/Exception';

export default () => (
  <Exception type="404" style={{ minHeight: 500, height: '100%' }} linkElement={Link} />
);

1037363-20190522175154331-750717640.png

//src\pages\User\index.js
import React, { Component } from 'react'
import { Steps,InputItem,Button,WhiteSpace} from 'antd-mobile'
import Container from '@/components/Container'
import { createForm } from 'rc-form'
import { connect } from 'dva'
import router from 'umi/router'
import Step1 from './model/step1'
import Step2 from './model/step2'
import Step3 from './model/step3'

const {Step} = Steps

@createForm()
@connect(({ common}) => ({
  userInfo:common.userInfo
}))
class app extends Component {
    state = {
      userInfo:{
        name:'', // 姓名
        dept:'', // 所属部门
        person:[], //个性标签
        avatar:"" //头像
      },
      stepNumber:1,
    }

    stepList=[
      {title:'基本设置',key:1},
      {title:'个性标签',key:2},
      {title:'上传头像',key:3},
    ]

componentWillMount(){
  const {userInfo} = this.props
  this.setState({userInfo})
}

componentDidMount(){

}

// 步骤变化
stepSwitch=(key)=>{
  const {userInfo} = this.state
  switch(key){
    case 1: return <Step1 onChange={this.changeData} userInfo={userInfo} />
    case 2: return <Step2 onChange={this.changeData} userInfo={userInfo} />
    case 3: return <Step3 onChange={this.changeData} userInfo={userInfo} />
    default: break;
  }
}

// 步骤完成保存数据
changeData=(data,key)=>{
  const { dispatch } = this.props
   let {stepNumber,userInfo} = this.state
   stepNumber=key+1
   if(stepNumber>3){
     const params ={...userInfo,...data}
    dispatch({
        type: 'common/updateUserInfo',
        payload: params,
      })
      router.goBack()
     return
   }
   this.setState({
    userInfo:{...userInfo,...data},
    stepNumber,
   })

}

    render() {
      const { getFieldProps, getFieldError } = this.props.form
      const {stepNumber} = this.state
        return (
          <Container title="个人设置">
            <Steps direction="horizontal">
              {this.stepList.map(item=><Step
                key={item.key}
                title={item.title} 
                icon={<i className={`step-circle ${item.key<=stepNumber?'bj-primary':''}`}>{item.key<stepNumber?'√':item.key}</i>}
                status={item.key<stepNumber?'finish':'wait'}
              />)}
            </Steps>
            <WhiteSpace />
            {this.stepSwitch(stepNumber)}
            {/* <Step1 /> */}
          </Container>
        )
    }
}

export default app

1037363-20190522175328802-1840661886.png

//src\pages\User\model\step1.js
import React, { Component } from 'react'
import { List, InputItem, Switch, Stepper, Range, Button, Picker, Toast } from 'antd-mobile'
import Container from '@/components/Container'
import { createForm } from 'rc-form'
import PropTypes from 'prop-types'

const { Item } = List
@createForm()
class app extends Component {
  PropTypes = {
    onChange: PropTypes.func,
  }

  state = {
  }

  componentDidMount() {
    const { userInfo } = this.props
    const { name, dept } = userInfo
    // debugger
    this.props.form.setFieldsValue({
      name,
      dept: [dept],
    })
  }

  onSubmit = () => {
    const { getFieldError } = this.props.form
    this.props.form.validateFields((error, values) => {
      if (error) {
        const msg = `请输入${getFieldError('name') || ''}${getFieldError('dept') || ''}`
        Toast.info(msg, 1);
        return
      }
      values.dept = values.dept[0]
      this.props.onChange(values, 1)
    })
  }

  validateAccount = (rule, value, callback) => {
    if (value && value.length > 0) {
      callback();
    } else {
      callback(new Error('At least four characters for account'));
    }
  }

  render() {
    const { getFieldProps, getFieldError } = this.props.form
    const deptData = [
      {
        label: '前端攻城狮',
        value: '前端攻城狮',
      },
      {
        label: 'java',
        value: 'java',
      },
    ]
    return (
      <form className="flex-column">
        <List className="flex-3">
          <InputItem
            {...getFieldProps('name', {
              rules: [{ required: true, message: '账号', }],
            }
            )}
            clear
            placeholder="请修改账号"
          >账号
              </InputItem>
          <Picker data={deptData} {...getFieldProps('dept',
            {
              rules: [{ required: true, message: '岗位', }],
            })}
            cols="1"
          >
            <List.Item arrow="horizontal">岗位</List.Item>
          </Picker>
        </List>
        <div className="flex-1">
          <Button type="primary" onClick={this.onSubmit}>下一步</Button>
        </div>
      </form>
    )
  }
}

export default app

1037363-20190522175949358-2013634472.png

//src\pages\User\model\step2.js
import React, { Component } from 'react'
import { Tag ,Button } from 'antd-mobile'
import { createForm } from 'rc-form'
import PropTypes from 'prop-types'
import ReactDOM from 'react-dom'

@createForm()
class app extends Component {
  PropTypes={
    onChange: PropTypes.func,
  }

    state = {

    }

    tagList=[
      '乐观','努力','积极','有爱心','勇敢','思想良好','积极向上','善于与相处','对工作积极','认真负责',
      '严格要求自己','有强烈的责任心'
    ]

componentDidMount(){
}

onSubmit = () => {
  const domSelect= ReactDOM.findDOMNode(this).querySelectorAll(".am-tag-active")
  const selectArr = Array.from(domSelect,x=>x.textContent)
    this.props.onChange({person:selectArr},2)
}

    render() {
      const {userInfo} = this.props
      const {person} = userInfo
        return (
          <div className="flex-column">
            <div className="flex-3">
              {this.tagList.map((x,index)=>
                <Tag key={index} selected={person&&person.includes(x)}>{x}</Tag>
            )}
            </div>
            <div className="flex-1">
              <Button type="primary" onClick={this.onSubmit}>下一步</Button>
            </div>
          </div>
        )
    }
}

export default app

1037363-20190522180127520-1380963625.png
//src\pages\User\model\step3.js
import React, { Component } from 'react'
import { ImagePicker ,Button } from 'antd-mobile'
import { createForm } from 'rc-form'
import PropTypes from 'prop-types'

@createForm()
class app extends Component {
PropTypes={
onChange: PropTypes.func,
}

state = {
  files: [],
}

componentDidMount(){
const {userInfo} = this.props
const {avatar} = userInfo
this.setState({files:[{url:avatar}]})
}

onSubmit = () => {
const {files} = this.state
this.props.onChange({avatar:files[0]?files[0].url:''},3)
}

onChange = (files, type, index) => {
console.log(files, type, index);
this.setState({
files,
})
}

render() {
  const { files } = this.state
    return (
      <div className="flex-column">
        <div className="flex-3">
          <ImagePicker
            files={files}
            onChange={this.onChange}
            onImageClick={(index, fs) => console.log(index, fs)}
            selectable={files.length < 1}
            accept="image/gif,image/jpeg,image/jpg,image/png"
          />
        </div>
        <div className="flex-1">
          <Button type="primary" onClick={this.onSubmit}>保存</Button>
        </div>
      </div>
    )
}

}

export default app
![](https://img2018.cnblogs.com/blog/1037363/201905/1037363-20190522180524238-1345634353.png)js
//src\pages\Map\index.js
import React, { Component } from 'react'
import { createForm } from 'rc-form'
import Bmap from '@/components/Bmap'
import { connect } from 'dva'

@createForm()
@connect(({ login, loading }) => ({
login,
submitting: loading.effects['login/login'],
}))
class app extends Component {
state = {
}

componentDidMount(){
console.info(this.props)
}

render() {
    return (
      <div className="page">
        <Bmap />
      </div>
    )
}

}

export default app
js
//src\components\Bmap\index.js
//定义地图组件
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import BMap from 'BMap'
import style from './index.less'

class app extends Component {
PropTypes={
info: PropTypes.string,
}

state = {
info:'叭哩叭哩'
}

map={}

componentDidMount () {
const map = new BMap.Map("Bmap"); // 创建Map实例
this.map=map
this.mapInit(map)
}

mapInit=(map)=>{
const _self = this
map.centerAndZoom(new BMap.Point(116.404, 39.915), 11);
map.addControl(new BMap.MapTypeControl()); // 添加地图类型控件
map.enableScrollWheelZoom(true); // 开启鼠标滚轮缩放
// const top_left_control = new BMap.ScaleControl({anchor: BMAP_ANCHOR_TOP_LEFT});// 左上角,添加比例尺
const top_left_navigation = new BMap.NavigationControl(); // 左上角,添加默认缩放平移控件
// const top_right_navigation = new BMap.NavigationControl({anchor: BMAP_ANCHOR_TOP_RIGHT, type: BMAP_NAVIGATION_CONTROL_SMALL}); // 右上角,仅包含平移和缩放按钮
// map.addControl(top_left_control);
map.addControl(top_left_navigation);
// map.addControl(top_right_navigation);

// 定位
const point = new BMap.Point(116.331398,39.897445);
map.centerAndZoom(point,15);// 初始化地图,设置中心点坐标和地图级别
const geolocation = new BMap.Geolocation();
geolocation.getCurrentPosition(function(r){
  if(this.getStatus() == BMAP_STATUS_SUCCESS){
    const mk = new BMap.Marker(r.point);
    map.addOverlay(mk);
    map.panTo(r.point);
    _self.setWindowInfo(mk)
    // alert('您的位置:'+r.point.lng+','+r.point.lat);
  }
  else {
    // alert('failed'+this.getStatus());
  }        
},{enableHighAccuracy: true})

}

setWindowInfo=(marker)=>{
const {info} = this.state
marker.addEventListener("click",(e) => {
this.openInfo(info,e)}
);
}

// 创建并打开信息窗口
openInfo=(content,e)=>{
const opts = {
width : 250, // 信息窗口宽度
height: 80, // 信息窗口高度
title : "信息窗口" , // 信息窗口标题
enableMessage:true// 设置允许信息窗发送短息
}
const map =this.map
const p = e.target;
const point = new BMap.Point(p.getPosition().lng, p.getPosition().lat);
const infoWindow = new BMap.InfoWindow(content,opts); // 创建信息窗口对象
map.openInfoWindow(infoWindow,point); // 开启信息窗口
}

render() {
return (


)
}
}

export default app
![](https://img2018.cnblogs.com/blog/1037363/201905/1037363-20190522180737167-1136189469.png)js
//这个比较厉害,还有下拉加载刷新

//src\pages\Book\index.js
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
// import { InputItem,Button, WhiteSpace, WingBlank } from 'antd-mobile'
// import data from './data'

import { PullToRefresh, ListView, Button } from 'antd-mobile';

const data = [
  {
    img: 'https://zos.alipayobjects.com/rmsportal/dKbkpPXKfvZzWCM.png',
    title: 'Meet hotel',
    des: '不是所有的兼职汪都需要风吹日晒',
  },
  {
    img: 'https://zos.alipayobjects.com/rmsportal/XmwCzSeJiqpkuMB.png',
    title: 'McDonald\'s invites you',
    des: '不是所有的兼职汪都需要风吹日晒',
  },
  {
    img: 'https://zos.alipayobjects.com/rmsportal/hfVtzEhPzTUewPm.png',
    title: 'Eat the week',
    des: '不是所有的兼职汪都需要风吹日晒',
  },
];
const NUM_ROWS = 20;
let pageIndex = 0;

function genData(pIndex = 0) {
  const dataArr = [];
  for (let i = 0; i < NUM_ROWS; i++) {
    dataArr.push(`row - ${(pIndex * NUM_ROWS) + i}`);
  }
  return dataArr;
}

class app extends React.Component {
  constructor(props) {
    super(props);
    const dataSource = new ListView.DataSource({
      rowHasChanged: (row1, row2) => row1 !== row2,
    });

    this.state = {
      dataSource,
      refreshing: true,
      isLoading: true,
      height: document.documentElement.clientHeight,
      useBodyScroll: false,
    };
  }

  // If you use redux, the data maybe at props, you need use `componentWillReceiveProps`
  // componentWillReceiveProps(nextProps) {
  //   if (nextProps.dataSource !== this.props.dataSource) {
  //     this.setState({
  //       dataSource: this.state.dataSource.cloneWithRows(nextProps.dataSource),
  //     });
  //   }
  // }

  componentDidUpdate() {
    if (this.state.useBodyScroll) {
      document.body.style.overflow = 'auto';
    } else {
      document.body.style.overflow = 'hidden';
    }
  }

  componentDidMount() {
    const hei = this.state.height - ReactDOM.findDOMNode(this.lv).offsetTop;

    setTimeout(() => {
      this.rData = genData();
      this.setState({
        dataSource: this.state.dataSource.cloneWithRows(genData()),
        height: hei,
        refreshing: false,
        isLoading: false,
      });
    }, 1500);
  }

  onRefresh = () => {
    this.setState({ refreshing: true, isLoading: true });
    // simulate initial Ajax
    setTimeout(() => {
      this.rData = genData();
      this.setState({
        dataSource: this.state.dataSource.cloneWithRows(this.rData),
        refreshing: false,
        isLoading: false,
      });
    }, 600);
  };

  onEndReached = (event) => {
    // load new data
    // hasMore: from backend data, indicates whether it is the last page, here is false
    if (this.state.isLoading && !this.state.hasMore) {
      return;
    }
    console.log('reach end', event);
    this.setState({ isLoading: true });
    setTimeout(() => {
      this.rData = [...this.rData, ...genData(++pageIndex)];
      this.setState({
        dataSource: this.state.dataSource.cloneWithRows(this.rData),
        isLoading: false,
      });
    }, 1000);
  };

  render() {
    const separator = (sectionID, rowID) => (
      <div
        key={`${sectionID}-${rowID}`}
        style={{
          backgroundColor: '#F5F5F9',
          height: 8,
          borderTop: '1px solid #ECECED',
          borderBottom: '1px solid #ECECED',
        }}
      />
    );
    let index = data.length - 1;
    const row = (rowData, sectionID, rowID) => {
      if (index < 0) {
        index = data.length - 1;
      }
      const obj = data[index--];
      return (
        <div
          key={rowID}
          style={{
            padding: '0 15px',
            backgroundColor: 'white',
          }}
        >
          <div style={{ height: '50px', lineHeight: '50px', color: '#888', fontSize: '18px', borderBottom: '1px solid #ddd' }}>
            {obj.title}
          </div>
          <div style={{ display: '-webkit-box', display: 'flex', padding: '15px' }}>
            <img style={{ height: '63px', width: '63px', marginRight: '15px' }} src={obj.img} alt="" />
            <div style={{ display: 'inline-block' }}>
              <div style={{ marginBottom: '8px', color: '#000', fontSize: '16px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: '250px' }}>{obj.des}-{rowData}</div>
              <div style={{ fontSize: '16px' }}><span style={{ fontSize: '30px', color: '#FF6E27' }}>{rowID}</span> 元/任务</div>
            </div>
          </div>
        </div>
      );
    };
    return (<div>
      <ListView
        ref={el => this.lv = el}
        dataSource={this.state.dataSource}
        renderFooter={() => (<div style={{ padding: 30, textAlign: 'center' }}>
          {this.state.isLoading ? 'Loading...' : 'Loaded'}
        </div>)}
        renderRow={row}
        renderSeparator={separator}
        useBodyScroll={false}
        style={{
          height: this.state.height,
          border: '1px solid #ddd',
          margin: '5px 0',
        }}
        pullToRefresh={<PullToRefresh
          refreshing={this.state.refreshing}
          onRefresh={this.onRefresh}
        />}
        onEndReached={this.onEndReached}
        pageSize={5}
      />
    </div>);
  }
}

export default app

转载于:https://www.cnblogs.com/smart-girl/p/10907962.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值