播放器

作者: Mark同学 | 来源:发表于2020-01-06 09:43 被阅读0次

    轮播

    //Recommend/index.js
    import React from 'react'
    import Slider from '../../components/slider'
    
    function Recommend() {
      const bannerList = [1, 2, 3, 4].map(() => {
        return {
          imageUrl: 'http://p1.music.126.net/ZYLJ2oZn74yUz5x8NBGkVA==/109951164331219056.jpg'
        }
      })
      return (
        <div>
          <Slider bannerList={bannerList}/>
        </div>
      )
    }
    
    export default Recommend
    
    //components/slider/index.js
    import React, { useState, useEffect } from 'react'
    import { SliderContainer } from './style'
    import 'swiper/css/swiper.css'
    import Swiper from 'swiper'
    
    function Slider(props) {
      const { bannerList } = props
      const [sliderSwiper, setSliderSwiper] = useState(null)
    
      useEffect(() => {
        if (bannerList.length && !sliderSwiper) {
          const sliderSwiper = new Swiper('.swiper-container', {
            loop: true,
            autoplay: {
              delay: 3000,
              disableOnInteraction: false
            },
            pagination: {
              el: '.swiper-pagination'
            }
          })
          setSliderSwiper(sliderSwiper)
        }
      }, [bannerList.length, sliderSwiper])
      
      return (
        <SliderContainer>
          <div className='before'></div>
          <div className="swiper-container">
            <div className="swiper-wrapper">
              {
                bannerList.map((banner, index) => {
                  return (
                    <div className="swiper-slide" key={index}>
                      <div className='swiper-nav'>
                        <img src={banner.imageUrl} width='100%' height='100%' alt='推荐'/>
                      </div>
                    </div>
                  )
                })
              }
            </div>
            <div className="swiper-pagination"></div>
          </div>
        </SliderContainer>
      )
    }
    
    export default Slider
    
    //components/scroll/style.js
    import styled from "styled-components"
    import style from '../../assets/global-style'
    
    export const SliderContainer = styled.div`
      position: relative;
      width: 100%;
      height: 100%;
      .before {
        position: absolute;
        top: 0;
        height: 60%;
        width: 100%;
        background: ${style['theme-color']}
      }
      .swiper-container {
        position: relative;
        width: 98%;
        height: 160px;
        overflow: hidden;
        margin: auto;
        border-radius: 6px;
        .swiper-nav {
          position: absolute;
          width: 100%;
          height: 100%;
        }
        --swiper-theme-color: ${style['theme-color']};
      }
    `
    

    推荐列表-mock

    //Recommend/index.js
    import React from 'react'
    import CommonList from '../../components/list';
    
    function Recommend() {
      const recommendList = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15].map(() => {
        return {
          id: 1,
          picUrl: 'https://p1.music.126.net/fhmefjUfMD-8qtj3JKeHbA==/18999560928537533.jpg',
          playCount: 17171122,
          name: '朴树、许巍、李健、郑钧、老狼、赵雷'
        }
      })
    
      return (
        <div>
          <CommonList list={recommendList}/>
        </div>
      )
    }
    
    export default Recommend
    
    //components/list/index.js
    import React from 'react'
    import { ListWrapper, List, ListItem } from './style'
    import { getCount } from '../../api/utils'
    
    function CommonList(props){
      const { list } = props 
      
      return (
        <ListWrapper>
          <h1 className='title'>推荐歌单</h1>
          <List>
            {
              list.map((item, index) => {
                return (
                  <ListItem key={item.id + index}>
                    <div className='image-wrapper'>
                      <div className='decorate'></div>
                      <img src={item.picUrl + '?param=300x300'} width='100%' height='100%' alt='歌单'/>
                      <div className='play-count'>
                        <span className='iconfont play'>&#xe885;</span>
                        <span className='count'>{getCount(item.playCount)}</span>
                      </div>
                    </div>
                    <div className='desc'>{item.name}</div>
                  </ListItem>
                )
              })
            }
          </List>
        </ListWrapper>
      )
    }
    
    export default CommonList
    
    //components/list/style.js
    import styled from "styled-components"
    import style from '../../assets/global-style'
    
    export const ListWrapper = styled.div`
      max-width: 100%;
      .title {
        font-weight: 700;
        padding-left: 6px;
        font-size: 14px;
        line-height: 60px;
      }
    `
    
    export const List = styled.div`
      width: 100%;
      display: flex;
      flex-direction: row;
      flex-wrap: wrap;
      justify-content: space-around;
    `
    
    export const ListItem = styled.div`
      position: relative;
      width: 32%;
      .image-wrapper {
        .decorate {
          position: absolute;
          top: 0;
          width: 100%;
          height: 35px;
          border-radius: 3px;
          background: linear-gradient(hsla(0, 0%, 43%, 0.4), hsla(0, 0%, 100%, 0));
        }
        position: relative;
        height: 0;
        padding-bottom: 100%;
        img {
          position: absolute;
          width: 100%;
          height: 100%;
          border-radius: 3px;
        }
        .play-count {
          position: absolute;
          right: 2px;
          top: 2px;
          line-height: 15px;
          color: ${style['font-color-light']};
          font-size: ${style['font-size-s']};
          .play {
            vertical-align: top;
          }
        }
      }
      .desc {
        overflow: hidden;
        margin-top: 2px;
        padding: 0 2px;
        height: 50px;
        text-align: left;
        font-size: ${style['font-size-s']};
        line-height: 1.4;
        color: ${style['font-color-desc']};
      }
    `
    
    //api/utils.js
    export const getCount = (count) => {
      if (count < 0) return
      if (count < 10000) {
        return count
      } else if (Math.floor(count/10000) < 10000) {
        return Math.floor(count/1000)/10 + '万'
      } else {
        return Math.floor(count/10000000)/10 + '亿'
      }
    }
    

    better-scroll 的初步应用

    //baseUI/scroll/index.js
    import React, { forwardRef, useState,useEffect, useRef, useImperativeHandle } from 'react'
    import PropTypes from 'prop-types'
    import BScroll from 'better-scroll'
    import styled from 'styled-components'
    
    const ScrollContainer = styled.div`
      width: 100%;
      height: 100%;
      overflow: hidden;
    `
    const Scroll = forwardRef((props, ref) => {
      const [bScroll, setBScroll] = useState();
    
      const scrollContaninerRef = useRef();
    
      const { direction, click, refresh,  bounceTop, bounceBottom } = props;
    
      const { pullUp, pullDown, onScroll } = props;
    
      useEffect(() => {
        const scroll = new BScroll(scrollContaninerRef.current, {
          scrollX: direction === "horizental",
          scrollY: direction === "vertical",
          probeType: 3,
          click: click,
          bounce:{
            top: bounceTop,
            bottom: bounceBottom
          }
        });
        setBScroll(scroll);
        return () => {
          setBScroll(null);
        }
        // eslint-disable-next-line
      }, []);
    
      useEffect(() => {
        if(!bScroll || !onScroll) return;
        bScroll.on('scroll', (scroll) => {
          onScroll(scroll);
        })
        return () => {
          bScroll.off('scroll');
        }
      }, [onScroll, bScroll]);
    
      useEffect(() => {
        if(!bScroll || !pullUp) return;
        bScroll.on('scrollEnd', () => {
          //判断是否滑动到了底部
          if(bScroll.y <= bScroll.maxScrollY + 100){
            pullUp();
          }
        });
        return () => {
          bScroll.off('scrollEnd');
        }
      }, [pullUp, bScroll]);
    
      useEffect(() => {
        if(!bScroll || !pullDown) return;
        bScroll.on('touchEnd', (pos) => {
          //判断用户的下拉动作
          if(pos.y > 50) {
            pullDown();
          }
        });
        return () => {
          bScroll.off('touchEnd');
        }
      }, [pullDown, bScroll]);
    
    
      useEffect(() => {
        if(refresh && bScroll){
          bScroll.refresh();
        }
      });
    
      useImperativeHandle(ref, () => ({
        refresh() {
          if(bScroll) {
            bScroll.refresh();
            bScroll.scrollTo(0, 0);
          }
        },
        getBScroll() {
          if(bScroll) {
            return bScroll;
          }
        }
      }));
    
    
      return (
        <ScrollContainer ref={scrollContaninerRef}>
          {props.children}
        </ScrollContainer>
      );
    })
    
    Scroll.defaultProps = {
      direction: "vertical",
      click: true,
      refresh: true,
      onScroll:null,
      pullUpLoading: false,
      pullDownLoading: false,
      pullUp: null,
      pullDown: null,
      bounceTop: true,
      bounceBottom: true
    }
    
    Scroll.propTypes = {
      direction: PropTypes.oneOf(['vertical', 'horizental']),
      refresh: PropTypes.bool,
      onScroll: PropTypes.func,
      pullUp: PropTypes.func,
      pullDown: PropTypes.func,
      pullUpLoading: PropTypes.bool,
      pullDownLoading: PropTypes.bool,
      bounceTop: PropTypes.bool,//是否支持向上吸顶
      bounceBottom: PropTypes.bool//是否支持向上吸顶
    }
    
    export default Scroll
    
    // Recommend/index.js
    import { Content } from './style'
    import Scroll from '../../baseUI/scroll'
    <Content>
      <Scroll className="list">
        <div>
          <Slider list={bannerList}></Slider>
          <RecommendList list={recommendList}></RecommendList>
        </div>
      </Scroll>
    </Content> 
    
    
    // Recommend/style.js
    import styled from'styled-components';
    
    export const Content = styled.div`
      position: fixed;
      top: 90px;
      bottom: 0;
      width: 100%;
    `
    
    //slider/style.js
    .before {
      position: absolute;
      top: -300px;
      height: 400px;
      width: 100%;
      background: ${style ["theme-color"]};
    }
    

    数据层

    1.

    //api/config.js
    import axios from 'axios'
    
    export const baseUrl = 'http://localhost:8000'
    
    //axios 的实例及拦截器配置
    const axiosInstance = axios.create ({
      baseURL: baseUrl
    })
    
    axiosInstance.interceptors.response.use (
      res => res.data,
      err => {
        console.log (err, "网络错误")
      }
    );
    
    export {
      axiosInstance
    }
    

    2.

    //api/request.js
    import { axiosInstance } from "./config"
    
    export const getBannerListRequest = () => {
      return axiosInstance.get('/banner')
    }
    
    export const getRecommendListRequest = () => {
      return axiosInstance.get('/personalized')
    }
    

    3.

    //Recommond/store/reducer.js
    import * as actionTypes from './actionTypes'
    import { fromJS } from 'immutable'
    
    const defaultState = fromJS ({
      bannerList: [],
      recommendList: [],
    })
    

    4.

    //Recommond/store/actionTypes.js
    export const CHANGE_BANNER_LIST = 'recommend/CHANGE_BANNER_LIST'
    export const CHANGE_RECOMMEND_LIST = 'recommend/CHANGE_RECOMMEND_LIST'
    

    5.

    //Recommond/store/reducer.js
    export default (state = defaultState, action) => {
      switch (action.type) {
        case actionTypes.CHANGE_BANNER_LIST:
          return state.set('bannerList', action.data)
        case actionTypes.CHANGE_RECOMMEND_LIST:
          return state.set('recommendList', action.data)
        default:
          return state
      }
    }
    

    6.

    //Recommond/store/actionCreators.js
    import * as actionTypes from './actionTypes'
    import { fromJS } from 'immutable'
    import { getBannerListRequest, getRecommendListRequest } from '../../../api/request'
    
    export const changeBannerList = (data) => ({
      type: actionTypes.CHANGE_BANNER_LIST,
      data: fromJS(data)
    })
    
    export const changeRecommendList = (data) => ({
      type: actionTypes.CHANGE_RECOMMEND_LIST,
      data: fromJS(data)
    })
    
    export const getBannerList = () => {
      return (dispatch) => {
        getBannerListRequest().then (data => {
          dispatch(changeBannerList(data.banners))
        }).catch (() => {
          console.log("轮播图数据传输错误")
        }) 
      }
    }
    
    export const getRecommendList = () => {
      return (dispatch) => {
        getRecommendListRequest().then (data => {
          dispatch (changeRecommendList(data.result))
        }).catch (() => {
          console.log ("推荐歌单数据传输错误");
        })
      }
    }
    

    7.\color{red}{导出!!!}

    //Recommond/store/index.js
    import reducer from './reducer'
    import * as actionCreators from './actionCreators'
    
    export { reducer, actionCreators }
    

    8.\color{red}{注册!!!}

    //src/store/reducer.js
    import { combineReducers } from 'redux-immutable'
    import { reducer as recommendReducer } from '../application/Recommend/store'
    
    export default combineReducers ({
      recommend: recommendReducer,
    })
    

    9.

    //Recommond/index.js
    import React, { useEffect, memo } from 'react'
    import { Content } from './style'
    import Slider from '../../components/slider'
    import CommonList from '../../components/list'
    import Scroll from '../../baseUI/scroll'
    import { connect } from "react-redux"
    import * as actionCreators from './store/actionCreators'
    
    function Recommend(props) {
      const { bannerList, recommendList } = props
      const { getBannerListDataDispatch, getRecommendListDataDispatch } = props
    
      useEffect (() => {
        getBannerListDataDispatch()
        getRecommendListDataDispatch()
        //eslint-disable-next-line
      }, [])
    
      const bannerListJS = bannerList ? bannerList.toJS() : []
      const recommendListJS = recommendList ? recommendList.toJS() : []
    
      return (
        <Content>
          <Scroll className='list'>
            <div>
              <Slider list={bannerListJS}/>
              <CommonList list={recommendListJS}/>
            </div>
          </Scroll>
        </Content>
      )
    }
    
    const mapStateToProps = (state) => ({
      bannerList: state.getIn(['recommend', 'bannerList']),
      recommendList: state.getIn(['recommend', 'recommendList']),
    })
    
    const mapDispatchToProps = (dispatch) => {
      return {
        getBannerListDataDispatch() {
          dispatch(actionCreators.getBannerList())
        },
        getRecommendListDataDispatch () {
          dispatch(actionCreators.getRecommendList())
        }
      }
    }
    
    export default connect(mapStateToProps, mapDispatchToProps)(memo(Recommend))
    

    相关文章

      网友评论

          本文标题:播放器

          本文链接:https://www.haomeiwen.com/subject/rgmhactx.html