{{song.name}}
{{getDesc(song)}}
摘要:在中新建組件許文瑞正在吃屎。。。。在中添加如下代碼三歌手組件開發歌手首頁開發數據獲取數據獲取依舊從音樂官網獲取歌手接口創建我們和以前一樣,利用我們封裝的等發放,來請求我們的接口,返回給。
Vue-Music
跟學一個網課老師做的仿原生音樂APP跟學的筆記,記錄點滴,也希望對學習vue初學小伙伴有點幫助一| 前期工作 1.項目初始化
npm install -g vue-cli
vue init webpack vue-music
npm install stylus stylus-loader -D
修改eslint.js
修改webpack.base.conf.js resolve配置項簡化路徑
2.裝包npm install fastclick --save 取消默認300ms延遲
import fastClick from "fastclick" fastClick.attach(document.body)
npm install babel-polyfill
對es6的高級語法進行轉義當運行環境中并沒有實現的一些方法,babel-polyfill 會給其做兼容
需要在main.js中引入
npm install babel-runtime --save 輔助編譯 不需要引入即可用
babel-runtime 是供編譯模塊復用工具函數。是錦上添花二| 頂部tab導航 && Recommend 頁面組件開發 1. 頂部導航欄 tab
babel-polyfil是雪中送炭,是轉譯沒有的api.
建立基本的頁面骨架,基本的組件引入
header rank recommend search singer tab 這幾個組件組成頁面骨架
數據獲取
qq音樂
JsonpJsonp發送的不是一個ajax請求,他動態創建一個script標簽,script沒有同源策略限制,所以能跨域 有一個返回參數 callback , 后端解析url,返回一個方法。
安裝: npm install jsonp@0.2.1
jsonp github倉庫
以后需要多出引用jsonp跨域請求,將其創建在 scr/common/jsonp.js 中
jsonp promise化import originJSONP from "jsonp" export default function jsonp(url, data, option) { // jsonp的三個參數 // - url-->一個純凈的url地址 // - data --> url中的 query 通過 data 拼到url上 // - option url += (url.indexOf("?") < 0 ? "?" : "&") + param(data) return new Promise((resolve, reject) => { originJSONP(url, option, (err, data) => { if (!err) { resolve(data) } else { reject(err) } }) }) } // 拼接data到url function param (data) { let url = "" for (var k in data) { let value = data[k] !== undefined ? data[k] : "" url += `&${k}=${encodeURIComponent(value)}` } // encodeURIComponent() 函數可把字符串作為 URI 組件進行編碼。 return url ? url.substring(1) : "" }
注意:當路徑報錯的時候,我們要想到webpack.base.conf.js配置文件中的 alias 選項 確保路徑是否匹配Recommend的數據獲取
在 recommend.vue 中的 created 生命周期鉤子中調用_getRecommend 方法
_getRecommend 方法調用recommend.js中暴露出來的getRecommend方法
而 getRecommend 方法調用了 Jsonp 方法, Jsonp方法抓取接口,從而獲得數據
輪播圖組件有的jsonp接口url很長,但是真正的url知識前面的部分
大公司一般用0來代表一切正常
輪播圖數據獲取完成后,就下來做的就是搭建輪播頁面 ,接下來編寫一個輪播組件 slider.vue
新建base文件夾,儲存如同slider.vue的基礎組件
在silder.vue中,我們使用了slot插槽,外部引用slider的時候slider標簽里面包裹的dom會被插入到slot插槽部分。
在recommend.vue中 引入 import Slider from "base/slider/slider",并在components中注冊Slider,之后就可以使用Slider標簽了
將jsonp返回的slider數據存儲到recommend數組中,然后遍歷recommned 數組項循環渲染內容
這個時候我們打開項目,會發現已有數據,但是樣式還不行,在props中添加loop,autoplay,interval(滾動間隔),
使用了第三方輪播 better-scroll 來進一步實現 slider
新版的BS中snap屬性集合成了一個對象選項 而舊版的是多帶帶的屬性名,這點要注意
初始化BS,在什么時候初始化?
我們要保證渲染的時機是正確的,通常在mounted生命周期鉤子中初始化,保證BS正常渲染的話我們通常在mounted里面加一個延遲
mounted () { setTimeout(() => { // 瀏覽器17ms刷新一次, 這里延遲20ms 確保組件已經渲染完成 this._setSliderWidth() // 設置slider寬度 this._initDots() // 初始話dots this._initSlider() // 初始化slider }, 20)
_setSliderWidth方法 -- 輪播圖組件的寬度計算
這里要注意,這時候執行玩寬度方法之后,可能無效,這是因為在寬度計算的時候,slot插槽里面的東西還未加載,為了解決這個問題,我們可以在recommend.vue中 給slider 的父元素 加上v-if="recommends.length",確保渲染時機正確
_initSlider()方法 -- 使用new BScroll 創建輪播實例,設置無限滾動及其他的相關初始化配置,至此,我們的輪播頁面已經可以無縫滾動了
添加dots導航
五個數據,dom有七個,因為loop為ture的時候,bs會自動在前后各拷貝一份。我們想要添加dots,必須保證和數據數一樣,所以我們應該在bs初始化之前完成dots的初始化
初始化dots為一個長度為childern.length的數組
this.dots = new Array(this.children.length)
在slider.vue中循環
v-for="(item,index) of dots"
添加選中樣式
:class="{active:currentPageIndex === index}"
在bs滾動的時候 會派發一個事件 在初始化slider 綁定一個事件
this.slider.on("scrollEnd", () => { let pageIndex = this.slider.getCurrentPage().pageX if (this.loop) { pageIndex -= 1 this.currentPageIndex = pageIndex if (this.autoplay) { clearTimeout(this.timer) this._play() } } })
使用了 bs中的 getCurrentPage 方法來獲取滾動的當前頁面
在autoplay中使用了bs 的 goToPage 方法來實現輪播
監聽窗口大小改變自動改變 && 優化slider
之前的slider基本完成,但是此時如果改變窗口大小,頁面就會亂掉
使用resize窗口監聽事件,配合bs的refresh刷新方法 實現每一次改變窗口大小都能重置寬度
window.addEventListener("resize", () => { if (!this.slider) { // slider還沒有初始化的時候 return } this._setSliderWidth(true) this.slider.refresh() })
在app.vue 中使用keepalive標簽,來避免重復請求
我們在跳轉到其他頁面的時候,要記得清理定時器,優化效率
destroyed() { clearTimeout(this.timer) // 性能優化小習慣 }歌單組件 歌單組件數據獲取
在pc版的qq音樂中獲取請求接口
由于QQ音樂的歌單數據時,請求接口host和refer規定了必須是qq音樂的地址,我們本地就會請求失敗。為了解決這個問題,我們可以使用 手動代理 偽裝成qq音樂地址請求接口 欺騙接口Vue proxyTable代理 后端代理接口
在項目開發的時候,接口聯調的時候一般都是同域名下,且不存在跨域的情況下進行接口聯調,但是當我們現在使用vue-cli進行項目打包的時候,我們在本地啟動服務器后,比如本地開發服務下是 http://localhost:8080 這樣的訪問頁面,但是我們的接口地址是 http://xxxx.com/save/index 這樣的接口地址,我們這樣直接使用會存在跨域的請求,導致接口請求不成功,因此我們需要在打包的時候配置一下,我們進入 config/index.js 代碼下如下配置即可:
dev: { // 靜態資源文件夾 assetsSubDirectory: "static", // 發布路徑 assetsPublicPath: "/", // 代理配置表,在這里可以配置特定的請求代理到對應的API接口 // 例如將"localhost:8080/api/xxx"代理到"www.example.com/api/xxx" // 使用方法:https://vuejs-templates.github.io/webpack/proxy.html proxyTable: { "/": { target: "https://c.y.qq.com", // 接口的域名 secure: false, // 如果是https接口,需要配置這個參數 changeOrigin: true, // 如果接口跨域,需要進行這個參數配置 pathRewrite: { "^/api": "/" }, headers: { referer: "https://c.y.qq.com" } } }
注意: "/api" 為匹配項,target 為被請求的地址,因為在 ajax 的 url 中加了前綴 "/api",而原本的接口是沒有這個前綴的,所以需要通過 pathRewrite 來重寫地址,將前綴 "/api" 轉為 "/"。如果本身的接口地址就有 "/api" 這種通用前綴,就可以把 pathRewrite 刪掉。表單組件開發
我們通過代理獲得ajax數據后,將其賦值給 discList
this.discList = res.data.list
之后將disclist渲染到組件中
v-for="item of discList"
滾動組件 Scroll.vue
由于 滾動 是一個很基礎的組件 所以在common里創建scroll.vue組件,使代碼結構化
在Recommend.vue中 一定要綁定data數據,因為scroll.vue中 watch 監聽data數據的變化來刷新better-scroll 這里的可以綁定recommend.vue中的 discList 數組來座位 data這里的 recommends 和 discList 數據獲取是有先后順序的,一般都是先recommends再discList,如果先獲取到的是discList的話 歌單列表就會出現滾動不到底部的問題
為了確保recommend數據后加載的情況下我們的表單還能正常滾動發,我們可以給slider中的img添加一個loadImage方法@load="loadImage",方法調用一個 refresh方法即可 this.$refs.scroll.refresh()
為了避免請求的每一張圖片都執行一次,我們可以設置一個bool標志位來控制 ,只要有一張圖片加載完成即可,如下:
loadImage() { if (!this.checkLoaded) { this.$refs.scroll.refresh() this.checkLoaded = true } }表單組件優化
圖片的懶加載
節省流量,提升加載速度
npm 安裝
npm install vue-lazyload
在main.js中添加代碼
import VueLazyLoad from "vue-lazyload" Vue.use(VueLazyLoad, { loading: require("common/images/touxiang.png") })
在Recommend.vue中使用
解決圖片點擊失效
有些情況下點擊事件之間互相沖突,我們在使用fastclick的時候,可以給點擊的dom添加一個fastclick里的一個css needsclick的類名,來確保點擊事件可以正常執行
loading組件
為了增加交互體驗,在表單還未渲染之前,我們可以使用一個loading來占位。
在base中新建loading組件
{{title}}
在recommend.vue中添加如下代碼:
三| 歌手組件開發 1.歌手首頁開發 數據獲取
數據獲取依舊從qq音樂官網獲取
歌手接口
創建singer.js
我們和以前一樣,利用我們封裝的jsonp等發放,來請求我們的接口,返回給singer.vue。
成功獲取數據以后,我們發現,官網的數據的數據結構和我們想要的不一樣,所以我們下一步進行數據結構的聚合處理數據處理
我們希望的數據結構是數據按照字母排序的數組再加上一個熱門的數組的集合,顯然我們在官網的到的數據不是這樣的,我們構造一個_normalizeSinger方法來完成:
_normalizeSinger(list) { // 處理數據結構 形參為list let map = { // 把數據都存在map對象中 hot: { // 熱門城市 title: HOT_NAME, items: [] // 初始化空數組 } } list.forEach((item, index) => { // 循環數組中的每一項 if (index < HOT_SINGER_LENGTH) { // 因為原始數據是按照熱度排列的,所以獲取前十的熱門 map.hot.items.push(new Singer({ // push到我們的hot數組中 // new Singer: 為了模塊化和減少代碼的復用,我們在common > js 創建了一個singer.js // 來創建一個類構造器 里面包括歌手頭像的拼接 id: item.Fsinger_mid, name: item.Fsinger_name })) } const key = item.Findex // 歌手姓氏字首字母 if (!map[key]) { // 如果不存在 map[key] = { // 創建 title: key, items: [] } } map[key].items.push(new Singer({ // 追加到map.items中 id: item.Fsinger_mid, name: item.Fsinger_name })) }) // 為了得到有序列表 我們需要處理map let hot = [] // 熱門城市 let ret = [] // 字母表城市 for (let key in map) { // 循環 let val = map[key] if (val.title.match(/[a-zA-Z]/)) { // 正則匹配字母 ret.push(val) } else if (val.title === HOT_NAME) { hot.push(val) // 熱門城市 } } ret.sort((a, b) => { return a.title.charCodeAt(0) - b.title.charCodeAt(0) // 把字母城市按charcode字母排序 }) return hot.concat(ret) // 將字母城市追加到hot城市 返回給外部 }
細節點注意
關于歌手圖片的獲取,通過官網觀察,我們發現圖片是有一個網址拼接item.Fsinger_mid 來完成的,所以我們在common >js >singer.js中 使用了${}來拼接,獲取歌手圖片地址,拼接url語法是使用的是 `` 而不是" "listview.vue開發
數據我們獲取到了,我們接下來開發listview.vue組件,因為這個列表組件我們后面有很多頁面也要用到,所以我們在base下創建基礎組件 listview.vue
在listview.vue中引入 我們之前封裝好的scroll組件
import Scroll from "base/scroll/scroll"
通過獲取的數據,進行兩次遍歷渲染,就能得到我們想要的dom頁面了
html代碼如下
{{group.title}}
- {{item.name}}
- {{item}}
至此 歌手頁面就能正常滾動了
shortcutList字母導航器接下來,開始我們的字母導航器的樣式制作
我們可以在listview.vue中創建一個計算屬性shortcutList
computed: { shortcutList() { return this.data.map((group) => { return group.title.substr(0, 1) }) } },
之后在頁面中v-for渲染shortcutList即可 配合css樣式 實現邊欄的字母導航dom的制作
- {{item}}
靜態的字母導航在頁面中已經展現出來了
接下來 來給導航器添加滑動點擊等事件,使其動態化
滑動右邊字母導航 listview實時滾動
在字母html標簽中加入touch事件**
@touchstart="onShortcutTouchStart" @touchmove.stop.prevent="onShortcutTouchMove"
在循環中遍歷index值,在后面的touch中獲取索引,由于蕾類似此類獲取數據的方法是很多地方都能用到的,我們在dom.js中添加getData方法
export function getData(el, name, val) { const perfix = "data-" name = perfix + name if (val) { return el.setAttribute(name, val) } else { return el.getAttribute(name) } }
接下來 為scroll組件添加 跳轉方法
scrollTo() { this.scroll && this.scroll.scrollTo.apply(this.scroll, arguments) }, scrollToElement() { this.scroll && this.scroll.scrollToElement.apply(this.scroll, arguments)
完整的touch方法代碼如下:
onShortcutTouchStart(e) { let anchorIndex = getData(e.target, "index") // 獲取data let firstTouch = e.touches[0] // 剛開始觸碰的位置坐標 this.touch.y1 = firstTouch.pageY this.touch.anchorIndex = anchorIndex this._scrollTo(anchorIndex) // 通過使用_scrollTo方法來跳轉到我們的字母所在位置 }, onShortcutTouchMove(e) { // 屏幕滑動方法 要明確開始滾動和結束滾動的兩個位置,然后計算出滾動到哪一個字母 let firstTouch = e.touches[0] // 停止滾動時的位置坐標 this.touch.y2 = firstTouch.pageY // 保存到touch對象中 let delta = (this.touch.y2 - this.touch.y1) / ANCHOR_HEIGHT | 0 // 計算滾動了多少個字母 let anchorIndex = parseInt(this.touch.anchorIndex) + delta // this.touch.anchorIndex 字符串轉化為整型 this._scrollTo(anchorIndex) // 跳轉到字母位置 }
注意:通過getData方法的到的anchorIndex是一個字符串,記得要用parseInt轉化為數字
至此 滑動字母導航器 左邊的list已經可以實現滾動了
滾動左邊list 右邊字母導航高亮
解決這個問題 ,就要知道左邊listview滾動到的相對位置
在data中增加scrollY 和 currentIndex來實時監聽listview滾動的位置 和 應該滾動到的具體索引
在scroll標簽組件綁定@scroll="scroll" 來將滾動的實時位置賦值給this.scrollY
scroll(pos) { this.scrollY = pos.y console.log(pos) // 測試 }
在listview中添加監視屬性data
watch: { data() { setTimeout(() => { // 數據變化到dom變化有一個延遲,所以這個加一個定時器 this._calculateHeight() // 計算每一個group的高度 }, 20) }
每次data變化,都會重新計算group的高度
_calculateHeight方法
_calculateHeight() { this.listHeight = [] const list = this.$refs.listGroup let height = 0 this.listHeight.push(height) for (let i = 0; i < list.length; i++) { let item = list[i] height += item.clientHeight this.listHeight.push(height) // 得到一個包含每一個group高度的數組 } }
這樣 就能得到一個包含所有grroup高度的一個數據
在watch里監聽scrollY
拿到了每組的位置,我們可以監聽scrollY 聯合兩者判斷字母導航器應該滾動到的位置
scrollY(newY) { const listHeight = this.listHeight // 當滾動到頂部 newY > 0 if (newY > 0) { this.currentIndex = 0 return } // 在中間部分滾動 for (let i = 0; i < listHeight.length; i++) { let height1 = listHeight[i] let height2 = listHeight[i + 1] if (-newY >= height1 && -newY < height2) { this.currentIndex = i this.diff = height2 + newY // 注意 newY為負值 return } } // 當滾動到底部,且-newY 大于最后一個元素的上線 this.currentIndex = listHeight.length - 2 }
currentIndex 綁定類 實現字母高亮
:class="{"current": currentIndex === index}"
?
細節優化
完善_scrollTo方法
_scrollTo(index) { if (!index && index !== 0) { // 點擊以外的部分 無反應 return } if (index < 0) { // 滑動到頂部時 index為負 index = 0 } else if (index > this.listHeight.length - 2) { // 滑動到尾部 index = this.listHeight.length - 2 } this.scrollY = -this.listHeight[index] // 每次點擊都更改scrollY以實現同步 this.$refs.listview.scrollToElement(this.$refs.listGroup[index], 300) }
fixedTitle
計算屬性
fixedTitle() { if (this.scrollY > 0) { return "" } return this.data[this.currentIndex] ? this.data[this.currentIndex].title : "" }
頁面html
{{this.fixedTitle}}
至此 頂部的fixedtitle標題就做好了 但是我們發現兩個title在重合的時候 并不是很完美,下面我們就來添加一個頂上去的動畫來優化
在scrollY函數中 我們可以輕松獲取一個 diff 值
this.diff = height2 + newY // 注意 newY為負值
通過監聽diff 我們可以來實現我們的要求
diff(newVal) { let fixedTop = (newVal > 0 && newVal < TITLE_HEIGHT) ? newVal - TITLE_HEIGHT : 0 if (this.fixedTop === fixedTop) { return } this.fixedTop = fixedTop this.$refs.fixed.style.transform = `translate3d(0,${fixedTop}px,0)` }2.歌手詳情頁
歌手詳情使用二級子路由來開發字路由 / 二級路由設置
路由是由組件承載的
在router -- index.js中 寫入代碼
添加字路由
{ path: "/singer", name: "Singer", component: Singer, children: [ { path: ":id", component: SingerDetail } ] }
如代碼所示,在Singer component組件路由選項中,添加children 實現二級路由,然后需要在頁面上加上router-view
標簽來掛在這個二級路由顯示頁面
編寫跳轉邏輯
在次頁面中,二級路由的跳轉是在listview.vue中通過點擊事件向外派發事件來實現的
selectItem(item) { this.$emit("select", item) // 向外派發事件 }
因為listview.vue是一個基礎組件,不會編寫業務邏輯,所以把點擊事件派發出去,讓外部實現業務邏輯的編寫
在singer.vue 中,我們監聽到這個派發出來的select
然后在selectSinger方法里面使用vue-router的 編程式跳轉接口
selectSinger(singer) { this.$router.push({ path: `/singer/${singer.id}` // 跳轉頁面 }) }添加轉場動畫
將singer-detail.vue 組件用transition標簽包裹
并在css中添加動畫
.slide-enter-active, .slide-leave-active transition: all 0.3s .slide-enter, .slide-leave-to transform: translate3d( 0, 100%, 0)
就下來,開始正式開發singer-detail組件,在這之前,我們先了解一下Vuex 跳轉到vuex筆記
獲取singer-detail數據export function getSingerDetail(singerId) { const url = "https://c.y.qq.com/v8/fcg-bin/fcg_v8_singer_track_cp.fcg" const data = Object.assign({}, commonParams, { hostUin: 0, needNewCode: 0, platform: "h5page", order: "listen", begin: 0, num: 50, songstatus: 1, g_tk: 649509476, singermid: singerId // 注意是mid而不是id 不要出錯 }) return jsonp(url, data, options) }
當在singer-detail頁面上刷新的時候,會獲取不到數據,因為我們的數據是通過跳轉得到的,如果我們在singer-detail數據上刷新,將返回上一級signer this.$router.push("/singer")整理獲取的數據結構
common>js>song.js
export default class Song { constructor({id, mid, singer, name, album, duration, image, url}) { this.id = id this.mid = mid this.singer = singer this.name = name this.album = album this.duration = duration this.image = image this.url = url } } export function createSong(musicData) { return new Song({ id: musicData.songid, mid: musicData.songmid, singer: filterSonger(musicData.singer), name: musicData.songname, album: musicData.albumname, duration: musicData.interval, image: `https://y.gtimg.cn/music/photo_new/T002R300x300M000${musicData.albummid}.jpg?max_age=2592000`, url: `http://ws.stream.qqmusic.qq.com/C100${musicData.songmid}.m4a?fromtag=0&guid=126548448&crazycache=1` }) } function filterSonger(singer) { let ret = [] if (!singer) { return "" } singer.forEach((s) => { ret.push(s.name) }) return ret.join("/") }
通過方法調用類構造器,我們就能通過createSong(musicData)來整理獲得我們需要的結構數據
singer-detail
methods: { _getDetail() { if (!this.singer.id) { this.$router.push("/singer") } getSingerDetail(this.singer.id).then((res) => { if (res.code === ERR_OK) { console.log(res.data.list) this.songs = this._normalizeSongs(res.data.list) } }) }, _normalizeSongs(list) { let ret = [] list.forEach((item) => { let {musicData} = item if (musicData.songid && musicData.albummid) { ret.push(createSong(musicData)) } }) return ret } }
這樣 通過調用_normalizeSongs方法 --> createSong 來得到songs數據
開發MusicList.vue組件在props中接受變量 bgImgae songs title
在singer-detail
通過計算屬性拿到title 和 bgImage ,
這樣就完成了父組件的singer-detail向子組件的music-list的傳值
因為歌曲列表是滾動的 我們在music-list中復用了scroll組件我們還需要編寫一個song-lsit組件,為接下來所用 跳轉到song-list組件開發
在music-list編寫代碼:
至此,打開頁面,我們可以看到歌單列表已經可以正常滾動
這是我們發現我們的頁面上全部被歌單列表所占用, 要計算圖片的位置把歌手背景圖展現出來
在mounted生命周期鉤子里添加
this.$refs.list.$el.style.top = `${this.$refs.bgImage.clientHeight}px`
這樣就能實現歌手海報圖的展示了
我們在music-list.vue中加入一個layer層,用于跟著跟單一起滾動,來覆蓋我們的bg-image,這樣就能視覺上達到我們想要的效果了
監聽滾動距離
為scroll組件傳入probeType值和listenScroll值
created() { this.probeType = 3 this.listenScroll = true }
為scroll添加scroll方法來監聽滾動距離
scroll(pos) { this.scrollY = pos.y }
并監聽scrollY數據
watch: { scrollY(newY) { let translateY = Math.max(this.minTranslateY, newY) let zIndex = 0 let scale = 1 let blur = 0 this.$refs.layer.style[transform] = `translate3d(0, ${translateY}px, 0)` const percent = Math.abs(newY / this.imageHeight) if (newY > 0) { scale = 1 + percent zIndex = 10 } else { blur = Math.min(20 * percent, 20) } this.$refs.filter.style[backdrop] = `blur(${blur}px)` if (newY < this.minTranslateY) { zIndex = 10 this.$refs.bgImage.style.paddingTop = 0 this.$refs.bgImage.style.height = `${RESERVED_HEIGHT}px` this.$refs.pbtn.style.display = "none" } else { this.$refs.bgImage.style.paddingTop = "70%" this.$refs.bgImage.style.height = 0 this.$refs.pbtn.style.display = "" } this.$refs.bgImage.style.zIndex = zIndex this.$refs.bgImage.style[transform] = `scale(${scale})` } }
處理方法見上面代碼zIndex相關操作
處理見上代碼 bgImage scale相關的操作
在scroll結尾復用loading 即可開發song-list組件
{{song.name}}
{{getDesc(song)}}
在music-list中傳入song值
Vuex 是一個專為 Vue.js 應用程序開發的狀態管理模式。它采用集中式存儲管理應用的所有組件的狀態,并以相應的規則保證狀態以一種可預測的方式發生變化。Vuex 也集成到 Vue 的官方調試工具 devtools extension,提供了諸如零配置的 time-travel 調試、狀態快照導入導出等高級調試功能。
簡單的說,當我們的vue項目比較復雜的時候,有的時候兩個兄弟組件,或者相關度聯系很低的組件相互之間需要同時獲取或監聽同一個數據或狀態,這個時候我們就要使用vuex
vuex 就像是一個大的機房,里面存著共享數據。這個房間我們可以讓任何一個組件進來獲取數據或者更新數據如何使用vuex
安裝vuex
npm install vuex --save
在項目的根目錄下,我們一般會新建一個store文件夾,里面添加新建文件:
入口文件 index.js
存放狀態 state.js
存放Mutations mutations.js
存放mutations相關數據的 mutation-types.js
數據修改 執行Mutations actions.js
數據映射 getters.js
getters 和 vue 中的 computed 類似 , 都是用來計算 state 然后生成新的數據 ( 狀態 ) 的。
以此項目為例子,需要各個組件之間共享一個singer數據
state.js
const state = { singer: {} } export default state
mutation-types.js
export const SET_SINGER = "SET_SINGER"
使用常量替代 mutation 事件類型在各種 Flux 實現中是很常見的模式。這樣可以使 linter 之類的工具發揮作用,同時把這些常量放在多帶帶的文件中可以讓你的代碼合作者對整個 app 包含的 mutation 一目了然
mutations.js
import * as types from "./mutation-types" // import * as obj from "xxx" 會將 "xxx" 中所有 export 導出的內容組合成一個對象返回。 const mutations = { [types.SET_SINGER](state, singer) { state.singer = singer } } export default mutations
mutations.js 可以理解為是一個修改數據的方法的集合
getter.js
有時候我們需要從 store 中的 state 中派生出一些狀態,如果有多個組件需要用到此屬性,我們要么復制這個函數,或者抽取到一個共享函數然后在多處導入它——無論哪種方式都不是很理想。
Vuex 允許我們在 store 中定義“getter”(可以認為是 store 的計算屬性)。就像計算屬性一樣,getter 的返回值會根據它的依賴被緩存起來,且只有當它的依賴值發生了改變才會被重新計算。
export const singer = state => state.singer
index.js
import Vue from "vue" import Vuex from "vuex" import * as actions from "./actions" import * as getters from "./getters" import state from "./state" import mutations from "./mutations" import createLogger from "vuex/dist/logger" Vue.use(Vuex) // 注冊插件 const debug = process.env.NODE_ENV !== "production" // 線下調試的時候 debug 為 ture export default new Vuex.Store({ // new一個實例 actions, getters, state, mutations, strict: debug, // 開啟嚴格模式,用于下面來控制是否開啟插件 plugins: debug ? [createLogger()] : [] // 開啟插件 })
main.js
在vue的main.js 中 注冊 vuex
import store from "./store" .... new Vue({ el: "#app", render: h => h(App), router, store })
以上,vuex的初始化就完成了
singer.vue 寫入 state
在組件中提交 Mutation
你可以在組件中使用 this.$store.commit("xxx") 提交 mutation,或者使用 mapMutations 輔助函數將組件中的 methods 映射為 store.commit 調用(需要在根節點注入 store)。
import {mapMutations} from "vuex"
在methods結尾添加
...mapMutations({ setSinger: "SET_SINGER" // 將 `this.setSinger()` 映射為 `this.$store.commit("SET_SINGER")` })
通過this.setSinger(singer) 實現了對Mutations的提交
singer-detail.vue 取出state數據
引入
import {mapGetters} from "vuex"
在computed中
computed: { ...... ...mapGetters([ "singer" // 把 `this.signer` 映射為 `this.$store.getters.singer` ]) }
至此,singer-detail 和 singer 之間就實現 singer 的共享了
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/97028.html
摘要:概述項目是基于,成品是一個移動端的音樂播放器,來源于的實戰課程。播放器是全局組件,放在下面,通過傳遞數據,觸發提交,從而使播放器開始工作。將請求的數據格式化后再通過傳遞,組件間共享,實現歌曲的播放切換等。 概述 項目是基于Vue.js,成品是一個移動端的音樂播放器,來源于imooc的實戰課程。自己動手實踐并加以修改拓展。項目的大致流程是Vue-cli構建開發環境,分析需求,設計構思,規...
這篇文章為大家講如何用JSd代碼實現音樂播放。 音樂播放的主要js代碼 音樂數據的數組對象 這里不僅有前端網頁提供數據,還有為后面的js代碼提供了音樂路徑,分享給大家。 { ablum:"海闊天空", artist:"Beyond", id:1, name:"大地", path:"musics/1...
摘要:前言本文的前身是源自上的項目但由于該項目上次更新時間為年月日,很多內容早已過期或是很多近期優秀組件未被收錄,所以小肆今天重新更新了內容并新建項目。提交的項目格式如下項目名稱子標題相關介紹如果收錄的項目有錯誤,可以通過反饋給小肆。 前言 本文的前身是源自github上的項目awesome-github-vue,但由于該項目上次更新時間為2017年6月12日,很多內容早已過期或是很多近期優...
閱讀 1674·2021-11-15 11:37
閱讀 3407·2021-09-28 09:44
閱讀 1648·2021-09-07 10:15
閱讀 2784·2021-09-03 10:39
閱讀 2686·2019-08-29 13:20
閱讀 1290·2019-08-29 12:51
閱讀 2204·2019-08-26 13:44
閱讀 2124·2019-08-23 18:02