package.json代码如下:
{
"name": "active",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^16.4.1",
"react-dom": "^16.4.1",
"react-redux": "^5.0.7",
"react-router-dom": "^4.3.1",
"react-scripts": "1.1.4",
"react-swipe": "^5.1.1",
"react-transition-group": "^2.3.1",
"redux": "^4.0.0",
"redux-logger": "^3.0.6",
"redux-promise": "^0.6.0",
"redux-thunk": "^2.3.0",
"swipe-js-iso": "^2.0.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"proxy": {
"/api": {
"target": "http://localhost:1000/",
"changeOrigin": true,
"pathRewrite": {
"/api": "/"
}
}
},
"devDependencies": {
"babel-plugin-transform-decorators-legacy": "^1.3.5"
}
}
api/home.js(在redux中的action中被引入store/actions/home.js)用来获取首页数据
//获取轮播图数据
function getSilders() {
//最原始的fetch
// fetch('api/loop', {method: "post"}).then(function (response) {
// // 转换为 JSON
// console.log("response")
// console.log(response)
// return response.json();
// }).then(function (j) {
// console.log('获取到的数据是====');
// console.log(j);
// return j
// });
////redux-promise的用法:可以将payload中的promise执行,执行后将内容放到action.payload中进行派发:{ type:SET_SLIDERS, patload:[{},{},{},{}] }
return fetch('api/loop', {method: "post"})
}
export { getSilders }
common/Tab/Tab.js;在app.js中被引入;作为底部导航;切换主页面
import React,{Component} from 'react'
import {Link,NavLink} from 'react-router-dom'
export default class Tab extends Component{
constructor(){
super()
}
render(){
return (
<ul>
<li><Link to={'/'}> 首页Link>li>
<li><Link to={'/lesson'} >课程 Link>li>
<li><Link to={'/profile'} > 用户中心Link>li>
{/*第二种写法如下:*/}
{/*<li> <NavLink to={'/'}>首页NavLink> li>*/}
{/*<li> <NavLink to={'/lesson'}>课程NavLink> li>*/}
{/*<li> <NavLink to={'/profile'}>用户中心NavLink> li>*/}
ul>
)
}
}
总结:
1:路由的2种写法NavLink , Link:
2:在当前路由下,再次点击路由切换报警告如下:
containers/Home/Homeheader/Homeheader.js;被Home.js被引入
import React, {Component} from 'react'
import logo from '../../../common/img/logo.png'
import './index.css'
import Transition from 'react-transition-group/Transition';
const duration = 10;
//默认样式
const defaultStyle = {
transition: `opacity ${duration}ms ease-in-out`,
opacity: 0,
display:'none'
}
const transitionStyles = {
entering: {opacity: 0},
entered: {opacity: 1},
};
export default class Homeheader extends Component {
constructor() {
super()
this.state = {
isShow: false
}
}
changeShow = () => {
this.setState({
isShow: !this.state.isShow
})
}
selectLesson=(e)=>{
//li元素,当前点击的元素是谁就是谁
// console.log(e.target)
// //整个ul元素。事件在谁身上绑着就是谁
// console.log(e.currentTarget)
// //获取h5 data属性
// console.log(e.target.dataset.type)
//隐藏元素
this.changeShow()
this.props.selectCurrentLesson(e.target.dataset.type)
}
render() {
return (
'home-header'}>
this.changeShow} className={'iconfont icon-menu menu'}>
'logo'} src={logo} alt=""/>
in={this.state.isShow} timeout={duration} onEnter={(node)=>{
node.style.display='block'
}} onExited={(node)=>{
node.style.display='none'
}}>
{(state) => (
'menu-ul'} style={{
...defaultStyle,
...transitionStyles[state]
}}
onClick={(e)=>{
this.selectLesson(e)
}}
>
- "all">全部课程
- "react">react课程
- "vue">vue课程
)}
)
}
}
总结:
1:显示隐藏采用‘react-transition-group’组件
2:官方组件地址:https://github.com/reactjs/react-transition-group
3:html5中的data属性获取:e.target.dataset.type
4:效果图如下:
containers/Home/Home.js;路由‘/’的组件
import React, {Component} from 'react'
import './index.css'
import Homeheader from './Homeheader/Homeheader'
import {connect} from 'react-redux'
import HomeSlider from './HomeSlider'
import Loading from '../../components/Loading'
import actions from '../../store/actions/home'
//修饰符的用法待研究
@connect(state => ({...state.home}), actions)
export default class Home extends Component {
// constructor(){
// super()
// }
componentWillMount() {
// 第一种方法:直接ajax
// fetch('api/loop', {method: "post"}).then(function (response) {
// // 转换为 JSON
// return response.json();
// }).then(function (j) {
// console.log(j);
// });
// 第2种方法:ajax从外部引入
// getSilders()
// 第3种方法:采用redux;只有connect装饰器以后才能使用redux中的store;如果redux中存在数据;则不进行请求
if (this.props.slider.length === 0) {
this.props.getSliderApi()
}
}
selectCurrentLesson = (val) => {
// console.log('传给父组件的值是'+val)
console.log(this.props)
this.props.updateCurrentLesson(val)
}
render() {
return (
this.selectCurrentLesson}>
//解决轮播图不出现的BUG
{
this.props.slider.length>0 ? this.props.slider}> :
}
)
}
}
containers/Lesson/Lesson.js;路由‘/lesson’的组件
import React,{Component} from 'react'
import './index.less'
export default class Lesson extends Component{
// constructor(){
// super()
// }
render(){
return (
<div>
Lesson
div>
)
}
}
containers/Profile/Profile.js;路由‘/Profile’的组件
import React,{Component} from 'react'
import './index.less'
export default class Profile extends Component{
// constructor(){
// super()
// }
render(){
return (
<div>
Profile
div>
)
}
}
store/actions/home.js;在Home.js中被引入;
import * as Types from '../action-types'
import { getSilders } from '../../api/home'
let actions={
//更新当前选择的课程
updateCurrentLesson(lesson){
return {
type:Types.SET_CURRENT_LESSON,
lesson
}
},
getSliderApi(){
// redux-thunk
return function (dispatch,getState) {
//redux-promise的用法:可以将payload中的promise执行,执行后将内容放到action.payload中进行派发:{ type:SET_SLIDERS, patload:[{},{},{},{}] }
dispatch({type:Types.SET_SLIDERS ,payload:getSilders().then(function (response) {
// 转换为 JSON
console.log("response")
console.log(response)
if(response.status==200){
return response.json();
}else{
alert('服务器挂掉了')
}
}).then(function (j) {
// console.log('获取到的数据是====');
// console.log(j);
return j
})})
}
}
}
export default actions
store/reducers/home.js;在下面的index.js中被引入;
//一个页面一个reducer
import * as Types from '../action-types'
let initState={
currentLesson:'all',
slider:[]
}
function home(state=initState, action) {
switch (action.type){
case Types.SET_CURRENT_LESSON:
return {
...state,
currentLesson:action.lesson
}
case Types.SET_SLIDERS:
return {
...state,
slider:action.payload
}
default:{
return state
}
}
}
export default home
store/reducers/index.js;在store中index.js中被引入;
import { combineReducers } from 'redux'
import home from './home'
export default combineReducers({
home
})
store/action-types.js;在store中的各种JS文件中引入;
//设置当前课程
export const SET_CURRENT_LESSON='set_current_lesson'
//设置轮播图数据
export const SET_SLIDERS='set_sliders'
store/index.js;被最外层的index.js引入
import { createStore , applyMiddleware } from 'redux'
import reduxLogger from 'redux-logger'
import reduxThunk from 'redux-thunk'
import reduxPromise from 'redux-promise'
import reducer from './reducers/index'
let store= createStore(reducer,applyMiddleware(reduxLogger,reduxThunk,reduxPromise))
window._store=store; //为了测试用
export default store
总结:
写redux的逻辑
1:action-types
2:reducer
3:action
4:组件中调用action; dispatch
架构最外层的index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
//配置路由组件
import {HashRouter as Router,Route, Switch} from 'react-router-dom'
import Home from './containers/Home/Home'
import Profile from './containers/Profile/Profile'
import Lesson from './containers/Lesson/Lesson'
import {Provider} from 'react-redux'
import store from './store/index'
import './common/reset.css'
ReactDOM.render(
'/' exact={true} component={Home}>
'/lesson' component={Lesson}>
'/profile'} component={Profile}>
, document.getElementById('root'));
registerServiceWorker();
架构最外层的app.js
import React, { Component } from 'react';
import Tab from './common/Tab/Tab'
class App extends Component {
render() {
return (
<div>
{this.props.children}
div>
//
// {this.props.children}
//
//
);
}
}
export default App;
HomeSlider.js
import React,{Component} from 'react'
//轮播图组件
import ReactSwipe from 'react-swipe';
export default class HomeSlider extends Component{
constructor(){
super()
this.state={
index:0
}
}
render(){
let _this=this
let opts={continuous: true,
speed: 400,
auto: 1000,
callback: function(index, elem) {
_this.setState({
index:index
})
},
}
return (
<div className={'loop'}>
"carousel" swipeOptions={opts}>
{
this.props.lists.map((item, index) => {
return (
<div key={index}>""/>div>
)
})
}
<div className={'slider-dots'}>
{
this.props.lists.map((item, index) => {
return (
index} className={this.state.index===index ? 'active': ''}>
)
})
}
div>
div>
)
}
}
1:轮播图插件
npm install react swipe-js-iso react-swipe
轮播图插件swipe-js-iso拖动一次后不再轮播的BUG修复
delay = options.auto || 0;