react项目构建流程及列表跳详情

本文详细介绍如何使用Create React App搭建项目,配置别名,安装及使用SCSS、React Router、Ant Design Mobile等,并展示了Home、Detail等页面的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、进行全局安装

cnpm i create-react-app -g    (全局安装只需安装一次)

2、项目创建

create-react-app myapp

myapp是项目名称
在这里插入图片描述

3、抽离配置文件命令

cd myapp    //进入创建的项目
cnpm run eject      //抽离配置文件命令

在命令行中输入抽离配置命令
在这里插入图片描述
抽离成功如下图:
在这里插入图片描述

4、配置@的别名指向src目录

打开config文件夹里的webpack.config.dev和webpack.config.dev的指定位置加入如下代码 ‘@’: path.join(__dirname, ‘…/’, ‘src’)

alias: {
      // Support React Native Web
      // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
      'react-native': 'react-native-web',
      **'@': path.join(__dirname, '../', 'src')**
    },

5、创建文件夹components、store

在src中创建components和store两个文件夹,将App.js 和 App.test.js 放入components文件夹中src里保留index.js 和 serviceWorker
在这里插入图片描述

6、安装scss

如果使用scss可以安装scss

cnpm i node-sass sass-loader -S

7、加入路由模块

cnpm i react-router-dom -S

8、UI类型的组件

ui组件地址

cnpm i antd-mobile -S
入口页面的相关配置 --- click/promise支持
<script src="https://as.alipayobjects.com/g/component/fastclick/1.0.6/fastclick.js"></script>
  <script>
    if ('addEventListener' in document) {
      document.addEventListener('DOMContentLoaded', function() {
        FastClick.attach(document.body);
      }, false);
    }
    if(!window.Promise) {
      document.writeln('<script src="https://as.alipayobjects.com/g/component/es6-promise/3.2.2/es6-promise.min.js"'+'>'+'<'+'/'+'script>');
    }

安装babel-plugin-import


     cnpm i babel-plugin-import -D

在webapck.config.dev.js和webapck.config.prod.js中添加:
[“import”, { libraryName: “antd-mobile”, style: “css” }]

plugins: [
                [
                  require.resolve('babel-plugin-named-asset-import'),
                  {
                    loaderMap: {
                      svg: {
                        ReactComponent: '@svgr/webpack?-prettier,-svgo![path]',
                      },
                    },
                  },
                ],
                ["import", { libraryName: "antd-mobile", style: "css" }]
              ],

9、在components创建home.js 代码如下

import React, { Component } from 'react';
import axios from 'axios';    //引入axios
import Banner from './Banner';   //引入加入的轮播图
import List from './List';    //引入加入的数据
import Footer from './Footer';  

class App extends Component {
  constructor (props) {
    super (props);
    this.state = {
      banner: [],
      imgHeight: 176,
      disabled: false,
      list: [],
    }
  }

  getBannerData () {
    return axios.get('http://jx.xuzhixiang.top/ap/api/bannerlist.php?id=13184')
  }

  getListData () {
    return axios.get('douban')
  }
  //  使用axios请求数据
  componentDidMount () {
    axios.all([this.getBannerData(),this.getListData()])
      .then(axios.spread((banner,list) => {
        console.log('banner', banner)
        console.log('list', list)
        this.setState({
          banner: banner.data.data,
          list: list.data
        })
        console.log(this.state)
      }))
  }
 // 进入详情
  goPageFn (id) {
    console.log(id)
    this.props.history.push('/detail/'+id);
  }
  
  render() {
    return (
      <div className="box">
        <header className="header">
          首页头部
        </header>
        <div className="content">
          首页内容
          <Banner banner={ this.state.banner } imgHeight={ this.state.imgHeight }/>
          <List list={ this.state.list } disabled={ this.state.disabled } goPageFn = { this.goPageFn.bind(this) }/>
        </div>
        <Footer />
      </div>
    );
  }
}

export default App;

9.1、将Footer底部抽离出来

Footer.js

import React, { Component } from 'react';
import { NavLink } from 'react-router-dom';

class footer extends Component {
  constructor (props) {
    super(props);
    this.state = {
      list: [
        {
          icon: 'iconfont icon-ai-home',
          name: '首页',
          path: '/home'
        },
        {
          icon: 'iconfont icon-fenlei',
          name: '分类',
          path: '/kind'
        },
        {
          icon: 'iconfont icon-gouwuche',
          name: '购物车',
          path: '/cart'
        },
        {
          icon: 'iconfont icon-04f',
          name: '我的',
          path: '/user'
        }
      ]
    }
  }
  render() {
    return (
      <footer className="footer">
      <ul>
          {
            this.state.list.map((item, index) => {
              return (
                <li key= { index }>
                  <NavLink to = { item.path }>      //设置跳转路由
                    <span className= { item.icon }></span>
                    <p>{ item.name }</p>
                  </NavLink>
                </li>
              )
            })
          }
        </ul>
      </footer>
    );
  }
}
export default footer

9.2、数据组件List.js

import React, { Component } from 'react';
import { List } from 'antd-mobile';

const Item = List.Item;
const Brief = Item.Brief;


class list extends Component {
  // constructor(props) {
  //   super(props);
  // }

  sendIdFn (id) {       //  向父组件home.js传值
    this.props.goPageFn(id)
  }

  render() {
    let lists = []
    this.props.list.map((item,index) => {
      // console.log(item.images.small)
      lists.push(
        <Item  key={index} extra={item.year} align="top" thumb={item.images.small} multipleLine onClick={ this.sendIdFn.bind(this, item.id) }>
          { item.title } <Brief>豆瓣评分:{ item.rating.average }分</Brief>
        </Item>
      )
      return lists
    })
    return (<div>
      <List renderHeader={() => '豆瓣电影'} className="my-list">
        { lists }
      </List>
    </div>);
  }
}

export default list;

9.3、轮播图组件Banner.js

import React, { Component } from 'react';
import { Carousel, } from 'antd-mobile';      //使用

class banner extends Component {
  // constructor (props) {
  //   super (props);
  // }
  render() {
    return (
      <Carousel
        autoplay={true}
        infinite
        beforeChange={(from, to) => console.log(`slide from ${from} to ${to}`)}
        afterChange={index => console.log('slide to', index)}
      >
        {this.props.banner.map((item, val) => (
          <a
            key={val}
            href="http://www.alipay.com"
            style={{ display: 'inline-block', width: '100%', height: this.props.imgHeight }}
          >
            <img
              src={ item.banner_img_url }
              alt=""
              style={{ width: '100%', verticalAlign: 'top' }}
              onLoad={() => {
                // fire window resize event to change height
                window.dispatchEvent(new Event('resize'));
                this.setState({ imgHeight: 'auto' });
              }}
            />
          </a>
        ))}
      </Carousel>
    );
  }
}

export default banner;

9.4详情页面Detail.js

import React, { Component } from 'react';
import axios from 'axios';

class App extends Component {
  constructor (props) {
    super (props);
    this.state = {
      // film: [], // film 电影
      title: '',
      year: '',
      average: '',
      genres: [],
      alt: '',
      img: ''
    }
  }

  getFilmData () {
    // console.log('detail', this)
    // console.log(this.props.match.params)
    const { id } = this.props.match.params
    return axios.get(`detail?id=${id}`)
  }

  componentDidMount () {
    // console.log(this.props.match.params)
    axios.all([this.getFilmData()])
      .then(axios.spread((film) => {
        // console.log('film', film.data[0])
        // console.log(film.data[0].genres)
        this.setState({
          title: film.data[0].title,
          year: film.data[0].year,
          average: film.data[0].rating.average,
          genres: film.data[0].genres,
          img: film.data[0].images.small
        })
      }))
  }
  render() {
    let tags=[]
    this.state.genres.map((item,index) => {
      tags.push(
        <span key={ index } style={ {margin: "0 0.05rem"} }>
          { item }
        </span>
      )
      return tags
    })
    let imgstyle = {
      width: "1.6rem",
      height: "2.3rem",
      flost: "left"
    }
    let liheight = {
      margin: '0.05rem 0'
    }
    return (
      <div className="container">
        <div className="box">
          <header className="header">
            电影详情
          </header>
          <div className="content">
            <div className="detail"
              style={{width: "90%", display: 'flex', margin: '0.25rem auto'}}
            >
              <p style={ {width: "50%"} }>
                <img src={ this.state.img } alt="" style={ imgstyle }/>
              </p>
              <ul style={ {width:"50%", float: "right", padding: "0 0.1rem"} }>
                <h3 style={ {margin: '0.15rem 0'} }>{ this.state.title }</h3>
                <li style= { liheight }>{ this.state.year }年</li>
                <li style= { liheight }>豆瓣评分:{ this.state.average }分</li>
                <li style= { liheight }>分类:{ tags }</li>
              </ul>
            </div>
          </div>
        </div>
        <Footer />
      </div>
    );
  }
}

export default App;

9.5src中的index.js中的代码

import React from 'react';
import ReactDOM from 'react-dom';
import { HashRouter as Router, Route, Switch, Redirect } from 'react-router-dom'
// import './index.css';
// import App from '@/components/App';
import Home from '@/components/Home';
import Cart from '@/components/Cart';
import Kind from '@/components/Kind';
import User from '@/components/User';
import Detail from '@/components/Detail';
import * as serviceWorker from './serviceWorker';
import './main.scss';

ReactDOM.render(
  <Router>
    <Switch>
      <Route path='/home' component = { Home } />
      <Route path='/cart' component = { Cart } />
      <Route path='/kind' component = { Kind } />
      <Route path='/user' component = { User } />
      <Route path='/detail/:id' component = { Detail } />
      <Redirect to={ {pathname: '/home'} } />
    </Switch>
  </Router>
  , document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: http://bit.ly/CRA-PWA
serviceWorker.unregister();

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值