堆積了兩天一起發的,先祝大家節日快樂 後面任務很繁重,還有登錄註冊組件還有後臺管理頁面,真的繁重,我現在感覺每天全天時間都在學都不一定學得完,主要想在六月一號之前把整個項目過一遍。看看能不能創造奇跡 一.防抖和節流 拋出一個問題,就是我們的三級聯動,正常情況你慢慢的去滑動是沒有bug的,但是當你快速 ...
堆積了兩天一起發的,先祝大家節日快樂
後面任務很繁重,還有登錄註冊組件還有後臺管理頁面,真的繁重,我現在感覺每天全天時間都在學都不一定學得完,主要想在六月一號之前把整個項目過一遍。看看能不能創造奇跡
一.防抖和節流
拋出一個問題,就是我們的三級聯動,正常情況你慢慢的去滑動是沒有bug的,但是當你快速的從上往下滑一圈,你會發現只會觸發幾個標題,如果這個時候我們的回調也就是滑動的事件函數裡面有大量的業務邏輯,他會執行完一個再去執行另一個,但是你已經滑完很久了,所以這個時候頁面就會有卡頓現象
1.防抖
什麼是防抖?防抖就是一個事件觸發多次,最終只會有觸發一次的結果。
我們這裡防抖和節流採用一個 Lodash的插件來完成,但是自己也要懂防抖和節流的一個原理,首先防抖大概封裝是這樣的,定義一個函數,接受的參數為我們事件的回調和定時器的等待時間,裡面先清除一個定時器,然後定義一個定時器,定時器裡面調用我們的事件回調,當我們事件觸發就去執行這個防抖函數,意思就是比如我們有一個鍵盤輸入事件,當我們一輸入就會清除定時器,在執行定時器,定時器裡面的回調才會列印輸出我們輸入的內容,要等個500ms,那麼在這500ms之內你再次輸入,又不會列印輸出了因為定時器被清除了,又會重新計時500ms,這就是防抖的一個思想。
註意這個clear只能寫在函數的外面
2.節流
防止觸發頻率過快,在一個時間段內只執行一次。
一定要把防抖和節流做一個區別:防抖是可以觸發n次,但是只會以你不觸發後的最後一次為準,而節流是可以觸發n次,但是限制了你的觸發頻率,所以n次內其實只觸發了不到n次
自己封裝就像這樣,需要一個節流閥flag,當我點擊一次去判斷節流閥,判斷成功進來先把節流閥關閉,在執行定時器,單位時間內執行完節流閥才會打開,所以這段時間,你怎麼點擊都執行不了回調,這裡不需要清除定時器,因為定時器會自動到時間就結束
3.三級聯動節流
首先要註意一點,vue腳手架預設是給你安裝好了lodash
怎麼來用具體可以參照他的中文文檔,它有兩種引入方式,以節流為例,在文檔裡面找到_.throttle,最主要的是引入如果是全部引入,因為他還有很多的方法,數組求和等等,直接以_命名他
然後用的時候就像官網文檔一樣用
但是我們這裡如果就想用一下節流就沒必要全部導入了,直接導入我們想要的節流,註意怎麼導入的,在lodash找到throttle
然後用的時候也是直接用,還要註意一下這裡要回歸原始的es5的鍵值對的形式才可以使用這個節流
二.三級聯動組件路由跳轉
當我們呢點擊三級聯動的一二三級標題的時候,可以實現跳轉到search頁面,並且會把自己的id和標題當成參數傳過去,所以這裡就涉及到,路由的跳轉,我們的這些標題又剛好是a標簽用一個router-link就可以跳轉過去,但是這樣做會有一點不完善,因為我們一級標題還好後面二級三級那麼多,每一個都轉換為router-link,這個組件標簽又是vue內部提供的,去點擊一次還要進入vue內部處理一次,就會造成頁面卡頓
那麼就只有採用編程式跳轉了,其實這裡編程式跳轉也不太好,為什麼?我們每一個a標簽都要來一個點擊事件,是不是跟上面這種情況差不多了
這裡最好的解決辦法是,用編程式路由導航➕事件委托來做,我們給他們共同的父元素來一個點擊事件,他們的父元素只有一個不就可以解決了嗎
現在就要去解決一些問題了
-
第一個問題:我們下麵這麼多元素,怎麼就能確保點擊的是a標簽?
我們可以把每一級標題添加一個自定義屬性data-categoryName,當我們點擊的時候再通過e.target.dataset.categoryName來判斷點擊的元素是否是a標簽
-
第二個問題:怎麼來區分點擊的是一級、二級還是三級標題,因為我們傳過去的參數有id1、id2、id3,這裡做一下改造,將我們前面獲取到的自定義屬性採用解構賦值,註意一下,我們雖然自定義屬性是駝峰命名,但是最終到頁面會給你轉化為小數 ,為一個變數
我們給每個標題同樣通過自定義屬性給他們的id給到,同時以解構賦值接受給變數
得到參數之後,因為我們是編程式導航嘛,所以最終肯定是要通過push方法傳出去值的,判斷為a標簽後定義一個對象裡面放的是要跳轉的地址也就是search,然後依次判斷是否是id1,是就來個query的對象裡面正常寫一般寫在push裡面query裡面的參數形式,最後都判斷完了,把query對象放到跳轉地址這個對象裡面,直接push即可
三.search模塊商品分類
將三級聯動全局組件直接拿過來,然後給三級聯動來一個條件渲染,預設為true
這裡要考慮一點,當我們進入home那麼在search裡面的組件就會被銷毀,當我們進入search,在home裡面的組件就會被銷毀,所以當我們切換到search的時候,typenav的mounted又會被執行一次,那麼我們就可以把邏輯寫在這裡,就是當$route.path!=home這個時候就把條件改為false
然後滑鼠移入分類,又改為true
移出可以接著上次在共同父級設置的移出這裡做,同樣還是要判斷一下是不是home頁面,因為home不能隱藏
1.過渡動畫
回顧一下過渡動畫,要寫vue的過渡動畫必須有一個前提 那就是必須要有v-for或者v-show,由transition標簽包裹,然後可以寫自己的name,css部分name-enter,name-enter-to,離開是leave,最後時間以及要變化哪些都寫在active裡面
四.三級聯動列表優化
現在還有什麼優化的地方,有一個地方,我們剛纔說過,切換一次路由,裡面的所有組件都會被銷毀,包括三級聯動組件,所以頻繁切換,三級聯動也在頻繁銷毀頻繁執行mounted,而我們的mounted裡面寫了一個東西,dispatch派發到vuex裡面的actions,並且這裡還有邏輯處理,就是發送了ajax請求,所以問題就出現在這裡,我們切換一次路由組件,就會發送一次ajax請求,但針對於這裡來說,這裡三級聯動的請求,只需要一次就夠了,也沒有改,所以就需要換位置,他的統計都不只是只執行一次,繼續往父級走,那就是App組件,就寫在這裡,因為app組件只會執行一次,在這裡派發到actons,typenav需要的時候就state來取就是
五.合併參數
就是將我們的query和我們的params參數合併起來。
這裡主要是考慮兩種場景,一個是點擊搜索會有params的參數,這個時候我點擊分類標題會將他的query參數合併上去。因為我們是後點的三級聯動列表,所以邏輯應該在後點這裡合併上去
然後還有一種場景,我已進入主頁就由三級聯動標題進入搜索頁,然後我再根據搜索頁去搜索更加詳細的查找內容,這個時候後點的是header裡面的搜索按鈕,所以邏輯在header組件去做
六.mockjs模擬數據
因為我們現在首頁組件當中除了三級聯動後面的業務沒有介面,包括輪播圖等,這個時候就需要一個模擬數據,mockjs是一個插件,專門用來生成數據,攔截ajax請求
1.創建數據
使用方法:
-
首先src創建一個mock文件夾
-
第二步開始創建假數據,我們的數據都是json格式,所以直接在mock裡面創建json文件,放入數據,註意格式化一下,不能留有空格,不然跑不起來
這是輪播圖的模擬數據,註意點mock數據需要的圖片要放到public文件夾下,因為只有public下麵的文件打包的時候才會原封不動輸送出去
-
第三步創建mockServer.js通過mockjs來模擬出數據
註意引入Mock名字必須是大寫首字母,它是一個對象,後面引入兩個json文件,為什麼沒有export,這裡可以直接導入?因為webpack是預設對圖片、json文件導出的,這些文件是預設導出的,不用export
-
然後就可以調用Mock裡面的mock方法,兩個參數,第一個是請求路徑,第二個是請求數據
-
然後我們的mockServer.js文件需要在入口文件引入,表示至少需要執行一次,我們的模擬數據才會出現,這裡不需要暴露,直接在入口文件引入這個js文件,表示直接執行
2.應用數據
這樣一來我們的模擬數據就創建好了,接下來就是怎麼來用他的問題了。
他雖然不會發起真正的ajax請求,會被瀏覽器攔截,但是可以把他當做真正的請求看,所以第一步我們先去介面統一管理裡面,給他來一個請求和響應的攔截器,並且用axios創建一個他的實例,而且baseurl要為/mock
然後去介面統一管理處,創建一個獲取banner的介面函數
這個時候回到我們需要輪播圖的組件,給他的mounted派發actions,把我們的數據用vuex管理起來,同時在actions獲取ajax請求
去actions發起ajax請求
可以在列印台看到,我們確實得到了數據,最重要的一點沒有網路請求,這就是ajax的攔截
這個時候mutations將我們的數據給上,同時state定義一個數組裝這個數據
在我們輪播圖組件拿到這個數據,通過計算屬性
3.輪播圖(方案一)
我們用swiper實現輪播圖功能
-
第一步下載導入,swiper需要導入兩個,一個是css樣式,由於我們下麵的組件也會用到這個樣式,所以直接導入在入口文件,還有一個是js哪裡要用就導入在哪
-
實現swiper輪播圖第二步就是要定義好結構,結構這裡最重要的是用我們的mock模擬出來的數據,列表渲染出來
-
這個時候可以去用她的js邏輯了,但是要想一下這個定義在哪裡,有一個很重要的前提,new Swiper首先必須頁面上有這些結構,如果我們把new Swiper寫在mounted,這個時候頁面上確實有結構了,但是我們的列表迴圈裡面的bannerList是通過ajax得來的,要知道ajax是典型的的非同步函數,所以當我們開始new的時候,圖片這些數據還沒有開始遍歷的,這個時候結構就不完整,輪播圖的實現就有問題
這裡有一個比較笨的解決方法,就是開一個定時器,將new swiper放在裡面
4.輪播圖(方案二)
這也是最佳的完美解決方案,我們首先可以通過watch來做,去觀察bannerList的值,當他發生變化就已經代表了ajax請求回來了,所以這個時候再去new swiper
當然只是這樣還是不夠,為什麼?這個時候我們的bannerList確實有值了,非同步操作也已經完成了,但是這個時候要把這些數據拿去v-for列表迴圈又需要一定的等待時間,這個時候你直接去new了,其實頁面上的結構還是沒有的,這裡真正完美的做法是watch+nextTick來做
nextTick:官網的解釋在下次 DOM 更新迴圈結束之後執行延遲回調。在修改數據之後立即使用這個方法,獲取更新後的 DOM。
其意思就是當DOM完全呈現之後包括迴圈結束之後才會去執行nextTick的回調函數
七.floor組件模擬數據
又要給一個組件動態渲染數據了,由於前面已經通過mock模擬出來了數據,這個時候需要先將數據的介面寫進介面統一管理
然後vuex三部曲走起,因為我們的介面請求都是在actions裡面來做的
這個時候我們應該去去派發actions了,但是我們先觀察一下這個數據的結構,它是一個數組裡面有兩個對象,而我們的floor這個組件當時也復用了兩次,說明是不同的兩個對象,如果我在floor組件裡面去派發actions到時候來的數據就是一個數組有兩個對象,你用這個也不行用那個也不行,都體現不了復用性,這裡應該在他們父級也就是放他們組件標簽處來接收數據,並且通過v-for遍歷組件標簽
接下來遍歷我們的floor組件標簽,同時父傳子,通過props把屬於他們自己的那個對象傳過去
1.floor數據渲染
註意點:
- swiper5及以前的版本最大的容器叫做swiper-container不是現在官網上的swiper
-
還有一個點我這裡直接在floor組件的mounted函數裡面new swiper是可以實現的,為什麼?
要知道當時不能實現是因為在mounted裡面還發了ajax這個非同步操作請求,所以那個時候接著來一個new swiper是沒有完整結構的,但是在這裡我們的ajax是在父級home這個組件完成的,並且都已經把數據通過props發過來了,你在floor裡面也沒有影響結構的非同步了,所以直接在這裡的mounted new swiper就沒問題
八.共用組件carousel
當我們開發項目時,如果看到某一個組件在很多地方都使用,而且結構包括邏輯這些都一樣的話,就可以拆分為全局組件,大家直接復用,就比如這裡的上下兩個輪播圖。
當然大的輪播圖是用watch來做的,我們也可以把小輪播圖用watch來做,你會發現監視不了這個數據
因為我們這個數據是父組件派發然後傳過來的,可以說過來的時候就已經是那個樣子了,從沒有變過,沒有變動還怎麼去監視,這裡可以添加immediate讓監視屬性一開始就監視一次。
既然是一開始就執行,那時候肯定floor也為空,不然怎麼會監視到數據變化,所以還是要配合nextTick讓數據都有了到DOM上了再來new
這樣我們就開始拆分組件了,全局組件放在components下麵,關鍵步驟在於我們需要接受一個從外部傳進來的輪播圖數據,並且全局組件監聽的就是他
然後在我們模板上遍歷的也是他
註冊全局組件
將我們的組件標簽運用上,同時將數據傳過來
九.Search模塊
1.靜態組件
完成一個組件開發,還是那個套路顯示靜態頁面完成,然後拆分組件,發請求,vuex三部曲,組件獲取數據並渲染出來
2.Search模塊vuex操作
我們已經完成了靜態組件以及拆分,下一步就是ajax的api請求,因為是api開頭的所以可以直接用封裝好的axios來獲取請求,但是還是要去介面統一管理封裝一下函數,因為這裡我們search搜索商品的參數很多,所以是用一個對象傳進來,而且正常的寫法data後面本身就是一個對象,所以這裡params傳進來的參數至少都是一個空對象
然後就可以去vuex三部曲,通過介面文檔可以看到,我們返回的結果是一個對象,所以這裡直接數據定義為對象形式,但是這裡還測試不了,用到了我們之前還沒怎麼用過的dispatch的第二個參數就是我們要傳進來的值
3.數據動態展示
我們可以看到獲取過來的數據有很多是數組形式的,這個時候就要用到 getters了,項目中的getters主要作用就是簡化倉庫中的數據,就是當我們state定義的數據裡面還嵌套多層數據,這個時候就可以用gettes來簡化,然後我們到時候用的話,就會簡便的多
所以把上面這個數組通過gettes來獲取,註意的是gettes可以接受一個參數,就是當前倉庫中的state
同樣也是寫在計算屬性裡面來獲取
然後我們就可以開始先把下麵商品詳情頁的數據動態展示了,先獲取getters
在我們getters裡面有一點要註意,雖然一般不會出現這種情況,就是怕別人沒有網了,這個時候我們沒有goodsList等這些數組,那麼用一個亦或語法讓其成為空數組以防網頁崩潰
4.根據不同參數獲取數據展示
要根據不同參數獲取數據展示,那我們就需要將mounted裡面發起ajax請求的派發封裝為一個函數
但是這裡發起一個空對象去搜索有點扯,我們需要把發給伺服器的參數整起來,看介面文檔可知,要發給伺服器的參數為一個對象,所以我們可以把這個參數定義在data裡面,然後再mounted之前傳進去參數,自然而然mounted掛載之後就會是我們從主頁通過點三級聯動及搜索頁面的詳情頁或者是從主頁通過搜索得來的詳情頁
當然我們不能就以這個數據發過去,所以在mounted,也就是dispatch之前將真正的參數傳進來,註意這裡用到一個es6新增對象的方法Object.assign,他可以合併多個對象,如果有相同的就以後面的值為準,沒有的就添加上最後形成一個新對象
5.search模塊子組件動態開發
既然我們都做了serach的搜索了,search裡面還有一個子組件,來展示品牌和一些標簽選擇的,這些數據也是順帶返回回來的所以順便就做了,因為這兩個數據是數組返回,所以直接getters,然後組件接受getters
6.再次請求獲取數據
為什麼要再次請求,因為我們剛纔做的版本只是在進入search這個組件由於重新掛載了,所以只能請求mounted那一次,如果我要繼續搜索呢?
這個時候,有一個關鍵的技術點,當我們每一次搜索或者點擊三級聯動列表的時候,我們的url是不是在變
而且以前我們都知道我們的響應數據一般是data裡面或者計算屬性裡面,通過vue管理者工具可以看到,我們的$route其實也是響應式數據
所以關鍵點就在於這裡,我們可以監聽$route,然後把參數來一次assign方法合併,再次dispatch即可做到重覆搜索的功能