本項目特色以下 :css
1. 原生js封裝本身的跨域請求函數,支持promise調用,支持錯誤處理 2. 製做一些複用性強的vue組件,如輪播圖組件,支持手勢滑動,無限循環,圖片按需加載 3. 清晰明瞭的項目目錄
一個易於維護和迭代的項目,應該是具備可靠的項目目錄的,這裏,在vue-cli生成的目錄中,加入了services、directives、utils、store等目錄,並在webpack中修改相應的導入地址:vue
1. services 用於全局管理接口和http請求 2. directives 用於添加全局指令 3. utils 用於放置通用js函數 4. store 用於管理vuex數據等
1. 播放器要用到的圖標 2. 用於vue transition標籤切換時使用的css3動畫 3. css reset 4. 項目主題顏色,目前只能在項目初始化以前設置主題顏色,用於管理,全部組件主題顏色都來源於此
分紅兩個部分:webpack
1. jsonp分裝,負責http請求 2. 收集url地址,並放在API類上,並循環將url用bind函數導入到jsonp封裝函數中,其餘請求一樣可用
包括 :css3
1. banner組件 2. 播放器
該組件只對傳入的數據進行處理,並相應轉化,保證了組件的通用性
核心的函數主要是對***無限循環的處理、觸摸屏滑動,圖片按需加載***處理:
computed : { sliderImg : function(){ const [...saveImg] = this.bannerlist, //拷貝圖片列表數據,在展現區域的圖片實際上首尾拷貝了同樣的圖片,即尾端拷貝第一張,首端拷貝最後一張 [imgfirst, ...other] = this.bannerlist; saveImg.unshift(other[other.length-1]) saveImg.push(imgfirst) return saveImg }, }, mounted () { if (this.bannerlist && this.bannerlist.length) { this.interTimer = setInterval(()=>{ this.sliderStart() },3000) } }, methods : { linkURl (item) { window.open(item[this.linkurl]) }, getURl (item,index) { //用於減小一次性請求,只加載當前的圖片,加載以後添加標識 if (!item) { return reloadImg } if (item.hasload) { return item[this.picurl] } if (this.nowSlider == index-1) { item.hasload = true return item[this.picurl] } return reloadImg }, stopSlider (e) { e.preventDefault() e.stopPropagation() if (e.target != e.currentTarget) { //事件委託節省下事件綁定,排除當前綁定的dom clearInterval(this.interTimer) delete this.sliderActive['transition'] //關閉css3過渡效果 this.startTouch = e.targetTouches[0].screenX } }, moveSlider (e) { e.preventDefault() e.stopPropagation() if (this.nowSlider === -1||this.nowSlider === this.bannerlist.length) { //首端與尾端未鏈接好禁止滑動 return; } if (e.target != e.currentTarget) { this.moveTouch = e.targetTouches[0].screenX let slideDir = this.moveTouch - this.startTouch, targetWidth = parseInt(window.getComputedStyle(e.target).width), tranDir; if (slideDir < -50 || slideDir > 50) { //加了50容錯值,能預防觸摸時圖片忽然閃動 if (slideDir < 0) { //再從新補回差值 slideDir -= 50 } else { slideDir += 50 } tranDir = -targetWidth * (this.nowSlider+1) + slideDir//觸摸時圖片隨手指移動,距離須減去當前圖片寬度乘以當前滾動索引 this.sliderActive.transform = `translate3d(${tranDir}px,0,0)` } } }, continSilder (e) { //結束觸摸 e.preventDefault() e.stopPropagation() if (e.target != e.currentTarget && this.moveTouch) { const slideDir = this.moveTouch - this.startTouch if (slideDir < 0) { this.nowSlider ++ } else if (slideDir > 0) { this.nowSlider -- } this.nowSlider -- this.sliderStart() //當即設置位置 this.moveTouch = 0 //清空手勢位置 this.startTouch = 0 this.interTimer = setInterval(()=>{ this.sliderStart() },3000) } }, sliderStart () { this.nowSlider ++ this.nowSlider %= this.sliderImg.length if (this.nowSlider === this.bannerlist.length) { //向右滑動到最大值時,將位置初始化並清0 nowSlider setTimeout(() => { //設置一個定時器,用於異步處理,一個進行尾端拷貝的圖片的正常滑動,這個處理在差很少到達時重置,形成無限循環的錯覺 this.sliderActive = { transform: `translate3d(-100vw,0,0)` } this.nowSlider = 0 }, 500) } if (this.nowSlider === -1) { //向右滑動到最小值時,將位置置爲最大值 setTimeout(() => { this.nowSlider = this.bannerlist.length-1 this.sliderActive = { transform: `translate3d(${-100*(this.nowSlider+1)}vw,0,0)` } }, 500) } this.sliderActive = Object.assign({},{ transition:'transform 0.5s', transform: `translate3d(${-100*(this.nowSlider+1)}vw,0,0)` }) } }
播放器的全部功能主要依賴vuex(store.js)的控制,因爲音樂是在整個app內都播放的,故audio標籤放在了App.vue中:
store.js:git
APP.vue:github
computed : { audioSrc : function () { //對當前播放的音頻切換,放在頂層 const song = this.$store.state.nowsong; let audioTimer; if (!song) { this.$store.state.playing = false clearInterval(audioTimer) return null } this.$store.state.playing = true audioTimer = setInterval(()=>{ //每秒獲取進度 let audio = document.getElementById('m-audio'); if (audio) { this.$store.state.audioProgss = audio.currentTime/audio.duration*100+'%' } else { clearInterval(audioTimer) } },1000) return `${API.url.getsong}${song.songid}.m4a?fromtag=46` //播放一首歌曲 }, playing : function () { return this.$store.state.playing }, }, directives : { play : { //控制是否播放 update : function(el,binding) { if (binding.value) { el.play() } else { el.pause() } } } },