原生事件绑定(.native)

如果想给vue组件绑定原生事件处理,要在事件名之后加上 .native。比如 element-ui 的输入框组件的点击事件和表单组件的数据提交。

组件定位

响应式,解决组件尺寸问题,可以酌情考虑的单位:vwvh(IE8以下有兼容性问题),当然还有rem

第三方组件的定位控制

el-form 表单内每一项之间的外边距不好控制。

组件间数据传递

  • 父到子
    父组件::sonData="parentData"
    子组件:props: ['sonData']

  • 子到父
    子组件:$emit('event-name', data)
    父组件:@event-name="handler(data)"

注意事件名应该是短横线命名法。事件名没有大小写转换,但 v-on 事件监听器会被转换为全小写,所以事件名应该使用短横线命名法。

组件里 propsmodel

props 用于创建组件时传入一次数据,而 v-model 可以使组件与子组件的数据双向绑定。

隔着一个组件往上传数据,为什么要用计算属性

就是文件链接设置歌曲这个组件,传数据给main组件,如果在按键绑定的点击事件往上传data中的数据,那么往后这个组件里只要数据有更新,不用点按键,data 里要传的更新过的数据就已经传给 main 组件了。如果用计算属性,则不会有这种情况。即 @click=”$emit(‘update-linkfile, newLinkFileInfo)”, 参数是一个另外重新根据新数据进行赋值的计算属性。

好了,没事了。bug不见了…但是为什么?

组件的数据验证

某些组件对 props 会有验证,比如 APlayer 如果接收到的 music 这个 props 对象中某个必需键的值为空字符,那么控制台将会显示
[Vue warn]: Invalid prop: custom validator check failed for prop …

所以使用组件时要注意组件的 prop。

vue-APlayer 的更新问题(版本:1.6.1)

第一次通过props创建(渲染) vue-APlayer 之后,就不能在父组件中对其进行修改歌曲、播放列表等操作了。想要再次更改播放器的信息(例如利用ajax获取歌曲信息去更新),就要用另一种方法。

解决方案,
父组件设置一个 showPlayer 属性,然后通过 v-if 来控制 APlayer 的创建和销毁

<aplayer v-if="showPlayer" :music="music" :showLrc="true”>

定义一个设置 music 的方法,方法运行最初将 showPlayer 设为 false,就将上次创建的 APlayer 销毁了,然后在其中调用获取歌曲信息的方法(比如ajax),获取完之后(ajax的成功回调),设置 musicshowPlayer,这样,将利用新的 music 数据去创建一个 APlayer ,就达到了目的。

跨域问题

参考了:Webpack dev server使用http-proxy解决跨域问题
页面资源由 webpack-dev-server 提供,地址是 http://localhost:8080
然后获取歌曲信息的API地址是 http://localhost:3000

其实我是在安卓 chrome 上调试页面时发现这个问题的,
如下:

Failed to load http://192.168.1.138:3000/song/detail?ids=28739330: The 'Access-Control-Allow-Origin' header has a value 'http://0.0.0.0:8080' that is not equal to the supplied origin. Origin 'http://192.168.1.138:8080' is therefore not allowed access.

如果我要在手机上访问 webpack-dev-server 提供的页面,webpack-dev-server 要设置 host0.0.0.0,手机要访问 我的电脑在局域网中的地址:端口号,这里是 http://192.168.1.138:8080

然而获取歌曲信息的地址被写死了,localhost:3000,到了手机上就是 手机的局域网地址:3000,与网页不同源了,因而出现上述跨域问题。

解决:
1)、首先改变获取歌曲信息的API地址为:http://192.168.1.138:8080/api,这样api地址和页面地址就是同源的了。
但是 http://192.168.1.138:8080/api 并没有真正提供API,所以需要在服务器端做一个转发,将API请求转发到真正的API地址。

2)、在 webpack 配置文件中修改 webpack-dev-server 的配置,主要是增加代理

    proxy: {
      '/api/*': {
        target: 'http://localhost:3000/',
        pathRewrite: {'^/api': ''},
        changeOrigin: true,
        secure: false
      }
    }

http://192.168.1.138:8080/api 的请求都转发到 localhost:3000/

pathRewrite 项是将API信息地址的路径部分的 api 去掉,因为本来API的地址是直接访问根路径的,localhost:3000

重启 webpack-dev-server

现在手机电脑访问都ok了。

网易云链接的正则

先提取链接,然后从链接里提取歌曲ID

按键事件

组件上响应按键释放事件,这个比较简单,类似于 @keyup.enter.native="...",还可以给按键设置别名,组合多个按键等。

ref 的使用

ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。

对vue-APlayer组件增加了 ref="aplayer",方便获取当前播放歌曲的已播放时长。

input的控制问题

可以粗浅分为值控制和行为控制吧。

可以通过数据绑定、对数据属性进行修改,以控制输入框的值。
控制输入框行为,就是控制光标、内容滚动等。如果是原生的元素,可以直接通过ref获取元素,然后用原生方法来对其进行控制。但如果是组件中的输入框(比如 element-ui 中的 el-input),我感觉就只能通过js的dom元素查找和操作方法来进行控制了。

让我绕了一圈的一个小坑,就是每次给输入框赋新值后,光标其实都会移动到末尾,而不是停留在之前的位置。

其实仅仅处理行前后的话,不要按照字符在整体中的位置处理,从行数出发可能会更易于理解和处理。

编辑框要确定当前编辑行,是用点击事件获取,还是通过计算属性获取?

肯定是要绑定编辑框的点击事件的,毕竟每次输入框值更新后,光标都会移动到末尾。本来打算设置计算属性直接获取光标位置,完全不行。

所以,点击哪行,就是要给哪行加时间标签。加完标签后,当前行++。

写好基础代码(自用库)的注释

vs code 的函数提示真的不错。

组件更新

vue-APlayer,创建之后没办法再修改它内部的信息,那就只能用 v-if 等语句控制它的渲染,通过控制一个值来控制它的渲染。

值更新太快会使vue没办法检测到变化吗? 好吧,并不会。时刻记住vue的“数据双向绑定”机制。

props 是父组件向子组件传递信息的渠道,通过 props 传递的信息发生变化时,子组件也随之做出变化。

这里,我希望可以控制 APlayer 的 lrc,在编辑完成后可以通过点击预览按钮,改变之前通过 music 这个 props 传递的信息(主要是改变了歌词信息)。

这里,有一个比较重要的问题。music 对象是与 APlayer 进行了绑定的,music 有任何变化都会导致 APlayer 发生变化。
一开始的music对象中的确赋予了一个lrc属性,但是这个lrc的值在取值的时候要注意。因为需要用到预览功能将编辑框中的歌词信息传递给 APlayer,所以很直接的想法就是直接通过编辑框来获取值然后给 music 的 lrc属性,但是最好不要这样做,或者说要有一个判断处理。

直接 musci.lrc = lrcEditor.value 这样的粗暴操作,会使得 APlayer 因为编辑框的文字变化而频繁刷新,而且没有编辑完成的歌词直接显示在播放器中也显得凌乱。
所以,一个解决方法是设置当前组件设置一个叫 previewingdata,通过判断它的真假值来决定是利用编辑框内容还是默认内容来对 music.lrc进行赋值。previewing 默认应当是 false。当点击预览按钮时,将 previewing 设为 true,此时通过编辑框获取歌词内容。当结束预览时,将 previewing 改为 false

querySelector 的使用

有时候只能通过js的原生dom操作来解决一些问题。

自动保存编辑中的歌词

定时保存正在编辑的歌词到localStorage,点击下载歌词后清除localStorage的歌词内容并清除计时器。可以监听音乐来源信息是否更新来确定是否重新增加自动保存计时器

无版权音乐get

参考:有没有可以随意使用的无版权音乐资源库?

默认音频:https://freepd.com/music/City%20Sunshine.mp3

加载网络文件成功后的无版权图片:https://gratisography.com/fullsize/gratisography-157H.jpg

移动端滚动问题、光标问题

其实就是编辑框高度问题,响应式问题

生成文件下载

fileapi相关知识

读取本地音乐

blob对象相关知识

禁止表单post(仅需本地读取歌曲而已)

element-ui upload 组件关闭自动上传,回车键事件监听。

对于歌词编辑框的数据更新问题(input输入框对象的新value更新到data)

再次证明了使用VUE的过程中,应该减少对dom的手动操作。手动对输入框赋新值,不会引起element-ui的input组件data更新,所以上级绑定的data同样也不会更新。
所以,应该将值赋给上级的data,由上往下地引起数据更新,最后input输入框的值是会更新的。

网易云音乐几种不同的分享链接

1 ios:
分享古巨基的单曲《眼睛不能没眼泪》http://music.163.com/song/86257?userid=118383880 (@网易云音乐)
2 Android:
分享古巨基的单曲《另一双手》: http://music.163.com/song/86242/?userid=118383880 (来自@网易云音乐)
3 Mac OS:
http://music.163.com/#/m/song?id=68350
4 网页:
http://music.163.com/#/song?id=473163943

响应式布局

常见的几种尺寸

em 和 rem :浏览器根据谁来转化成px值。
em,根据当前元素的字体大小来决定尺寸。但是因为字体大小有可能经过多重继承进而影响 em 单位的大小,所以应当显式指定当前元素的字体大小(比如多少px)。1em = 当前元素字体尺寸的一倍。

rem,取决于页根元素(html)的字体大小。1rem = 根元素字体尺寸的一倍

当根元素没有指定字体大小时,浏览器设置中字体大小会影响页面

参考:下手响应式及断点设置分析

阿里字体图标的使用

element-ui 本身就带有一些常用的字体图标,但没找到合适的,所以就换了一些。

减小打包体积

第三方库分到 vendor.js,或者采用CDN的方式引入。

路由的使用,当前路由地址

路由设置,监听。

部署

国外服务器获取歌曲链接的问题。本来觉得国外服务器可能要用代理,或者利用一下国内的服务器,后来根据API文档解决了问题。

nginx反向代理,让API为前端服务,参考:
Nginx反向代理映射成子路径Nginx的location规则:优先级和路径替换

此外,为减小静态资源体积,在 nginx 提供页面服务的 server 段中开启 gzip。
参考 Nginx(4)-nginx配置文件详解-http配置段

加入gzip相关配置如下

  # 开启gzip
  gzip on;
  # 启用gzip压缩的最小文件,小于设置值的文件将不会压缩
  gzip_min_length 1k;
  # gzip 压缩级别,1-10,数字越大压缩的越好,也越占用CPU时间,后面会有详细说明
  gzip_comp_level 2;
  # 进行压缩的文件类型。javascript有多种形式。其中的值可以在 mime.types 文件中找到。
  gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
  # 是否在http header中添加Vary: Accept-Encoding,建议开启
  gzip_vary on;
  # 禁用IE 6 gzip
  gzip_disable "MSIE [1-6]\.”;

设置nginx 的缓存:

  location ~* ^.+\.(ico|gif|jpg|jpeg|png)$ {
        access_log   off;
        expires      30d;
  }
  location ~* ^.+\.(css|js|txt|xml|swf|wav)$ {
    access_log   off;
    expires      24h;
  }
  location ~* ^.+\.(html|htm)$ {
        expires      1h;
  }

nginx中,404页面的设置。