国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Vue 實(shí)現(xiàn)的音樂(lè)項(xiàng)目 music app 知識(shí)點(diǎn)總結(jié)分享

meteor199 / 1455人閱讀

摘要:后兩個(gè)屬性可選。屬性定義了項(xiàng)目的縮小比例,默認(rèn)為,即如果空間不足,該項(xiàng)目將縮小。屬性定義了在分配多余空間之前,項(xiàng)目占據(jù)的主軸空間。它的默認(rèn)值為,即項(xiàng)目的本來(lái)大小。結(jié)合的異步組件和的代碼分割功能,輕松實(shí)現(xiàn)路由組件的懶加載。

項(xiàng)目總結(jié)

這是我第二個(gè)用 Vue 實(shí)現(xiàn)的項(xiàng)目,下面內(nèi)容包括了在實(shí)現(xiàn)過(guò)程中所記錄的知識(shí)點(diǎn)以及一些小技巧

項(xiàng)目演示地址:https://music-vue.n-y.io
源代碼地址:https://github.com/nanyang24/...

其他

此應(yīng)用的全部數(shù)據(jù)來(lái)自 QQ音樂(lè),利用 axios 結(jié)合 node.js 代理后端請(qǐng)求抓取

全局通用的應(yīng)用級(jí)狀態(tài)使用 vuex 集中管理

全局引入 fastclick 庫(kù),消除 click 移動(dòng)瀏覽器 300ms 延遲

頁(yè)面是響應(yīng)式的,適配常見(jiàn)的移動(dòng)端屏幕,采用 flex 布局

疑難總結(jié) & 小技巧 關(guān)于 Vue 知識(shí) & 使用技巧 v-html 可以轉(zhuǎn)義字符,處理特定接口很有用 watch 對(duì)象可以觀測(cè) 屬性 的變化 像這種父組件傳達(dá)子組件的參數(shù)通常都是在data()里面定義的,為什么這里要放到created()定義,兩者有什么區(qū)別呢?

因?yàn)檫@個(gè)變量不需要觀測(cè)它的變化,因此不用定義在 data 里,這樣也會(huì)對(duì)性能有所優(yōu)化

不明白什么時(shí)候要把變量放在data()里,什么時(shí)候又不需要放 ?

需要監(jiān)測(cè)這個(gè)數(shù)據(jù)變化的時(shí)候,放在 data() 里,會(huì)給數(shù)據(jù)添加 getter 和 setter

生命周期 鉤子函數(shù)

生命周期鉤子函數(shù),比如 mounted 是先觸發(fā)子組件的 mounted,再會(huì)觸發(fā)父組件的 mounted,但是對(duì)于 created 鉤子,又會(huì)先觸發(fā)父組件,再觸發(fā)子組件。

銷毀計(jì)數(shù)器

如果組件有計(jì)數(shù)器,在組件銷毀時(shí)期要記得清理,好習(xí)慣

對(duì)于 Vue 組件,this.$refs.xxx 拿到的是 Vue 實(shí)例,所以需要再通過(guò) $el 拿到真實(shí)的 dom 關(guān)于 JS 知識(shí) & 技巧 setTimeout(fn, 20)

一般來(lái)說(shuō) JS 線程執(zhí)行完畢后一個(gè) Tick 的時(shí)間約17ms內(nèi) DOM 就可以渲染完畢所以課程中 setTimeout(fn, 20) 是非常穩(wěn)妥的寫法

關(guān)于 webpack 知識(shí) & 技巧 " ~ " 使 SCSS 可以使用 webpack 的相對(duì)路徑
@import "~common/scss/mixin";
@import "~common/scss/variable";
babel-runtime 會(huì)在編譯階段把 es6 語(yǔ)法編譯的代碼打包到業(yè)務(wù)代碼中,所以要放在dependencies里。 Fast Click 是一個(gè)簡(jiǎn)單、易用的庫(kù),專為消除移動(dòng)端瀏覽器從物理觸摸到觸發(fā)點(diǎn)擊事件之間的300ms延時(shí) 為什么會(huì)存在延遲呢?

從觸摸按鈕到觸發(fā)點(diǎn)擊事件,移動(dòng)端瀏覽器會(huì)等待接近300ms,原因是瀏覽器會(huì)等待以確定你是否執(zhí)行雙擊事件

何時(shí)不需要使用

FastClick 不會(huì)伴隨監(jiān)聽(tīng)任何桌面瀏覽器

Android 系統(tǒng)中,在頭部 meta 中設(shè)置 width=device-width 的Chrome32+ 瀏覽器不存在300ms 延時(shí),所以,也不需要

同樣的情況也適用于 Android設(shè)備(任何版本),在viewport 中設(shè)置 user-scalable=no,但這樣就禁止縮放網(wǎng)頁(yè)了

IE11+ 瀏覽器中,你可以使用 touch-action: manipulation; 禁止通過(guò)雙擊來(lái)放大一些元素(比如:鏈接和按鈕)。IE10可以使用 -ms-touch-action: manipulation

請(qǐng)求接口

jsonp:

XHR:

手寫輪播圖

利用 BScroll

BScroll 設(shè)置 loop 會(huì)自動(dòng) clone 兩個(gè)輪播插在前后位置

如果輪播循環(huán)播放,是前后各加一個(gè)輪播圖保證無(wú)縫切換,所以需要再加兩個(gè)寬度

if (this.loop) {
  width += 2 * sliderWidth
}

初始化 dots 要在 BScroll 克隆插入兩個(gè)輪播圖之前

dots active狀態(tài) 是通過(guò)判斷 currentIndex 與 index 是否相等

currentIndex 更新是通過(guò)獲取 scroll 當(dāng)前 page,BScroll 提供了 api 方便調(diào)用

this.currentPageIndex = this.scroll.getCurrentPage().pageX

為了保證改變窗口大小依然正常輪播,監(jiān)聽(tīng)窗口 resize 事件,重新渲染輪播圖

window.addEventListener("resize", () => {
  if (!this.scroll || !this.scroll.enabled) return

  clearTimeout(this.resizeTimer)
  this.resizeTimer = setTimeout(() => {
    if (this.scroll.isInTransition) {
      this._onScrollEnd()
    } else {
      if (this.autoPlay) {
        this._play()
      }
    }
    this.refresh()
  }, 60)
})

在切換 tab 相當(dāng)于 切換了 keep-alive 的組件
輪播會(huì)出問(wèn)題,需要手動(dòng)幫助執(zhí)行,利用了 activated , deactivated 鉤子函數(shù)

activated() {
  this.scroll.enable()
  let pageIndex = this.scroll.getCurrentPage().pageX
  this.scroll.goToPage(pageIndex, 0, 0)
  this.currentPageIndex = pageIndex
  if (this.autoPlay) {
    this._play()
  }
},
deactivated() {
  this.scroll.disable()
  clearTimeout(this.timer)
}

實(shí)測(cè),首次打開(kāi)網(wǎng)頁(yè)并不會(huì)執(zhí)行 activated,只有在之后切換 tab ,切回來(lái)才會(huì)執(zhí)行

在組件銷毀之前 beforeDestroy 銷毀定時(shí)器是好習(xí)慣,keep-alive 因?yàn)槭菍⒔M件緩存了,所以不會(huì)觸發(fā)

beforeDestroy() {
  this.scroll.disable()
  clearTimeout(this.timer)
}
后端接口代理

簡(jiǎn)單設(shè)置一下 Referer, Host,讓別人直接通過(guò)瀏覽器抓到你的接口
但是這種方式防不了后端代理的方式

前端 XHR 會(huì)有跨域限制,后端發(fā)送 http 請(qǐng)求則沒(méi)有限制,因此可以偽造請(qǐng)求

axios 可以在瀏覽器端發(fā)送 XMLHttpRequest 請(qǐng)求,在服務(wù)器端發(fā)送 http 請(qǐng)求

(在項(xiàng)目編寫階段,可以將后端代理請(qǐng)求寫在 webpack 的 dev 文件的 before 函數(shù)內(nèi))

before(app) {
  app.get("/api/getDiscList", function (req, res) {
    const 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) // axios 返回的數(shù)據(jù)在 response.data,要把數(shù)據(jù)透?jìng)鞯轿覀冏远x的接口里面 res.json(response.data)
    }).catch((e) => {
      console.log(e)
    })
  });
}

定義一個(gè)路由,get 到一個(gè) /api/getDiscList 接口,通過(guò) axios 偽造 headers,發(fā)送給QQ音樂(lè)服務(wù)器一個(gè) http 請(qǐng)求,還有 param 參數(shù)。
得到服務(wù)端正確的響應(yīng),通過(guò) res.json(response.data) 返回到瀏覽器端

另外 因?yàn)槭?http 請(qǐng)求數(shù)據(jù),是ajax,所以 format 參數(shù)要將原本接口的 jsonp 改為 json

大公司怎么防止被惡意代理呢?當(dāng)你的訪問(wèn)量大的時(shí)候,出口ip會(huì)被查到獲取封禁,還有一種就是參數(shù)驗(yàn)簽,也就是請(qǐng)求人家的數(shù)據(jù)必須帶一個(gè)簽名參數(shù),然后這個(gè)簽名參數(shù)是很難拿到的這個(gè)正確的簽名,從而達(dá)到保護(hù)數(shù)據(jù)的目的

當(dāng)然,獲取的數(shù)據(jù)并不能直接拿來(lái)用,需要做進(jìn)一步的規(guī)格化,達(dá)到我們使用的要求,所以在這方面多帶帶封裝了一個(gè) class 來(lái)處理這方面的數(shù)據(jù),具體請(qǐng)看src/common/js/song.js

flex 布局,熱門歌單推薦

左側(cè) icon 固定大小,flex: 0 0 60px

flex 屬性是 flex-grow , flex-shrinkflex-basis 的簡(jiǎn)寫,默認(rèn)值為 0 1 auto。后兩個(gè)屬性可選。

flex-grow 屬性定義項(xiàng)目的放大比例,默認(rèn)為 0,即如果存在剩余空間,也不放大。

flex-shrink 屬性定義了項(xiàng)目的縮小比例,默認(rèn)為 1,即如果空間不足,該項(xiàng)目將縮小。

flex-basis 屬性定義了在分配多余空間之前,項(xiàng)目占據(jù)的主軸空間(main size)。瀏覽器根據(jù)這個(gè)屬性,計(jì)算主軸是否有多余空間。它的默認(rèn)值為auto,即項(xiàng)目的本來(lái)大小。

右側(cè) text 區(qū)塊 自適應(yīng)占據(jù)剩下的空間,并且內(nèi)部也采用 flex,使用 flex-direction: column; justify-content: center; 來(lái)達(dá)到縱向居中排列

recommend 頁(yè)面 利用 BScroll 滾動(dòng)

Scroll 初始化但卻沒(méi)有滾動(dòng),是因?yàn)槌跏蓟瘯r(shí)機(jī)不對(duì),必須保證數(shù)據(jù)到來(lái),DOM 成功渲染之后 再去進(jìn)行初始化
可以使用父組件 給 Scrol組件傳 :data 數(shù)據(jù),Scroll 組件自己 watch 這個(gè) data,有變化就立刻 refesh 滾動(dòng)

新版本 BScroll 已經(jīng)自己實(shí)現(xiàn)檢測(cè) DOM 變化,自動(dòng)刷新,大部分場(chǎng)景下無(wú)需傳 data 了

所以也就 無(wú)需監(jiān)聽(tīng) img 的 onload 事件 然后執(zhí)行 滾動(dòng)刷新 了

    
  
  
修復(fù)進(jìn)度條的 BUG

迷你播放器暫停狀態(tài),進(jìn)入全屏,按鈕在進(jìn)度條最左邊

原因:當(dāng)播放器最小化的時(shí)候,progress-bar 仍然在監(jiān)聽(tīng) percent 的變化,所以在不斷計(jì)算進(jìn)度條的位置,然而這個(gè)時(shí)候由于播放器隱藏,進(jìn)度條的寬度 this.$refs.progressBar.clientWidth 計(jì)算為0,因此計(jì)算出來(lái)的 offset 也是不對(duì)的,導(dǎo)致再次最大化播放器的時(shí)候,由于播放器是暫停狀態(tài), percent 并不會(huì)變化,也不會(huì)重新計(jì)算這個(gè) offset ,導(dǎo)致 Bug。

解決方案:當(dāng)播放器最大化的時(shí)候,手動(dòng)去計(jì)算一次 offset,確保進(jìn)度條的位置正確。

progress-bar 組件要 watch 下 fullScreen,在進(jìn)入全屏的時(shí)候調(diào)用一下 移動(dòng)按鈕函數(shù)

歌詞 lyric

獲取歌詞,雖然我們約定返回?cái)?shù)據(jù)是 json,但QQ音樂(lè) 返回的是依然是 jsonp,所以我們需要做一層數(shù)據(jù)的處理

const reg = /^w+(({.+}))$/
就是將返回的jsonp格式摘取出我們需要的json字段

ret = JSON.parse(matches[1])
將正則分組(就是正則括號(hào)內(nèi)的內(nèi)容)捕獲的json字符串?dāng)?shù)據(jù) 轉(zhuǎn)成 json 格式

然后我們?cè)?player 組件中監(jiān)聽(tīng) currentSong 的變化,獲取 this.currentSong.getLyric()

axios.get(url, {
  headers: {
    referer: "https://c.y.qq.com/",
    host: "c.y.qq.com"
  },
  params: req.query
}).then((response) => {
  let ret = response.data
  if (typeof ret === "string") {
    const reg = /^w+(({.+}))$/
    const matches = ret.match(reg)
    if (matches) {
      ret = JSON.parse(matches[1])
    }
  }
  res.json(ret)
})

然后我們得到的返回?cái)?shù)據(jù)的是 base64 的字符串,需要解碼,這里用到了第三方庫(kù): js-base64
(我們這次用的是QQ音樂(lè)pc版的歌詞,需要解碼base64,而移動(dòng)版的QQ音樂(lè)是不需要的)

this.lyric = Base64.decode(res.lyric)

之后利用第三方庫(kù): js-lyric ,解析我們的歌詞,生成方便操作的對(duì)象

getLyric() {
  this.currentSong.getLyric()
    .then(lyric => {
      this.currentLyric = new Lyric(lyric)
    })
}
歌詞滾動(dòng)

當(dāng)前歌曲的歌詞高亮是利用 js-lyric 會(huì)派發(fā)的 handle 事件

 this.currentLyric = new Lyric(lyric, this.handleLyric)

js-lyric 會(huì)在每次改變當(dāng)前歌詞時(shí)觸發(fā)這個(gè)函數(shù),函數(shù)的參數(shù)為 當(dāng)前的 lineNum 和 txt

而 使當(dāng)前高亮歌詞保持最中間 是利用了 BScroll 滾動(dòng)至高亮的歌詞
let middleLine = isIphoneX() ? 7 : 5  // 鑒于iphonex太長(zhǎng)了,做個(gè)小優(yōu)化
if (lineNum > middleLine) {
  let lineEl = this.$refs.lyricLine[lineNum - middleLine]
  this.$refs.lyricList.scrollToElement(lineEl, 1000)
} else {
  this.$refs.lyricList.scrollTo(0, 0, 1000)
}
cd 與 歌詞 之間滑動(dòng)

通過(guò)監(jiān)聽(tīng) middle 的 三個(gè) touch 事件

offsetWidth 是為了計(jì)算歌詞列表的一個(gè)偏移量的,首先它的偏移量不能大于0,也不能小于 -window.innerWidth
left 是根據(jù)當(dāng)前顯示的是 cd 還是歌詞列表初始化的位置,如果是 cd,那么 left 為 0 ,歌詞是從右往左拖的,deltaX 是小于 0 的,所以最終它的偏移量就是 0+deltaX;如果已經(jīng)顯示歌詞了,那么 left 為 -window.innerWidth,歌詞是從左往右拖,deltaX 是大于 0 的,所以最終它的偏移量就是 -window.innerWidth + deltaX

middleTouchStart(e) {
  this.touch.initiated = true
  this.touch.startX = e.touches[0].pageX
  this.touch.startY = e.touches[0].pageY
},
middleTouchMove(e) {
  if (!this.touch.initiated) return
  const deltaX = e.touches[0].pageX - this.touch.startX
  const deltaY = e.touches[0].pageY - this.touch.startY
  if (Math.abs(deltaY) > Math.abs(deltaX)) {
    return
  }
  const left = this.currentShow === "cd" ? 0 : -window.innerWidth
  const offsetWidth = Math.min(0, Math.max(-window.innerWidth, left + deltaX))
  this.touch.percent = Math.abs(offsetWidth / window.innerWidth)
  console.log(this.touch.percent)
  this.$refs.lyricList.$el.style[transform] = `translate3d(${offsetWidth}px,0,0)`
  this.$refs.lyricList.$el.style[transitionDuration] = 0
  this.$refs.middleL.style.opacity = 1 - this.touch.percent
  this.$refs.middleL.style[transitionDuration] = 0
},
middleTouchEnd() {
  let offsetWidth, opacity
  // 從右向左滑 的情況
  if (this.currentShow === "cd") {
    if (this.touch.percent > 0.1) {
      offsetWidth = -window.innerWidth
      opacity = 0
      this.currentShow = "lyric"
    } else {
      offsetWidth = 0
      opacity = 1
    }
  } else {
    //  從左向右滑 的情況
    if (this.touch.percent < 0.9) {
      offsetWidth = 0
      opacity = 1
      this.currentShow = "cd"
    } else {
      offsetWidth = -window.innerWidth
      opacity = 0
    }
  }
  const durationTime = 300
  this.$refs.lyricList.$el.style[transform] = `translate3d(${offsetWidth}px,0,0)`
  this.$refs.lyricList.$el.style[transitionDuration] = `${durationTime}ms`
  this.$refs.middleL.style.opacity = opacity
  this.$refs.middleL.style[transitionDuration] = `${durationTime}ms`
}
優(yōu)化

Vue 按需加載路由:

當(dāng)打包構(gòu)建應(yīng)用時(shí),Javascript 包會(huì)變得非常大,影響頁(yè)面加載。如果我們能把不同路由對(duì)應(yīng)的組件分割成不同的代碼塊,然后當(dāng)路由被訪問(wèn)的時(shí)候才加載對(duì)應(yīng)組件,這樣就更加高效了。

結(jié)合 Vue 的異步組件Webpack 的代碼分割功能,輕松實(shí)現(xiàn)路由組件的懶加載。

首先,可以將異步組件定義為返回一個(gè) Promise 的工廠函數(shù) (該函數(shù)返回的 Promise 應(yīng)該 resolve 組件本身):

const Foo = () => Promise.resolve({ /* 組件定義對(duì)象 */ })

第二,在 Webpack 2 中,我們可以使用動(dòng)態(tài) import語(yǔ)法來(lái)定義代碼分塊點(diǎn) (split point):

import("./Foo.vue") // 返回 Promise

在我們的項(xiàng)目中的 router/index.js 是這樣定義的:

// Vue 異步加載路由
// 引入5個(gè) 一級(jí)路由組件
const Recommend = () => import("components/recommend/recommend")
const Singer = () => import("components/singer/singer")
const Rank = () => import("components/rank/rank")
const Search = () => import("components/search/search")
const UserCenter = () => import("components/user-center/user-center")
// 二級(jí)路由組件
const SingerDetail = () => import("components/singer-detail/singer-detail")
const Disc = () => import("components/disc/disc")
const TopList = () => import("components/top-list/top-list")

無(wú)需改動(dòng)其他的代碼

手機(jī)聯(lián)調(diào)

電腦,手機(jī) 同一WIFI下

配置 config 的 index.js 里的 host 為 "0.0.0.0",手機(jī)可以打開(kāi)電腦的IP地址+端口查看

mac下 ifconfig 查看ip

移動(dòng)端調(diào)試工具

移動(dòng)端console:vConsole
移動(dòng)端抓包工具:charles

結(jié)語(yǔ)

以上是在實(shí)現(xiàn)這個(gè)音樂(lè) Vue 項(xiàng)目中遇到的難點(diǎn)以及一些使用技巧。在這里記錄下來(lái)方便以后自己查閱,還能夠給同樣在前端這個(gè)小領(lǐng)域奮斗的大家提供一小些學(xué)習(xí)資料~

我的 Github:https://github.com/nanyang24
如果對(duì)你有幫助,歡迎 star 和 互粉 ~

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/107496.html

相關(guān)文章

  • 讓工作與音樂(lè)Vue)相伴

    摘要:前言最近在自學(xué)打算自己仿一個(gè)項(xiàng)目來(lái)實(shí)戰(zhàn)一下,由于本人很喜歡聽(tīng)歌,所以就選擇了網(wǎng)易云音樂(lè),在這與大家分享一下自己所遇到的問(wèn)題,其中也有些不足之處也希望大家提一些寶貴的意見(jiàn),互相學(xué)習(xí),一起進(jìn)步。 showImg(https://segmentfault.com/img/remote/1460000015805758); 前言 最近在自學(xué)vue,打算自己仿一個(gè)項(xiàng)目來(lái)實(shí)戰(zhàn)一下,由于本人很喜歡聽(tīng)...

    jemygraw 評(píng)論0 收藏0
  • ?基于H5+js開(kāi)發(fā)一款音樂(lè)播放器

    前言:當(dāng)下音樂(lè)播放器不勝其數(shù),為了更好的掌握一些東西,我們來(lái)自己制作一個(gè)音樂(lè)播放器。 文章目錄: 一.開(kāi)發(fā)環(huán)境:二.頁(yè)面視圖:1.主文件入口(首頁(yè)):2.音樂(lè)播放界面: 三.功能實(shí)現(xiàn)(1)、index.html:(2)、播放音樂(lè)(music.html):(3)、樣式文件(index.css): 四.項(xiàng)目地址: 一.開(kāi)發(fā)環(huán)境: 開(kāi)發(fā)工具:HbuliderX; 框架:Vant,Mui,V...

    BearyChat 評(píng)論0 收藏0
  • vue-music(1)音樂(lè)播發(fā)器 項(xiàng)目開(kāi)發(fā)記錄

    摘要:在中新建組件許文瑞正在吃屎。。。。在中添加如下代碼三歌手組件開(kāi)發(fā)歌手首頁(yè)開(kāi)發(fā)數(shù)據(jù)獲取數(shù)據(jù)獲取依舊從音樂(lè)官網(wǎng)獲取歌手接口創(chuàng)建我們和以前一樣,利用我們封裝的等發(fā)放,來(lái)請(qǐng)求我們的接口,返回給。 Vue-Music 跟學(xué)一個(gè)網(wǎng)課老師做的仿原生音樂(lè)APP跟學(xué)的筆記,記錄點(diǎn)滴,也希望對(duì)學(xué)習(xí)vue初學(xué)小伙伴有點(diǎn)幫助 showImg(https://segmentfault.com/img/remot...

    happen 評(píng)論0 收藏0
  • 給自己網(wǎng)站添加網(wǎng)易云音樂(lè)歌單吧^ ^

    摘要:每次用網(wǎng)易云音樂(lè)客戶端播放聽(tīng)歌的時(shí)候,收藏的歌曲,在我的博客上也可以同步進(jìn)行更新。 最近應(yīng)該發(fā)現(xiàn),我的博客https://blog.codelabo.cn左下角多了一個(gè)音樂(lè)播放器 showImg(https://segmentfault.com/img/remote/1460000016786096?w=1806&h=952); 這個(gè)是怎么實(shí)現(xiàn)的?一起來(lái)看看吧 APlayer 首先我們...

    RaoMeng 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<