音乐播放器笔记

来源:互联网 发布:js数组的长度 编辑:程序博客网 时间:2024/05/16 12:20

  • 音乐播放器完整实例开发
    • 项目分析
    • 开发环境
    • 播放器基本功能
    • 播放器高级功能
    • 最佳实践
    • 开发过程知识学习在实践中学习
      • React组件通信
        • 父-子组件通信
          • 实现手段
          • 最佳实践
          • 通信的动机
        • 子-父组件通信
        • 同级组件通信
          • 实现手段
          • 通信的动机
      • webpack中 pathpublicPath webpack-dev-server中 content-base
      • file-loader和url-loader
        • 浏览器并发请求资源数限制
        • base64
        • dataURL
      • inline和inline-block
        • background-size
        • transition
      • refs
      • offsetXclientXpageX等位置的计算
      • overflow
      • thispropschildren
      • ReactcloneElement
      • react-router-dom中的BrowserRouter
      • constructorprops和constructor
      • 路由Route匹配
      • ES6的扩展运算符
    • 问题解决

音乐播放器完整实例开发

项目分析

项目开发是由思想来指导代码的编写顺序和步骤,而不是思想被代码主导。项目开发重要的不是编写代码,而是学习项目开发中的思想和解决问题的方法

开发思想:工程建立—>模块化开发(具体来说就是组件化开发,每一个组件都是一个模块)。每一个组件都是由.js文件样式.less文件和组成,然后导入导出模块(组件)进行拼接组合,层层上溯,最后形成一个完整的项目。

  1. 项目的模块版本太陈旧,很多写法没有办法照搬,需要结合新版本的写法,新的参数,新的内容来进行重新写。

  2. 组件分析:

    • 头部<Header />

    • 播放界面<PlayUI />

      • 暂停/播放<PlayPause/>
      • 播放规则<PlayRule />
      • 进度条<Progress />
      • 歌名和歌手<Singer />
      • 路由组件:链接<Link />
    • 选歌界面<SelectSong />

      • 歌曲<Song/>
    • 组件结构
  3. 组件通信:propsstate

开发环境

Webpack+React+ES6+Router+Less+Babel+GitHub

当通过一个使用了ES6和JSX语法的js文件通过webpack-dev-server指令运行后,在浏览器中输入正确的网址,页面能正常显示,并且更改js源文件页面自动刷新,则说明环境配置完成。

  • 一个现有的完整项目的分析从package.json入手,分析其用到的插件和模块,用到的运行指令,以及项目的介绍。

播放器基本功能

播放器高级功能

最佳实践

开发过程知识学习(在实践中学习)

开发过程中遇到新的知识点就学习!!!

React组件通信

参考文章:React 组件之间的通信方式

组件之间的通信分为3种:父-子组件通信、子-父组件通信和同级组件之间的通信。

父-子组件通信

项目中暂时未遇到!

实现手段:

父组件只需要将子组件需要的props传给子组件,子组件直接通过this.props来使用

最佳实践:

为了将子组件设计成一个复用性强的通用组件,需要将能够复用的部分抽象出来。
抽象出来的props有两种形成,一种是简单的变量,另一种是抽象出来处理某种逻辑的函数

通信的动机:

子组件需要这样的属性来完成自己的展示。还有一种动机可以统称向子组件传递监听事件。前一种是子组件的需求,后一种更多的是父组件的需求。

子-父组件通信

同级组件通信

同级组件之间的通信,是构建复杂界面的粘合剂

实现手段

同级组件之间的通信需要通过父组件作为中介,将需要传递的数据放在父组件的state中,利用多次父-子组件通信,变动时可以自动地同步传递。

通信的动机:

当组件需要的props,不能直接从父组件中获取时,需要父组件作为中介,再与其他的组件进行通信获取。

webpack中 path,publicPath ,webpack-dev-server中 –content-base

path:用来存放打包后文件的输出目录
publicPath:指定资源文件引用的目录

====================================

webpack-dev-server环境下,path、publicPath、区别与联系

path:指定编译目录而已(/build/js/),不能用于html中的js引用。
publicPath:虚拟目录,自动指向path编译目录(/assets/ => /build/js/)。html中引用js文件时,必须引用此虚拟路径(但实际上引用的是内存中的文件,既不是/build/js/也不是/assets/)。

====================================

发布至生产环境:

1.webpack进行编译(当然是编译到/build/js/)
2.把编译目录(/build/js/)下的文件,全部复制到/assets/目录下(注意:不是去修改index.html中引用bundle.js的路径)

===================================

–content-base:必须指向应用根目录(即index.html所在目录),与上面两个配置项毫无关联。

file-loader和url-loader

参考文章:
webpack学习笔记-2-file-loader 和 url-loader
webpack踩坑之路 (2)——图片的路径与打包

两者主要用来处理图片,url-loader内置了file-loader,file-loader中的参数url-loader都可以用。所以在使用时安装url-loader即可。

file-loader可以解析项目中的url引入,根据配置,将图片拷贝到相应的路径

url-loader会将引入的图片编码,生成dataURl。相当于把图片数据翻译成一串字符。再把这串字符嵌入到了页面中,与HTML成为一体,以实现对图片的访问。如果图片较大,编码会消耗性能。因此url-loader提供了一个limit参数,小于limit字节的文件会被转为DataURl,大于limit的还会使用file-loader进行处理。

url-loader的优劣:

劣:

  1. 在减小http请求数的同时增大了js或者html文件的大小,而且在图片的重用度较高时,每一次的引入会造成代码冗余。而使用http请求加载的图片会被缓存到浏览器,下次访问会速度很快。因此要平衡考虑使用!!
  2. Base64编码的数据体积通常是原数据的体积4/3,也就是Data URL形式的图片会比二进制格式的图片体积大1/3。

优:

  1. 当图片是在服务器端用程序动态生成,每个访问用户显示的都不同时(场景较少)
  2. 当图片的体积太小,占用一个HTTP会话不是很值得时(雪碧图可以出场了)

浏览器并发请求资源数限制

  1. 这是浏览器作为一个有良知的客户端在保护服务器。将所有请求一起发给服务器,也很可能会引发服务器的并发阈值控制而被(BAN)禁止,而另外一个控制在8以内的原因也是keep alive技术的存在使得浏览器复用现有连接和服务器通信比创建新连接的性能要更好一些。

  2. 由于 TCP 协议的限制,PC 端只有65536个端口可用以向外部发出连接,而操作系统对半开连接数也有限制以保护操作系统的 TCP\IP 协议栈资源不被迅速耗尽,因此浏览器不好发出太多的 TCP 连接,而是采取用完了之后再重复利用 TCP 连接或者干脆重新建立 TCP 连接的方法。

补充:半开连接指的是 TCP 连接的一种状态,当客户端向服务器端发出一个 TCP 连接请求,在客户端还没收到服务器端的回应并发回一个确认的数据包时,这个 TCP 连接就是一个半开连接。

base64

Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法。Base64编码是从二进制到字符的过程,

dataURL

参考文章:data url简介及data url的利弊

使用原因:img标记的src属性指定了一个远程服务器上的资源。当网页加载到浏览器中 时,浏览器会针对网页使用到的每个外部资源都向服务器发送一次拉取资源请求,占用网络资源。大多数的浏览器都有一个并发请求数不能超过4个的限制。这意味着,如果一个 网页里嵌入了过多的外部资源,这些请求会导致整个页面的加载延迟。而使用Data URL技术,图片数据以base64字符串格式嵌入到了页面中,与HTML成为一体

inline和inline-block

inline: inline元素的margin和padding属性,水平方向的padding-left, padding-right, margin-left, margin-right都产生边距效果;但竖直方向的padding-top, padding-bottom, margin-top, margin-bottom不会产生边距效果。

inline-block: 将对象呈现为inline对象,但是对象的内容作为block对象呈现。并且对象具有宽高,padding,margin的特性。不过-top和-bottom时会带动起所在的行一起移动。

background-size

取值为百分比:将计算相对于背景定位区域的百分比

transition

transition-delay:延迟时间
transition-duration:过渡时间
transition-timing-function:过渡时间函数

取值:linear: 线性过渡。等同于贝塞尔曲线(0.0, 0.0, 1.0, 1.0) ease: 平滑过渡。等同于贝塞尔曲线(0.25, 0.1, 0.25, 1.0) ease-in: 由慢到快。等同于贝塞尔曲线(0.42, 0, 1.0, 1.0) ease-out: 由快到慢。等同于贝塞尔曲线(0, 0, 0.58, 1.0) ease-in-out: 由慢到快再到慢。等同于贝塞尔曲线(0.42, 0, 0.58, 1.0) 

refs

参考文章:
React文档(十六)refs和DOM
对组件的引用(refs)

以下有几种很好的方式使用refs:

  • 管理焦点,文本选择或者媒体播放
  • 触发重要的动画
  • 整合第三方DOM库

React支持一个特殊的属性,你可以把它挂到任何的组件上。这个ref属性可以是一个回调函数,并且这个回调函数会在组件被挂载后立刻被执行。引用到的组件会被作为参数传递,这个回调函数可以立即使用组件,或者把它的引用保存起来供将来使用(又或者,两者兼有)。
立即使用:

render() {  return (    <TextInput      ref={function(input) {        if (input != null) {          input.focus();        }      }} />  );}

保存为变量:

render() {    return <TextInput ref={(c) => this._input = c} />;}componentDidMount() {    this._input.focus();}

offsetX、clientX、pageX等位置的计算

参考文章:
offsetX、clientX、pageX等位置的计算
理解 e.clientX,e.clientY e.pageX e.pageY e.offsetX e.offsetY

  • event.clientX、event.clientY
    鼠标相对于浏览器窗口可视区域的X,Y坐标(窗口坐标),可视区域不包括工具栏和滚动条。IE事件和标准事件都定义了这2个属性

  • event.screenX、event.screenY
    鼠标相对于用户显示器屏幕左上角的X,Y坐标。标准事件和IE事件都定义了这2个属性

  • event.pageX、event.pageY
    类似于event.clientX、event.clientY,但它们使用的是文档坐标而非窗口坐标。这2个属性不是标准属性,但得到了广泛支持。IE事件中没有这2个属性。

  • event.offsetX、event.offsetY
    鼠标相对于事件源元素(srcElement)的X,Y坐标,只有IE事件有这2个属性,标准事件没有对应的属性。

  • clientWidth:对象相对于网页可见区域的宽度(无滚动条时,包括padding和content。有滚动条时在原来计算的基础上减去滚动条的宽度和高度)
    clientHeight:对象相对于网页可见区域的高度

滚动条占用的空间是盒模型中content和padding部分

  • scrollHeight: 获取对象的滚动的高度。(高度包括content和上下padding)
    scrollWidth:获取对象的滚动的宽度(高度包括content和左右padding)
    scrollLeft:设置或获取位于对象左边界和窗口中目前可见内容的最左端之间的距离,即被卷起的宽度(包括盒模型中的padding和content,当移到最下边和最右边的时候,会把滚动条相对于内容内侧的那个边作为边框,而不是原来的边框)
    scrollTop:设置或获取位于对象最顶端和窗口中可见内容的最顶端之间的距离,即被卷起的高度

overflow

visible:默认值。内容不会被修剪,会呈现在元素框之外。
hidden:内容会被修剪,并且其余内容是不可见的。
scroll:内容会被修剪,但是浏览器会显示滚动条以便查看其余的内容。
auto:如果内容被修剪,则浏览器会显示滚动条以便查看其余的内容。

scroll和auto的区别在于scroll一定会显示滚动条,而auto只有在内容超了的时候才会显示滚动条。

this.props.children

this.props 对象的属性与组件的属性一一对应,但是有一个例外,就是 this.props.children 属性。它表示组件的所有子节点

React.Children 是顶层API之一,为处理 this.props.children 这个封闭的数据结构提供了有用的工具。

我们可以用 React.Children.map 来遍历子节点,而不用担心 this.props.children 的数据类型是 undefined 还是 object.

var NotesList = React.createClass({  render: function() {    return (      <ol>      {        React.Children.map(this.props.children, function (child) {          return <li>{child}</li>;        })      }      </ol>    );  }});ReactDOM.render(  <NotesList>    <span>hello</span>    <span>world</span>  </NotesList>,  document.body);

React.cloneElement()

React.cloneElement
参数:TYPE(ReactElement),[PROPS(object)],[CHILDREN(ReactElement)]

克隆并返回一个新的 ReactElement (内部子元素也会跟着克隆),新返回的元素会保留有旧元素的 props、ref、key,也会集成新的 props(只要在第二个参数中有定义)。

当一个组件作为一个路由对应的组件时,无法在路由中向该组件传参,此时可以用React.cloneElement来传参。
作用:给子元素添加新的属性返回

{React.cloneElement(this.props.children, this.state)}

react-router-dom中的BrowserRouter

  • 只能有一个子元素,而且不能是<Route>,一般用<div>

constructor(props)和constructor()

  • 调用super的原因:ES6中,在子类的constructor中必须先调用super才能引用this
  • super(props)的目的:在constructor中可以使用this.props

    所以只有一个理由需要传递props作为constructor()和super()的参数,那就是你需要在构造函数内使用this.props

但是官方给的例子都是写的

constructor(props){    super(props);}

所以建议一般这样写。

路由(Route)匹配

1.关于匹配:假如有路由”/”,”/A”,”/A/B”
则在访问路径是”/A/B”时会匹配到三个路由,
在访问路径是“/A”时会同时匹配到”/”
所以要想让路由“/A”只在访问路径时“/A”被匹配到,需要在路由里面添加参数exact。这就是默认路径一般会添加exact的原因

2.Switch组件可以只让匹配到的第一个组件被渲染出来,所以在Switch里面,一般将容易多次匹配到的路由Route写在最后面。

…:ES6的扩展运算符

将一个数组转为参数序列,主要用于函数调用,作为参数传入

function push(array, ...items) {  array.push(...items);  }  

//withRouter可以包装任何自定义组件,
// 将react-router 的 history,location,match 三个对象传入
//当需要用的Route 属性的时候,将组件包一层withRouter,就可以拿到需要的路由信息
//保证组件被正确使用变得非常有用。为此引入propTypes属性类型

问题解决

  1. Package require os(darwin) not compatible with your platform(win32):cnpm安装时,安装包不兼容win32

    解决办法:cnpm rebuild node-sass

  2. 浏览器的子页面更新后找不到文件:

    解决办法:设置属性historyApiFallback(devServer): 对于单页面程序,浏览器的browerhistroy可以设置成html5 history api或者hash,而设置为html5 api的,如果刷新浏览器会出现404 not found,原因是它通过这个路径(比如: /activities/2/ques/2)来访问后台,所以会出现404,而把historyApiFallback设置为true那么所有的路径都执行index.html。(参考文章:webpack 看我就够了)

  3. webpack.config.js从一个应用移植到另一个应用?

    需要注意的是:各个loader或者是和插件中用到了路径的地方。比如babel-loader中的include属性,需要改变原路径到该项目中正确的路径。否则无法正常加载。

  4. import导入文件的路径出错?

    解决办法:后面的from指定模块文件的位置,可以是相对路径,也可以是绝对路径,.js路径可以省略。如果只是模块名,不带有路径,那么必须有配置文件,告诉 JavaScript 引擎该模块的位置。

    import是静态执行,所以不能使用表达式,变量和语句,这些只有在运行时才能得到结果的语法结构。

  5. 图片无法被正常加载解析显示?

    使用file-loader时,css/less文件中的url会被正确加载显示,在index.html中的img标签中的图片也会正常加载显示,但是在jsx中使用ing无法正确加载?

    解决办法:
    本地图片<img src={require(‘xxx.jpg’)} />
    外链图片<img src={‘imgurl’} />

  6. **webpack中扩展运算符…使用babel不能通过编译?

解决办法:

要使用插件babel-plugin-transform-object-rest-spread,

  • NPM 安装 babel-plugin-transform-object-rest-spread插件
  • 在.babelrc文件中添加:”plugins”: [“transform-object-rest-spread”]

7.使用官方的react-router的文档中的验证的代码时出错?

解决办法:
新的react语法必须把状态量写在this.state里面,然后对于函数必须使用bind方法,参数为this,使得函数能够作用在当前类型中。