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

資訊專(zhuān)欄INFORMATION COLUMN

基于vue的移動(dòng)端web音樂(lè)播放器

chemzqm / 1174人閱讀

摘要:代碼實(shí)現(xiàn)得到合適的瀏覽器前綴對(duì)外暴露的方法使用案例導(dǎo)入該模塊加了合適前綴的屬性使用該屬性移動(dòng)端的事件隨著觸屏設(shè)備的普及,為移動(dòng)端新增了事件。如果用戶(hù)的手指從觸屏設(shè)備的邊緣移出了觸屏設(shè)備,也會(huì)觸發(fā)事件。

聲明

以下只是學(xué)習(xí)完慕課網(wǎng)huangyi老師實(shí)戰(zhàn)視頻課程的筆記內(nèi)容,僅供個(gè)人參考學(xué)習(xí)使用。
如果對(duì)Vue2.0實(shí)戰(zhàn)高級(jí)-開(kāi)發(fā)移動(dòng)端音樂(lè)WebApp感興趣的話,請(qǐng)移步這里:
https://coding.imooc.com/clas...
謝謝。

項(xiàng)目GitHub地址: https://github.com/bjw1234/vu...

項(xiàng)目演示地址: http://music.baijiawei.top

項(xiàng)目初始化

</>復(fù)制代碼

  1. // 安裝vue腳手架工具
  2. npm install vue-cli -g
  3. // 初始化webpack應(yīng)用
  4. vue init webpack vue-music
項(xiàng)目中使用到的mixin

</>復(fù)制代碼

  1. // 背景圖片
  2. bg-image($url)
  3. background-image: url($url + "@2x.png")
  4. @media (-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio: 3)
  5. background-image: url($url + "@3x.png")
  6. // 不換行
  7. no-wrap()
  8. text-overflow: ellipsis
  9. overflow: hidden
  10. white-space: nowrap
  11. // 擴(kuò)展點(diǎn)擊區(qū)域
  12. extend-click()
  13. position: relative
  14. &:before
  15. content: ""
  16. position: absolute
  17. top: -10px
  18. left: -10px
  19. right: -10px
  20. bottom: -10px
配置路徑別名

</>復(fù)制代碼

  1. resolve: {
  2. extensions: [".js", ".vue", ".json"],
  3. alias: {
  4. "@": resolve("src"),
  5. "common": resolve("src/common")
  6. }
  7. }
移動(dòng)端300毫秒延時(shí)和點(diǎn)透問(wèn)題

fastclick:處理移動(dòng)端click事件300毫秒延遲和點(diǎn)透問(wèn)題。

先執(zhí)行安裝fastclick的命令。

</>復(fù)制代碼

  1. npm install fastclick --save

之后,在main.js中引入,并綁定到body

</>復(fù)制代碼

  1. import FastClick from "fastclick";
  2. FastClick.attach(document.body);

注意: 當(dāng)fastclick和其他的模塊點(diǎn)擊沖突,導(dǎo)致點(diǎn)擊事件不可用時(shí),可以給對(duì)應(yīng)的dom添加needsclick類(lèi)來(lái)解決。

對(duì)jsonp進(jìn)一步封裝

下載原始的jsonp模塊:

</>復(fù)制代碼

  1. npm install jsonp --save

再次封裝:

</>復(fù)制代碼

  1. import originJSONP from "jsonp";
  2. /**
  3. * 做一個(gè)簡(jiǎn)單的jsonp封裝
  4. * @param url
  5. * @param data
  6. * @param option
  7. * @return {Promise}
  8. */
  9. export default function jsonp (url, data, option) {
  10. return new Promise((resolve, reject) => {
  11. url = `${url}?${_obj2String(data)}`;
  12. originJSONP(url, option, (err, data) => {
  13. if (!err) {
  14. resolve(data);
  15. } else {
  16. reject(err);
  17. }
  18. });
  19. });
  20. };
  21. function _obj2String (obj, arr = [], index = 0) {
  22. for (let item in obj) {
  23. arr[index++] = [item, obj[item]];
  24. }
  25. return new URLSearchParams(arr).toString();
  26. }
vue的生命周期函數(shù)

注意: 當(dāng)使用keep-alive組件時(shí),當(dāng)切換到其他路由,會(huì)調(diào)用前組件的deactivated鉤子函數(shù),當(dāng)切回來(lái)時(shí),會(huì)調(diào)用activated函數(shù)。

better-scroll組件的使用

注意:

1.better-scroll只處理容器的第一個(gè)子元素的滾動(dòng)。

2.一定得保證子元素超出父元素,這樣才能正確的滾動(dòng)。

初始化:

</>復(fù)制代碼

  1. import BScroll from "better-scroll";
  2. let wrapper = document.querySelector(".wrapper");
  3. let scroll = new BScroll(wrapper,{
  4. // 配置項(xiàng)
  5. });

</>復(fù)制代碼

  1. .wrapper
  2. position: fixed
  3. width: 100%
  4. top: 88px
  5. bottom: 0
  6. .scroll
  7. height: 100%
  8. overflow: hidden

問(wèn)題排查(無(wú)法滾動(dòng)原因:)

1.內(nèi)層容器的高度沒(méi)有超過(guò)外層容器。

2.dom沒(méi)有渲染完畢就初始化better-scroll

3.改變了dom的顯隱性,沒(méi)有對(duì)scroll進(jìn)行重新計(jì)算。

針對(duì)3:當(dāng)dom顯示出來(lái)之后,加20毫秒延時(shí),然后調(diào)用refresh方法。

開(kāi)發(fā)模式下的請(qǐng)求代理

當(dāng)在開(kāi)發(fā)模式下,需要使用一些后臺(tái)接口,為了防止跨域問(wèn)題,vue-cli提供了非常強(qiáng)大的http-proxy-middleware包。可以對(duì)我們的請(qǐng)求進(jìn)行代理。
進(jìn)入 config/index.js 代碼下如下配置即可:

</>復(fù)制代碼

  1. proxyTable: {
  2. "/getDescList": {
  3. target: "http://127.0.0.1:7070/desclist", // 后端接口地址
  4. changeOrigin: true,
  5. // secure: false,
  6. pathRewrite: {
  7. "^/getDescList": "/"
  8. }
  9. }
  10. }
負(fù)外邊距的作用效果

marin-left或者margin-top是負(fù)值:它會(huì)將元素在相應(yīng)的方向進(jìn)行移動(dòng)。left就是左右方向移動(dòng),top就是上下方向移動(dòng)。也就是會(huì)使元素在文檔流里的位置發(fā)生變化

margin-right或者margin-bottom是負(fù)值:它不會(huì)移動(dòng)該元素(該元素不變化),但會(huì)使該元素后面的元素往前移動(dòng)。也就是說(shuō),如果margin-bottom為負(fù)值,那么該元素下面的元素會(huì)往上移動(dòng);如果margin-right為負(fù)值,那么該元素右邊的元素會(huì)往左移動(dòng),從而覆蓋該元素。

配置子路由

需求:在歌手頁(yè)面下需要一個(gè)歌手詳情頁(yè)。

</>復(fù)制代碼

  1. export default new Router({
  2. routes:[
  3. {
  4. path: "/",
  5. component: Singer,
  6. children: [
  7. {
  8. path: ":id",
  9. compoonent: SingerDetail
  10. }
  11. ]
  12. },
  13. ...
  14. ]
  15. });

當(dāng)監(jiān)聽(tīng)到用戶(hù)點(diǎn)擊之后進(jìn)行路由跳轉(zhuǎn):

</>復(fù)制代碼

  1. this.$router.push({
  2. path: `singer/${singer.id}`
  3. });
  4. // 別忘了在`Singer`頁(yè)面中:
Vuex的使用 Vuex是什么?

簡(jiǎn)單來(lái)說(shuō):Vuex解決項(xiàng)目中多個(gè)組件之間的數(shù)據(jù)通信和狀態(tài)管理。

Vuex將狀態(tài)管理多帶帶拎出來(lái),應(yīng)用統(tǒng)一的方式進(jìn)行處理,采用單向數(shù)據(jù)流的方式來(lái)管理數(shù)據(jù)。用處負(fù)責(zé)觸發(fā)動(dòng)作(Action)進(jìn)而改變對(duì)應(yīng)狀態(tài)(State),從而反映到視圖(View)上。

Vuex怎么用?

安裝:

</>復(fù)制代碼

  1. npm install vuex --save

引入:

</>復(fù)制代碼

  1. import Vuex from "vuex";
  2. import Vue from "Vue";
  3. Vue.use(Vuex);

Vuex的組成部分

使用Vuex開(kāi)發(fā)的應(yīng)用結(jié)構(gòu)應(yīng)該是這樣的:

State

State負(fù)責(zé)存儲(chǔ)整個(gè)應(yīng)用的狀態(tài)數(shù)據(jù),一般需要在使用的時(shí)候在根節(jié)點(diǎn)注入store對(duì)象,后期就可以使用this.$store.state直接獲取狀態(tài)。

</>復(fù)制代碼

  1. import store from "./store";
  2. ..
  3. new Vue({
  4. el: "#app",
  5. store,
  6. render: h => h(App)
  7. });

那么這個(gè)store又是什么?從哪來(lái)的呢?

store可以理解為一個(gè)容器,包含應(yīng)用中的state。實(shí)例化生成store的過(guò)程是:

</>復(fù)制代碼

  1. const mutations = {...};
  2. const actions = {...};
  3. const state = {...};
  4. // 實(shí)例化store對(duì)象并導(dǎo)出
  5. export defautl new Vuex.Store({
  6. state,
  7. actions,
  8. mutations
  9. });

Mutations

中文意思是“變化”,利用它可以來(lái)更改狀態(tài),本質(zhì)上就是用來(lái)處理數(shù)據(jù)的函數(shù)。
store.commit(mutationName)是用來(lái)觸發(fā)一個(gè)mutation的方法。
需要記住的是,定義的mutation必須是同步函數(shù)。

</>復(fù)制代碼

  1. const mutations = {
  2. changState(state) {
  3. // 在這里改變state中的數(shù)據(jù)
  4. }
  5. };
  6. // 可以在組件中這樣觸發(fā)
  7. this.$store.commit("changeState");

Actions

Actions也可以用于改變狀態(tài),不過(guò)是通過(guò)觸發(fā)mutation實(shí)現(xiàn)的,重要的是可以包含異步操作。

直接觸發(fā)可以使用this.$store.dispatch(actionName)方法。

簡(jiǎn)單的多組件數(shù)據(jù)交互

</>復(fù)制代碼

  1. import Vue from "vue";
  2. import Vuex from "vuex";
  3. Vue.use(Vuex);
  4. // 狀態(tài)
  5. const state = {
  6. singer: {}
  7. };
  8. // 跟蹤狀態(tài)的變化
  9. const mutations = {
  10. setSinger (state, singer) {
  11. state.singer = singer;
  12. }
  13. };
  14. // 實(shí)例化store對(duì)象
  15. export default new Vuex.Store({
  16. state,
  17. mutations
  18. });
  19. // 在singer組件中提交數(shù)據(jù)
  20. this.$store.commit("setSinger",singer);
  21. // 在singer-detail組件中接收數(shù)據(jù)
  22. let singer = this.$store.state.singer;
vuex稍微復(fù)雜點(diǎn)的使用

在上面的小栗子中,我們把satemutations等其他一些內(nèi)容寫(xiě)在了一起,
但是這種方式不適合大型點(diǎn)的項(xiàng)目。最好能將這些內(nèi)容拎出來(lái),多帶帶作為一個(gè)文件來(lái)使用。

在src/store目錄中新建以下文件:

state.js 用于存儲(chǔ)狀態(tài)信息

</>復(fù)制代碼

  1. const sate = {
  2. singer: {}
  3. };
  4. export default state;

mutation-types.js 保存一些常量(mutations中函數(shù)的函數(shù)名)

</>復(fù)制代碼

  1. export const SET_SINGER = "SET_SINGER";

mutations.js 用于更改狀態(tài)(state中的數(shù)據(jù))

</>復(fù)制代碼

  1. import * as types from "./mutation-types";
  2. // 通過(guò)這個(gè)函數(shù)可以傳入payload信息
  3. const mutations = {
  4. [types.SET_SINGER](state,singer){
  5. state.singer = singer;
  6. }
  7. };
  8. export default mutations;

getters.js 對(duì)狀態(tài)獲取的封裝

</>復(fù)制代碼

  1. export const singer = state => state.singer;

actions.js 對(duì)mutation進(jìn)行封裝,或者執(zhí)行一些異步操作

</>復(fù)制代碼

  1. // 暫時(shí)沒(méi)有什么異步操作

index.js store的入口文件

</>復(fù)制代碼

  1. // 入口文件
  2. import Vue from "vue";
  3. import Vuex from "vuex";
  4. import state from "./state";
  5. import mutations from "./mutations";
  6. import * as actions from "./actions";
  7. import * as getters from "./getters";
  8. import createLogger from "vuex/dist/logger";
  9. Vue.use(Vuex);
  10. // 調(diào)試環(huán)境下開(kāi)啟嚴(yán)格模式
  11. const debug = process.env.NODE_ENV !== "production";
  12. // 創(chuàng)建store對(duì)象并導(dǎo)出
  13. export default new Vuex.Store({
  14. state,
  15. actions,
  16. getters,
  17. mutations,
  18. strict: debug,
  19. plugins: debug ? [createLogger()] : []
  20. });

使用:

</>復(fù)制代碼

  1. // main.js中引入
  2. import store from "./store";

有了以上內(nèi)容,那么我們就可以在業(yè)務(wù)中去使用了:

例如:多組件之間的的數(shù)據(jù)交互。
需求:singer組件中需要將用戶(hù)點(diǎn)擊的那個(gè)singer對(duì)象傳遞給組件singer-detail組件。

singer.vue 組件中:

</>復(fù)制代碼

  1. // 使用這個(gè)語(yǔ)法糖
  2. import { mapMutations } from "vuex";
  3. methods:{
  4. ...mapMutations({
  5. // 將這個(gè)函數(shù)(setSinger)和mutations中用于修改狀態(tài)的函數(shù)關(guān)聯(lián)起來(lái)
  6. setSinger: "SET_SINGER"
  7. });
  8. }
  9. // 傳參
  10. this.setSinger(singer);
  11. // 語(yǔ)法糖的本質(zhì)
  12. this.$store.commit("setSinger", singer);

singer-detail.vue 組件中:
我們就可以去使用這個(gè)數(shù)據(jù)了,當(dāng)然也是使用我們的語(yǔ)法糖啦。

</>復(fù)制代碼

  1. import { mapGetters } from "vuex";
  2. export default {
  3. // 使用一個(gè)計(jì)算屬性
  4. computed: {
  5. ...mapGetters([
  6. "singer" // 這個(gè)就是getters.js中的那個(gè)singer
  7. ]);
  8. },
  9. created(){
  10. console.log(this.singer);
  11. }
  12. }
  13. // 語(yǔ)法糖的本質(zhì):
  14. let singer = this.$store.state.singer;
js中給CSS添加prefix

我們一定遇到過(guò)這種情況:
需要用JS寫(xiě)CSS動(dòng)畫(huà)。但我們又不得不處理前綴的問(wèn)題。

所以一般是這樣寫(xiě)的:

</>復(fù)制代碼

  1. this.$refs.image.style.transform = `scale(${scale})`;
  2. this.$refs.image.style.webkitTansform = `scale(${scale})`;
  3. ...

那么問(wèn)題來(lái)了,怎樣用JS處理這種情況呢?

思路:

檢測(cè)瀏覽器的能力。

返回帶著前綴的CSS樣式。

代碼實(shí)現(xiàn):

</>復(fù)制代碼

  1. let elementStyle = document.createElement("div").style;
  2. // 得到合適的瀏覽器前綴
  3. let vendor = (() => {
  4. let transformNames = {
  5. webkit: "webkitTransform",
  6. Moz: "MozTransform",
  7. O: "OTransform",
  8. ms: "msTransform",
  9. standard: "transform"
  10. };
  11. for (let key in transformNames) {
  12. let support = elementStyle[transformNames[key]] !== undefined;
  13. if (support) {
  14. return key;
  15. }
  16. }
  17. return false;
  18. })();
  19. // 對(duì)外暴露的方法
  20. export function prefixStyle (style) {
  21. if (vendor === false) {
  22. return style;
  23. }
  24. if (vendor === "standard") {
  25. return style;
  26. }
  27. let result = vendor + style.charAt(0).toUpperCase() + style.substr(1);
  28. return result;
  29. }

使用案例:

</>復(fù)制代碼

  1. // 導(dǎo)入該模塊
  2. import { prefixStyle } from "common/js/dom";
  3. // 加了合適前綴的CSS屬性
  4. const TRANSFORM = prefixStyle("transform");
  5. // 使用該CSS屬性
  6. this.$refs.image.style[TRANSFORM] = `scale(${scale})`;
移動(dòng)端的touch事件

隨著觸屏設(shè)備的普及,w3c為移動(dòng)端web新增了touch事件。

最基本的touch事件包括4個(gè)事件:

touchstart 當(dāng)在屏幕上按下手指時(shí)觸發(fā)

當(dāng)用戶(hù)手指觸摸到的觸摸屏的時(shí)候觸發(fā)。事件對(duì)象的 target 就是 touch 發(fā)生位置的那個(gè)元素。

touchmove 當(dāng)在屏幕上移動(dòng)手指時(shí)觸發(fā)

即使手指移出了 原來(lái)的target元素,但 touchmove 仍然會(huì)被一直觸發(fā),而且 target 仍然是原來(lái)的 target 元素。

touchend 當(dāng)在屏幕上抬起手指時(shí)觸發(fā)

當(dāng)用戶(hù)的手指抬起的時(shí)候,會(huì)觸發(fā) touchend 事件。如果用戶(hù)的手指從觸屏設(shè)備的邊緣移出了觸屏設(shè)備,也會(huì)觸發(fā) touchend 事件。

touchend 事件的 target 也是與 touchstarttarget 一致,即使已經(jīng)移出了元素。

touchcancel 當(dāng)一些更高級(jí)別的事件發(fā)生的時(shí)候(如電話接入或者彈出信息)會(huì)取消當(dāng)前的touch操作,即觸發(fā)touchcancel。一般會(huì)在touchcancel時(shí)暫停游戲、存檔等操作。

如果你使用了觸摸事件,可以調(diào)用 event.preventDefault()來(lái)阻止鼠標(biāo)事件被觸發(fā)。

與移動(dòng)端相關(guān)的interface主要有三個(gè):

TouchEvent 表示觸摸狀態(tài)發(fā)生改變時(shí)觸發(fā)的event

可以通過(guò)檢查觸摸事件的 TouchEvent.type 屬性來(lái)確定當(dāng)前事件屬于哪種類(lèi)型。

</>復(fù)制代碼

  1. dom.addEventListener("touchstart",(e) => {
  2. // 獲取事件類(lèi)型
  3. let type = e.type;
  4. // toch事件發(fā)生時(shí)那個(gè)位置的元素對(duì)象
  5. let target = e.target;
  6. });

Touch 表示用戶(hù)和觸屏設(shè)備之間接觸時(shí)多帶帶的交互點(diǎn)(a single point of contact)

screenXscreenY:觸點(diǎn)相對(duì)于屏幕左邊緣或上邊緣的x、y坐標(biāo)。
clientXclientY:觸點(diǎn)相對(duì)于瀏覽器viewport左邊緣或上邊緣的x、y坐標(biāo)。(不包含滾動(dòng)距離)

pageXpageY:觸點(diǎn)相對(duì)于document的左邊緣或上邊緣的x、y坐標(biāo)。與client不同的是,包含左邊滾動(dòng)的距離。

target:觸摸開(kāi)始時(shí)的element。

</>復(fù)制代碼

  1. // 獲取touchList
  2. let touchList = e.changedTouches;
  3. // 獲取第i個(gè)touch對(duì)象
  4. let touch = touchList[i];
  5. touch.screenX
  6. touch.clientX
  7. touch.pageX
  8. touch.target
  9. ...

TouchList 表示一組touches。當(dāng)發(fā)生多點(diǎn)觸摸的時(shí)候才用的到。

如果一個(gè)用戶(hù)用三根手指接觸屏幕(或者觸控板), 與之相關(guān)的TouchList對(duì)于每根手指都會(huì)生成一個(gè) Touch 對(duì)象, 共計(jì) 3 個(gè).
可以通過(guò)三種方式獲取這個(gè)對(duì)象:

</>復(fù)制代碼

  1. dom.addEventListener("touchstart",(e) => {
  2. // 這個(gè) TouchList對(duì)象列出了和這個(gè)觸摸事件對(duì)應(yīng)的那些發(fā)生了變化的 Touch 對(duì)象
  3. e.changedTouches
  4. // 這個(gè)TouchList列出了那些 touchstart發(fā)生在這個(gè)元素,并且還沒(méi)有離開(kāi) touch surface 的touch point(手指)
  5. e.targetTouches
  6. // 這個(gè) TouchList 列出了事件觸發(fā)時(shí): touch suface上所有的 touch point。
  7. e.touches
  8. });
播放器內(nèi)核開(kāi)發(fā) audio標(biāo)簽

對(duì)于音樂(lè)的播放,我們使用了audio標(biāo)簽,監(jiān)聽(tīng)它的事件和操作DOM,可以達(dá)到對(duì)音樂(lè)播放、
暫停、進(jìn)度控制等操作。

</>復(fù)制代碼

對(duì)audio進(jìn)行操作

</>復(fù)制代碼

  1. let audio = this.$refs.audio;
  2. // 暫停和播放
  3. audio.pause();
  4. audio.play();
  5. // Audio對(duì)象的屬性(部分)
  6. audio.currentTime // 設(shè)置或返回音頻中的當(dāng)前播放位置(以秒計(jì))。
  7. audio.duration // 返回音頻的長(zhǎng)度(以秒計(jì))。
  8. audio.loop // 設(shè)置或返回音頻是否應(yīng)在結(jié)束時(shí)再次播放。(默認(rèn)false
  9. audio.volume // 設(shè)置或返回音頻的音量。[0,1]
  10. // Audio對(duì)象多媒體事件(Media Events)
  11. onerror // 加載發(fā)生錯(cuò)誤時(shí)的回調(diào)
  12. ontimeupdate // 當(dāng)播放位置改變時(shí)調(diào)用
  13. updateTime(e) {
  14. if(this.currentSongReady){
  15. // 獲取當(dāng)前播放的進(jìn)度
  16. this.currentSongTime=e.traget.currentTime;
  17. }
  18. }
  19. oncanplay // 能夠播放時(shí)調(diào)用
  20. // 通過(guò)監(jiān)聽(tīng)這個(gè)事件,設(shè)置標(biāo)志位,這個(gè)標(biāo)志位可以幫助我們
  21. // 防止用戶(hù)快速切換歌曲引起一些錯(cuò)誤。
  22. songCanPlay(){
  23. this.currentSongReady = true;
  24. }
  25. onended // 到達(dá)結(jié)尾時(shí)調(diào)用
  26. onplay、onpause...
進(jìn)度條組件

1.progress-bar.vue接收一個(gè)percent參數(shù),用來(lái)顯示當(dāng)前播放的一個(gè)進(jìn)度。

2.對(duì)于進(jìn)度條用戶(hù)手動(dòng)拖動(dòng)進(jìn)度的實(shí)現(xiàn)。

</>復(fù)制代碼

思路:主要是通過(guò)監(jiān)聽(tīng)ontouchstartontouchmoveontouchend事件來(lái)完成。

</>復(fù)制代碼

  1. // 首先得定義一個(gè)`touch`對(duì)象
  2. let touch = {};
  3. // 在監(jiān)聽(tīng)的方法中
  4. touchStart(e){
  5. this.touch.initialized = true;
  6. // 獲取touch的起始位置
  7. this.touch.startX = e.touches[0].pageX;
  8. // 獲取整個(gè)進(jìn)度條的寬度
  9. this.touch.barW = xxx;
  10. // 獲取已經(jīng)播放的進(jìn)度
  11. this.touch.offset = xxx;
  12. }
  13. touchMove(e){
  14. // 判斷有無(wú)初始化
  15. ...
  16. // 獲取用戶(hù)滑動(dòng)的距離
  17. let deltaX = e.touches[0].pageX - this.touch.startX;
  18. let barW = xxx; // 進(jìn)度條的寬度 - 拖動(dòng)btn的寬度
  19. let offset = Math.min(Math.max(0, this.touch.offset + detail), barW);
  20. // 最后設(shè)置btn的位置和progress的進(jìn)度就OK
  21. ...
  22. }
  23. touchEnd(){
  24. this.touch.initialized = false;
  25. // 然后將進(jìn)度推送出去就好了
  26. this.$emit("percentChange",percent);
  27. }
svg實(shí)現(xiàn)圓形進(jìn)度條

</>復(fù)制代碼

通過(guò)svg可以實(shí)現(xiàn)各種進(jìn)度條,有一個(gè)問(wèn)題,怎樣去動(dòng)態(tài)的修改它的進(jìn)度值呢?

這就不能不提 SVG Stroke 屬性

stroke 定義一條線,文本或元素輪廓顏色

stroke-width 文本或元素輪廓的厚度

stroke-dasharray 該屬性可用于創(chuàng)建虛線

stroke-dashoffset 設(shè)置虛線邊框的偏移量

OK,知道了以上屬性,就足以實(shí)現(xiàn)一個(gè)可設(shè)置進(jìn)度的SVG進(jìn)度條了。

思路:stroke-dasharray適用于創(chuàng)建虛線的,如果這個(gè)虛線長(zhǎng)度為整個(gè)輪廓的周長(zhǎng)呢。
stroke-dashoffset可以設(shè)置虛線的偏移量,利用這兩個(gè)屬性,我們就可以完成對(duì)進(jìn)度的控制。

且看一個(gè)小栗子:

所以,通過(guò)父組件傳入的percent,不斷地修改stroke-dashoffset就能達(dá)到進(jìn)度的顯示了。

全屏和退出全屏

</>復(fù)制代碼

  1. // 全屏顯示
  2. document.documentElement.webkitRequestFullScreen();
  3. // 退出全屏
  4. document.webkitExitFullscreen();
  5. // 1.得根據(jù)不同的瀏覽器添加前綴
  6. // 2.程序主動(dòng)調(diào)用不管用,得用戶(hù)操作才可以(點(diǎn)擊按鈕)
歌詞頁(yè)的顯示

通過(guò)網(wǎng)絡(luò)接口獲取的歌詞:

對(duì)于歌詞的解析,播放是通過(guò)一個(gè)插件lyric-parser完成的。

這個(gè)插件很簡(jiǎn)單:
1.通過(guò)正則把時(shí)間和對(duì)應(yīng)的歌詞切分出來(lái)創(chuàng)建成對(duì)象。
2.當(dāng)調(diào)用play方法時(shí),通過(guò)定時(shí)器完成歌詞的播放,并將對(duì)應(yīng)的行號(hào)和歌詞通過(guò)回調(diào)函數(shù)傳遞出去。

當(dāng)播放的歌詞超過(guò)5行時(shí),就可以使用封裝的scroll組件完成滾動(dòng)操作。

</>復(fù)制代碼

  1. if (lineNum > 5) {
  2. let elements = this.$refs.lyricLine;
  3. this.$refs.lyricScroll.scrollToElement(elements[lineNum - 5], 1000);
  4. } else {
  5. this.$refs.lyricScroll.scrollTo(0, 0, 1000);
  6. }
Vue中的mixin

為什么要使用mixin?

多個(gè)組件公用一樣的代碼,我們可以將這部分抽離出來(lái)作為mixin,只要引入對(duì)應(yīng)的組件中就可以了。

例如下面的mixin

</>復(fù)制代碼

  1. import { mapGetters } from "vuex";
  2. export const playListMixin = {
  3. mounted () {
  4. this.handlePlayList(this.playList);
  5. },
  6. // 當(dāng)路由對(duì)應(yīng)的頁(yè)面激活時(shí)調(diào)用
  7. activated () {
  8. this.handlePlayList(this.playList);
  9. },
  10. watch: {
  11. playList (newPlayList) {
  12. this.handlePlayList(newPlayList);
  13. }
  14. },
  15. computed: {
  16. ...mapGetters([
  17. "playList"
  18. ])
  19. },
  20. methods: {
  21. // 這個(gè)方法需要對(duì)應(yīng)的組件自己去實(shí)現(xiàn),直接調(diào)用拋出錯(cuò)誤
  22. handlePlayList () {
  23. throw new Error("Components must implement handlePlayList method.");
  24. }
  25. }
  26. };

有了mixin我們?cè)诮M件中就可以這樣使用了:

</>復(fù)制代碼

  1. import { playListMixin } from "common/js/mixin";
  2. export default{
  3. mixins: [playListMixin],
  4. ...
  5. }
節(jié)流處理

在搜索頁(yè)面,我們需要處理用戶(hù)的輸入,然后向服務(wù)器發(fā)起請(qǐng)求。
為了不必要的請(qǐng)求、節(jié)省流量和提高頁(yè)面性能,我們都有必要做節(jié)流處理。

在搜索框search-box這個(gè)基礎(chǔ)組件中:

</>復(fù)制代碼

  1. // 在created鉤子中,我們監(jiān)聽(tīng)用戶(hù)輸入字符串(query)變化,然后將變化后的字符串
  2. // 提交給父組件
  3. // 可以看到在回調(diào)函數(shù)中,又包了一層debounce函數(shù)
  4. created () {
  5. this.$watch("query", debounce(() => {
  6. this.$emit("queryChange", this.query);
  7. }, 500));
  8. }

所以debounce函數(shù),就是我們的節(jié)流函數(shù),這個(gè)函數(shù),接收一個(gè)函數(shù),返回一個(gè)新的函數(shù)

</>復(fù)制代碼

  1. function debounce(func,delay){
  2. let timer = null;
  3. return function(...args){
  4. if(timer){
  5. clearTimeout(timer);
  6. }
  7. timer = setTimeout(()=>{
  8. func.apply(this,args);
  9. },delay)
  10. }
  11. }
  12. // 測(cè)試
  13. function show(){
  14. console.log("hello...");
  15. }
  16. var func = debounce(show,3000);
  17. // 調(diào)用
  18. func();
  19. // 連續(xù)調(diào)用時(shí),沒(méi)有超過(guò)三秒是不會(huì)有任何輸出的
animation動(dòng)畫(huà)

語(yǔ)法:

</>復(fù)制代碼

  1. animation: name duration timing-function delay iteration-count direction fill-mode play-state;
    animation: 動(dòng)畫(huà)名稱(chēng) 執(zhí)行時(shí)間 速度曲線 延時(shí)時(shí)間 執(zhí)行次數(shù) 動(dòng)畫(huà)播放順序 結(jié)束時(shí)應(yīng)用的樣式 播放的狀態(tài)(paused|running
封裝localStorage操作

</>復(fù)制代碼

  1. const __VERSION__ = "1.0.1";
  2. const store = {
  3. version: __VERSION__,
  4. storage: window.localStorage,
  5. session: {
  6. storage: window.sessionStorage
  7. }
  8. };
  9. // 操作store的api
  10. const api = {
  11. set (key, val) {
  12. if (this.disabled) {
  13. return false;
  14. }
  15. if (val === undefined) {
  16. return this.remove(key);
  17. }
  18. this.storage.setItem(key, this.serialize(val));
  19. return val;
  20. },
  21. get (key, val) {
  22. if (this.disabled) {
  23. return false;
  24. }
  25. let result = this.storage.getItem(key);
  26. if (!result) {
  27. return val;
  28. }
  29. return this.deSerialize(result);
  30. },
  31. getAll () {
  32. if (this.disabled) {
  33. return false;
  34. }
  35. let ret = {};
  36. for (let key in this.storage) {
  37. if (this.storage.hasOwnProperty(key)) {
  38. ret[key] = this.get(key);
  39. }
  40. }
  41. return ret;
  42. },
  43. remove (key) {
  44. if (this.disabled) {
  45. return false;
  46. }
  47. this.storage.removeItem(key);
  48. },
  49. removeAll () {
  50. if (this.disabled) {
  51. return false;
  52. }
  53. this.storage.clear();
  54. },
  55. forEach (cb) {
  56. if (this.disabled) {
  57. return false;
  58. }
  59. for (let key in this.storage) {
  60. if (this.storage.hasOwnProperty(key)) {
  61. cb && cb(key, this.get(key));
  62. }
  63. }
  64. },
  65. has (key) {
  66. if (this.disabled) {
  67. return false;
  68. }
  69. return key === this.get(key);
  70. },
  71. serialize (val) {
  72. try {
  73. return JSON.stringify(val) || undefined;
  74. } catch (e) {
  75. return undefined;
  76. }
  77. },
  78. deSerialize (val) {
  79. if (typeof val !== "string") {
  80. return undefined;
  81. }
  82. try {
  83. return JSON.parse(val) || undefined;
  84. } catch (e) {
  85. return undefined;
  86. }
  87. }
  88. };
  89. // 擴(kuò)展store對(duì)象
  90. Object.assign(store, api);
  91. Object.assign(store.session, api);
  92. // 瀏覽器能力檢測(cè)
  93. try {
  94. let testKey = "test_key";
  95. store.set(testKey, testKey);
  96. if (store.get(testKey) !== testKey) {
  97. store.disabled = true;
  98. }
  99. store.remove(testKey);
  100. } catch (e) {
  101. store.disabled = true;
  102. }
  103. export default store;
路由懶加載

為什么需要?

如果開(kāi)發(fā)的App太大的話,就會(huì)導(dǎo)致首屏渲染過(guò)慢,為了增強(qiáng)用戶(hù)體驗(yàn),加快渲染速度,
需要用到懶加載功能。讓首屏的內(nèi)容先加載出來(lái),其他路由下的組件按需加載。

vue官網(wǎng)描述:

</>復(fù)制代碼

  1. 異步組件
    在大型應(yīng)用中,我們可能需要將應(yīng)用分割成小一些的代碼塊,并且只在需要的時(shí)候才從服務(wù)器加載一個(gè)模塊。
    為了簡(jiǎn)化,Vue 允許你以一個(gè)工廠函數(shù)的方式定義你的組件,這個(gè)工廠函數(shù)會(huì)異步解析你的組件定義。
    Vue 只有在這個(gè)組件需要被渲染的時(shí)候才會(huì)觸發(fā)該工廠函數(shù),且會(huì)把結(jié)果緩存起來(lái)供未來(lái)重渲染。

</>復(fù)制代碼

  1. const AsyncComponent = () => ({
  2. // 需要加載的組件 (應(yīng)該是一個(gè) `Promise` 對(duì)象)
  3. component: import("./MyComponent.vue"),
  4. // 異步組件加載時(shí)使用的組件
  5. loading: LoadingComponent,
  6. // 加載失敗時(shí)使用的組件
  7. error: ErrorComponent,
  8. // 展示加載時(shí)組件的延時(shí)時(shí)間。默認(rèn)值是 200 (毫秒)
  9. delay: 200,
  10. // 如果提供了超時(shí)時(shí)間且組件加載也超時(shí)了,
  11. // 則使用加載失敗時(shí)使用的組件。默認(rèn)值是:`Infinity`
  12. timeout: 3000
  13. })

注意:如果你希望在 Vue Router 的路由組件中使用上述語(yǔ)法的話,你必須使用 Vue Router 2.4.0+ 版本。

當(dāng)然為了簡(jiǎn)單起見(jiàn):

router/index.js路由配置文件中這樣加載組件:

</>復(fù)制代碼

  1. // import Recommend from "@/components/recommend/recommend";
  2. const Recommend = () => ({
  3. component: import("@/components/recommend/recommend")
  4. });

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

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

相關(guān)文章

  • 如何用vue打造一個(gè)移動(dòng)音樂(lè)放器

    摘要:寫(xiě)在前面沒(méi)錯(cuò),這就是慕課網(wǎng)上的那個(gè)音樂(lè)播放器,后臺(tái)是某音樂(lè)播放器的線上接口扒取,雖然這類(lèi)項(xiàng)目寫(xiě)的人很多,但不得不說(shuō)這還是個(gè)少有的適合提升的好項(xiàng)目,做這個(gè)項(xiàng)目除了想寫(xiě)一個(gè)比較大并且功能復(fù)雜的項(xiàng)目,主要原因是要拿它來(lái)應(yīng)對(duì)面試,也確實(shí)對(duì)我的業(yè)務(wù)能 寫(xiě)在前面 沒(méi)錯(cuò),這就是慕課網(wǎng)上的那個(gè)vue音樂(lè)播放器,后臺(tái)是某音樂(lè)播放器的線上接口扒取,雖然這類(lèi)項(xiàng)目寫(xiě)的人很多,但不得不說(shuō)這還是個(gè)少有的適合vu...

    lanffy 評(píng)論0 收藏0
  • 基于vue移動(dòng)web音樂(lè)放器

    摘要:代碼實(shí)現(xiàn)得到合適的瀏覽器前綴對(duì)外暴露的方法使用案例導(dǎo)入該模塊加了合適前綴的屬性使用該屬性移動(dòng)端的事件隨著觸屏設(shè)備的普及,為移動(dòng)端新增了事件。如果用戶(hù)的手指從觸屏設(shè)備的邊緣移出了觸屏設(shè)備,也會(huì)觸發(fā)事件。 聲明 以下只是學(xué)習(xí)完慕課網(wǎng)huangyi老師實(shí)戰(zhàn)視頻課程的筆記內(nèi)容,僅供個(gè)人參考學(xué)習(xí)使用。如果對(duì)Vue2.0實(shí)戰(zhàn)高級(jí)-開(kāi)發(fā)移動(dòng)端音樂(lè)WebApp感興趣的話,請(qǐng)移步這里:https://c...

    tracy 評(píng)論0 收藏0
  • Vue 實(shí)現(xiàn)網(wǎng)易云音樂(lè) WebApp

    摘要:基于等開(kāi)發(fā)一款移動(dòng)端音樂(lè),界面參考了安卓版的網(wǎng)易云音樂(lè)布局適配常見(jiàn)移動(dòng)端。圖標(biāo)使用阿里巴巴圖標(biāo)庫(kù),中間的唱片旋轉(zhuǎn)動(dòng)畫(huà)使用了實(shí)現(xiàn)。搜索功能實(shí)現(xiàn)功能搜索歌手歌單歌曲熱門(mén)搜索數(shù)據(jù)節(jié)流上拉刷新保存搜索記錄。 基于 Vue(2.5) + vuex + vue-router + vue-axios +better-scroll + Scss + ES6 等開(kāi)發(fā)一款移動(dòng)端音樂(lè) WebApp,UI ...

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

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

0條評(píng)論

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