Vue-music 小知识点

  • Object.assign()

方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

语法
Object.assign(target, ...sources)

具体请参考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

  • 数组的空位

数组的空位指,数组的某一个位置没有任何值。比如,Array构造函数返回的数组都是空位。

Array(3) // [, , ,]

上面代码中,Array(3)返回一个具有3个空位的数组。

注意,空位不是undefined,一个位置的值等于undefined,依然是有值的。空位是没有任何值,in运算符可以说明这一点。

0 in [undefined, undefined, undefined] // true
0 in [, , ,] // false

上面代码说明,第一个数组的0号位置是有值的,第二个数组的0号位置没有值。
参考:http://es6.ruanyifeng.com/#docs/array

  • fastclickbetter-scroll 点击冲突,只需要给被点击的元素添加一个类: class="needsclick", 最新版本的better-scroll已经解决了这个问题,不用再加class="needsclick"

如:给img标签添加class="needsclick"


    

  • 数组根据标题首字母排序
ret.sort((a, b) => {
   return a.title.charCodeAt(0) - b.title.charCodeAt(0)
})

参考:http://www.w3school.com.cn/jsref/jsref_charCodeAt.asp
以及:music 歌手页面

  • 通过map获取一个新的集合数组
computed: {
      shortcutList() {
      //group:获取到的每一个对象
        return this.data.map((group) => {
          //从0开始,截取一个字符
          return group.title.substr(0, 1)
        })
      }
},
  • 数组过滤 filter()
computed: {
      /* 计算出推荐的数组 */
      positives() {
        return this.ratings.filter((rating) => {
          return rating.rateType === POSITIVE;
        });
      },
      /* 计算出吐槽的数组 */
      negatives() {
        return this.ratings.filter((rating) => {
          return rating.rateType === NEGATIVE;
        });
      }
    },
  • @touch 触碰事件
  • {{item}}
  • event.target 事件属性可返回事件的目标节点(触发该事件的节点),如生成事件的元素、文档或窗口。

下面的例子可获得触发事件的元素:









Click on this paragraph. An alert box will show which element triggered the event.

  • Vue.js 定义一个变量,若不想被系统添加set和get方法,可以定义在created()钩子里面

这样,系统就不会去观测该变量值的改变,从而影响双向绑定

created() {
   this.touch = {}
    ......
}
  • better-scroll scrollToElement(), 第一个参数指的是节点,第二个参数:动画时间

下面的例子中,0指的是动画时间为0
这个默认把你所在的那一行滚动到顶部位置!!!

this.$refs.listview.scrollToElement(this.$refs.listGroup[index], 0)
  • methods 方法书写规范

公共方法放在上面,
私有的方法放在下面.
如下图:

    methods: {
      refresh() {
          ......
      },
      scroll(pos) {
          ......
      },
      _calculateHeight() {
          ......
      },
      _scrollTo(index) {
          ......
      }
    },
  • 数据的变化,到dom的变化,大概耗时17ms

所以,一般倒计时20ms后执行需要操作的函数。

watch: {
  data() {
    setTimeout(() => {
          this._calculateHeight()
     }, 20)
  }
}
  • better-scroll的probeType属性默认是1,如果想要在scroll快速滚动的时候,正确的监听scroll,需把该属性设置为3。
  • 设置background-image:url( ),最好写在行内样式里面,不要写在css里.

计算属性:

computed: {
      bgStyle() {
        return `background-image:url(${this.bgImage})`
      }
    },
  • this.$refs.list.$el.style.top = ${this.imageHeight}px

vm.$el : Vue 实例使用的根 DOM 元素, 类型:HTMLElement

Vue-music 小知识点_第1张图片
this.$refs.list.$el.style.top
  • Math.max(x...) 返回两个指定的数中带有较大的值的那个数。

    Math.PI * 2r : 获取圆的周长


    Vue-music 小知识点_第2张图片
    Math 对象方法
  • js修改样式时,则需要把webkit-xxx也写上,也可以单独封装来实现autoprefix效果,如: vue-music

    注意: width,height 除外

this.$refs.filter.style['backdrop-filter'] = `blur(${blur}px)`
this.$refs.filter.style['webkitBackdrop-filter'] = `blur(${blur}px)`

封装, 创建一个js文件


let elementStyle = document.createElement('div').style

let vendor = (() => {
  let transformNames = {
    webkit: 'webkitTransform',
    Moz: 'MozTransform', // 火狐
    O: 'OTransform', // 欧朋
    ms: 'msTransform', // IE
    standard: 'transform'
  }

  for (let key in transformNames) {
    if (elementStyle[transformNames[key]] !== undefined) {
      return key
    }
  }

  return false
})()

// 在外边调用该方法
export function prefixStyle(style) {
  if (vendor === false) {
    return false
  }

  if (vendor === 'standard') {
    return style
  }

  // vendor 浏览器厂家
  // style.charAt(0).toUpperCase() + style.substr(1) 首字母大写
  return vendor + style.charAt(0).toUpperCase() + style.substr(1)
}

在外边直接调用prefixStyle()函数

  • vue-router 按钮返回上一个界面
this.$router.back()
  • push到子路由
this.$router.push({
   path: `/singer/${singer.id}` // ${singer.id} 为传递的参数
})
  • Vuex 在传递参数时的使用
    • 先在父界面,引入mapMutations 语法糖
      import {mapMutations} from 'vuex'
      
    • 在该界面methods中代理该...mapMutations语法糖
      methods: {
          ...mapMutations({
              setSinger: 'SET_SINGER'
          })
      }
      
    • push界面时,调用上面的setSinger
      this.setSinger(singer)
      
    • 在使用该参数的界面,先引入mapGetters语法糖
      import {mapGetters} from 'vuex'
      
    • 在计算属性中实现...mapGetters()语法糖
      computed: {
        ...mapGetters([
          'singer'
        ])
      }
      
    • 最后就可以愉快的使用了
      this.singer.id 或者 singer.id 看情况决定是否使用this调用
      
  • 创建model 和 class的区别
    • 创建model
      export const playMode = {
           sequence: 0,
           loop: 1,
           random: 2
      }
      
      在外部使用先引入
      import {playMode} from 'common/js/config'
      
      再调用
      mode: playMode.sequence
      
    • 创建class
       export default class Singer {
         constructor({id, name}) {
            this.id = id
            this.name = name
            this.avatar =   `https://y.gtimg.cn/music/photo_new/T001R300x300M000${id}.jpg?max_age=2592000`
         }
      }
      
      class在外部调用时,需要new一个对象
      map.hot.items.push(new Singer({
                name: item.Fsinger_name,
                id: item.Fsinger_mid
      }))
      
  • 事件派发
this.$emit('select', item, index)
  • index : index ,前后一致,可以简写为index,如下面的方法
selectItem(item, index) {
     this.selectPlay({
        list: this.songs,
        index
     })
},
  • 获取屏幕的宽度/高度 window.innerWidth/window.innerHeight
window.innerWidth / window.innerHeight
  • ES6的写法
const {x, y, scale} = this._getPosAndScale()

_getPosAndScale()函数为

_getPosAndScale() {
        const targetWidth = 40
        const paddingLeft = 40
        const paddingBottom = 30
        const paddingTop = 80
        const width = window.innerWidth * 0.8
        const scale = targetWidth / width
        const x = -(window.innerWidth / 2 - paddingLeft)
        const y = window.innerHeight - paddingTop - width / 2 - paddingBottom
        return {
          x,
          y,
          scale
        }
      }
  • Vue 过渡动画transition,可以利用钩子实现一些特殊动画.

动画和过渡的区别 ?
动画:可以不需要触发就可以执行
过渡:需要人为触发

可以学习vue-music音乐内核动画
https://cn.vuejs.org/v2/api/#transition

  • create-keyframe-animation 获取dom的fame,用于实现移动动画,利用Vue.js 之 transition的钩子,可以实现各种复杂的动画.
  • x | 0 代表向下取整
const interval = interval | 0   //代表向下取整
  • 获取拖动等手势 touchstart, touchmove ,touchend

实现方法

    created() {
      this.touch = {}
    },
    methods: {
      progressTouchStart(e) {
        this.touch.initiated = true
      //  e.touches[0] 表示第 0 个手指的位置 
        this.touch.startX = e.touches[0].pageX
        this.touch.left = this.$refs.progress.clientWidth
      },
      progressTouchMove(e) {
        if (!this.touch.initiated) {
          return
        }
        const deltaX = e.touches[0].pageX - this.touch.startX
        const offsetWidth = Math.min(this.$refs.progressBar.clientWidth - progressBtnWidth, Math.max(0, this.touch.left + deltaX))
        this._offset(offsetWidth)
      },
      progressTouchEnd() {
        this.touch.initiated = false
        this._triggerPercent()
      },
      _triggerPercent() {
        const barWidth = this.$refs.progressBar.clientWidth - progressBtnWidth
        const percent = this.$refs.progress.clientWidth / barWidth
        this.$emit('percentChange', percent)
      },
  • 通过点击事件,获取位置

实现方法 e.pageX 获取x位置
getBoundingClientRect()用于获取某个元素相对于视窗的位置集合。集合中有top, right, bottom, left等属性。 参考:http://www.cnblogs.com/Songyc/p/4458570.html

progressClick(e) {
        const rect = this.$refs.progressBar.getBoundingClientRect()
        const offsetWidth = e.pageX - rect.left
        this._offset(offsetWidth)
        // 这里当我们点击 progressBtn 的时候,e.offsetX 获取不对
        // this._offset(e.offsetX)
        this._triggerPercent()
},
  • 圆形进度条的实现 SVG

    参考:http://www.w3school.com.cn/svg/index.asp

  • CSS之stroke: 描边的宽度
  • 洗牌函数:用于把数组的顺序打乱,如:随机播放音乐等

    slice() 方法可从已有的数组中返回选定的元素。http://www.runoob.com/jsref/jsref-slice-array.html

function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1) + min)
}

// 洗牌函数
export function shuffle(arr) {
  let _arr = arr.slice()   // 类似于拷贝一个副本,如不这样做,会改变原来(arr)数组的顺序,发生bug
  for (let i = 0; i < _arr.length; i++) {
    let j = getRandomInt(0, i)
    let t = _arr[i]
    _arr[i] = _arr[j]
    _arr[j] = t
  }
  return _arr
}
  • (ES6) array.findIndex(),用于筛选满足某个条件的item所对应的索引;
let index = list.findIndex((item) => {
  // 筛选出当前歌曲id为this.currentSong.id 的item的索引
   return item.id === this.currentSong.id
})
  • 单曲循环播放原理:当这首歌播放完毕的时候,把他的开始时间重设为0即可
      end() {
        if (this.mode === playMode.loop) {
          //单曲循环播放
          this.loop()
        } else {
          this.next()
        }
      },
      loop() {
        this.$refs.audio.currentTime = 0
        this.$refs.audio.play()
        if (this.currentLyric) {
          this.currentLyric.seek(0)
        }
      },
      next() {
        if (!this.songReady) {
          return
        }
        if (this.playlist.length === 1) {
          this.loop()
        } else {
          let index = this.currentIndex + 1
          if (index === this.playlist.length) {
            index = 0
          }
          this.setCurrentIndex(index)
          if (!this.playing) {
            this.togglePlaying()
          }
        }
        this.songReady = false
      },
  • $el的作用:Vue 实例上的 $el 属性才是 DOM
this.$refs.list.$el.style.top = `${this.imageHeight}px` 
和
this.$refs.layer.style[transform] = `translate3d(0,${translateY}px,0)` 
的区别

我们先看一下标签内容

第一个是一个自定义组件,也就是一个Vue实例.

 ......


第二个是直接是一个标签

也就是说:

一个直接是 DOM,一个是 Vue 的实例,Vue 实例上的 $el 属性才是 DOM。

  • 获取当前的时间戳
+new Date()
  • res.json() : 转换其他的值到json

下面的例子中:res.json(response.data) 把获取到的数据response.data 转化为json赋值给res,是该函数可以在外边调用,获取到json的数据.

apiRoutes.get('/getDiscList', function (req, res) {
  var url = 'https://c.y.qq.com/splcloud/fcgi-bin/fcg_get_diss_by_tag.fcg'
  axios.get(url, {
    headers: {
      referer: 'https://c.y.qq.com/',
      host: 'c.y.qq.com'
    },
    params: req.query
  }).then((response) => {
    res.json(response.data)
  }).catch((e) => {
    console.log(e)
  })
})
  • 如果更改了后端的代码.node 必须重启服务,才能正常显示

下面webpack里面的内容更改,也需要重启服务器.


Vue-music 小知识点_第3张图片
修改了配置的东西,必须重启服务
  • scroll 中下面两个方法参数的传递

详见vue-music-chapter6scroll.vue组件中的注释

scrollTo() {
        // 滚动到某个位置  时间ms  如:({0, 0}, 1000) 滚动到顶部 1000ms
        this.scroll && this.scroll.scrollTo.apply(this.scroll, arguments)
},
scrollToElement() {
        // 要滚动到的元素  时间ms
        this.scroll && this.scroll.scrollToElement.apply(this.scroll, arguments)
}
  • mixin.js 用于写一些方法,合并到调用他的组件的方法中,类似于git提交代码>>合并代码

mixin.js文件中实现下面方法

import {mapGetters} from 'vuex'

export const playlistMixin = {
  computed: {
    ...mapGetters([
      'playlist'
    ])
  },
  mounted() {
    this.handlePlaylist(this.playlist)
  },
  // 导航条切换会触发此事件
  activated() {
    this.handlePlaylist(this.playlist)
  },
  watch: {
    playlist(newVal) {
      this.handlePlaylist(newVal)
    }
  },
  methods: {
    handlePlaylist() {
      throw new Error('component must implement handlePlaylist method')
    }
  }
}

在music-list.vue文件中调用


详细使用请参考vue-music

  • 在子路由界面按F5刷新数据,由于有一些参数是上一级界面传过来的,会导致刷新获取不到数据,此时可以判断从上一个界面的参数存不存在,不存在就返回到上一级界面
methods: {
      _getSongList() {
        if (!this.disc.dissid) {
          this.$router.push('/recommend')
          return
        }
      }
}
  • loading组件,最好用div再包裹一层,如下面:
  • 绝对定位设置居中,如垂直居中设置top: 50% , transform: translateY(-50%),水平居中同理可证;
.list-shortcut
   position: absolute
   z-index: 30
   right: 0
   top: 50%
   transform: translateY(-50%)
  • 设置垂直水平居中,设置top: 50%,left: 50%,transform: translate(-50%, -50%)
position: absolute
top: 50%
left: 50%
transform: translate(-50%, -50%)
z-index: 999
  • this.$watch() 和watch钩子的区别:

created() {
      this.$watch('query', debounce((newQuery) => {
        this.$emit('query', newQuery)
      }, 200))
}
  • 数组的截取 slice()

array.slice(0, 10) // 截取数组的前十个;

  • 父组件如何调用子组件的方法?
    • 子组件search-box.vue组件中,有一个方法setQuery(),想在父组件中调用.
      methods: {
         ......
         setQuery(query) {
           this.query = query
         },
         ......
      }
      
    • 父组件先添加ref属性ref="searchBox",在methods钩子中的addQuery()函数使用this.$refs.searchBox.setQuery()调用; 具体使用如下:
      
      
      methods: {
        addQuery(query) {
          this.$refs.searchBox.setQuery(query)
        }
      }
      
  • 对象的扩展运算符 (...)

扩展运算符(...)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。

let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }

这等同于使用Object.assign方法。

let aClone = { ...a };
// 等同于
let aClone = Object.assign({}, a);

上面的例子只是拷贝了对象实例的属性
... 还有更多功能,请参考:http://es6.ruanyifeng.com/?search=%25E5%25B1%2595%25E5%25BC%2580%25E8%25BF%2590%25E7%25AE%2597%25E7%25AC%25A6&x=0&y=0#docs/object#%E5%AF%B9%E8%B1%A1%E7%9A%84%E6%89%A9%E5%B1%95%E8%BF%90%E7%AE%97%E7%AC%A6

  • javascript 中 push和concat的区别
    在javascript中,我们一般都只用push向数组的尾部插入新元素的,但是其实在javascript中还有另外一个方法和push一样,也是向数组尾部插入新元素的,但是他们之间却存在着一定的区别,当我们看下面的代码的时候就明显的知道了:
  1. 通过使用push操作数组:


    Vue-music 小知识点_第4张图片
    push
  2. 通过使用concat操作数组:
    Vue-music 小知识点_第5张图片
    concat

    从上面的两个操作就很明显的看出来push和concat的区别了
    ①. push 遇到数组参数时,把整个数组参数作为一个元素;而 concat 则是拆开数组参数,一个元素一个元素地加进去。
    ②.push 直接改变当前数组;concat 不改变当前数组。
  • apply()法的使用

请参考:http://www.cnblogs.com/delin/archive/2010/06/17/1759695.html

  • 搜索页面:输入框快速输入(删除)内容 会导致频繁请求数据, 故做截留处理 debounce():自己封装的函数

请参考:search-box.vue 组件

  • 让输入框失去焦点blur()

js调用,让键盘下去,让输入框失去焦点

可以在scroll滚动,或者点击方法中调用
this.$refs.query.blur()  // 让移动端输入框失去焦点
  • localStorage 和 sessionStorage 的区别
    • localStorage - 没有时间限制的数据存储。
    • sessionStorage - 针对一个 session 的数据存储(关闭窗口,存储的数据清空) 。
      将数据存到 session中,管你前进后退还是刷新,数据依然在,关闭窗口后再进页面才会清空数据。
  • array.findIndex()

语法: array.findIndex(function())
function() 一般是比较条件

var ages = [3, 10, 18, 20];
 
function checkAdult(age) {
    return age >= 18;
}
 
function myFunction() {
    document.getElementById("demo").innerHTML = ages.findIndex(checkAdult);
}

或者

let index = list.findIndex((item) => {
   return item.id === this.currentSong.id
})
  • better-scroll 使用注意:

下面的写法,scroll的高度获取只能是第一个div的高度,这样是不对的!!!


   
正确的写法:需要用容器包括下

  

div1和div2里面放的不同的数据数组,如果想让内容撑开scroll,在计算属性中, 把连个div的数据数组concat在一起,然后给scroll的:data属性赋值即可!
为什么要用计算属性呢? 因为在计算属性中,如果两个div的数据数组有一个发生改变,那么计算属性就会重新计算.故保证了数据的正确性!

  • 阻止事件冒泡

下面的代码,当我们点击wrapper里面的任意一个div时,div的事件都会冒泡到最外面的wrapper上面,从而触发wrapper的点击事件儿.

此时要想阻止里面的div事件冒泡到最外层的wrapper上,可以给div添加@click.stop阻止事件冒泡即可!

  • 的区别?
 元素作为单个元素/组件的过渡效果。
 只会把过渡效果应用到其包裹的内容上,而不会额外渲染 DOM 元素,也不会出现在检测过的组件层级中。

 元素作为多个元素/组件的过渡效果。
 渲染一个真实的 DOM 元素。默认渲染 ,可以通过 tag 属性配置哪个元素应该被渲染。

transition-group的使用注意事项:

①.需指定tag,如:tag="ul";
②.子元素需设置 :key, 如:

  • 
       
          
  • ......
  • 详见官方文档

    • scroll里面有动画时,scroll的refresh()应延时,比如transition-group的动画时间是0.1s,那么scroll的refresh()最少延时120ms,才能正确计算高度

    :refreshDelay="120" 延时120ms,为什么呢?
    因为:transition-group动画时长是100ms, 当从添加歌曲到队列中时,一般情况下,20ms就会执行scroll.refresh()操作,此时动画还没有执行完,会导致scroll的高度计算不对,故 应在动画结束之后再执行refresh()操作,所以延时120ms执行refresh()。

    
        
            
    • js如何查询某个对象是否在这个数组中?
    isFavorite(song) {
          const index = this.favoriteList.findIndex((item) => {
            return item.id === song.id
          })
          return index > -1  // 如果大于-1, 说明存在
    }
    
    • 打出的包比较大,可以使用路由懒加载优化下 : 这样首屏加载的资源就会很少,提交加载速度!!!!

    https://router.vuejs.org/zh-cn/advanced/lazy-loading.html

    • 在对Vue.js进行版本升级时,vuevue-template-compiler的版本号必须一致,否则编译报错!!!
    "dependencies": {
        "vuex": "^2.3.1",  // 必须一致
         ......
      },
    "devDependencies": {
        "vue-template-compiler": "^2.3.3", // 必须一致
    }
    
    • vConsole 一个轻量、可拓展、针对手机网页的前端开发者调试面板。

    main.js中调用 ,然后console.log的内容在手机上就可以查看了.

    在上线的时候,把import vConsole from 'vconsole'注释掉就可以了

    // 规避Eslint语法检查, vue中,如果之引入,不调用的话,会报错
    /* eslint-disable no-unused-vars */
    import vConsole from 'vconsole'    
    

    你可能感兴趣的:(Vue-music 小知识点)