vue 頭條 demo 寫在前面
總結(jié)一下寫 demo 過(guò)程中 遇到的一些問(wèn)題,方便自己的學(xué)習(xí)總結(jié)!如有錯(cuò)誤,還請(qǐng)指正!
一直想學(xué)習(xí)使用 vue ,并準(zhǔn)備以后在實(shí)際項(xiàng)目使用,之前跟著慕課網(wǎng) 黃軼 老師 敲了一下 餓了么商品購(gòu)買頁(yè)的demo
ele效果預(yù)覽
該 demo 借鑒自 hcy1996-github 這個(gè)項(xiàng)目,但內(nèi)部?jī)?nèi)容,布局風(fēng)格,完全不同,只為共同學(xué)習(xí),共同交流
數(shù)據(jù)接口 直接打開 今日頭條 網(wǎng)頁(yè)版 ,在 network 分析了下,直接 copy 過(guò)來(lái)的
還有很多功能沒(méi)有實(shí)現(xiàn),后期在完善吧!
項(xiàng)目地址:github-項(xiàng)目地址
預(yù)覽效果: demo預(yù)覽效果
建議在 chrome 瀏覽器查看(不知道為什么在手機(jī)上數(shù)據(jù)請(qǐng)求,一個(gè)勁卡死,不知道是不是因?yàn)榻袢疹^條接口的原因)
演示頭部添加 rem 布局
引入 reset.css
使用 阿里媽媽圖標(biāo)庫(kù),index.html 引入
使用 css 預(yù)處理器 sass安裝 node-sass sass-loader npm install node-sass sass-loader --save-dev
使用
參考文章: http://www.jianshu.com/p/67f52071657d
app.vue
底部導(dǎo)航欄欄 ==> 剛開始時(shí)用的 vux 的 tabbar tabbar-item 組件,發(fā)現(xiàn)有需求實(shí)現(xiàn)不了,剛開始還改了源碼,最后實(shí)在受不了了
就用 vue-router roter-link 自己寫了
底部導(dǎo)航欄 四個(gè)按鈕分別對(duì)應(yīng) 四個(gè)組件
由于自己對(duì) vue-router 理解還欠火候,所以遇到了一個(gè)問(wèn)題
routes 數(shù)組里面的內(nèi)容對(duì)應(yīng)的就是 組件 ,
path 選項(xiàng)對(duì)應(yīng)的是路由路徑,初始時(shí)沒(méi)有路由嵌套 即為 index
components 選項(xiàng)對(duì)應(yīng)該路由對(duì)應(yīng)的組件,由于組件已經(jīng)全部通過(guò) import 引入了,所以不需要寫路徑了
底部通用 tab 導(dǎo)航欄
本想多帶帶抽出一個(gè) bottom.vue 組件呢,但在左右切換的滑動(dòng)樣式中,表現(xiàn)并不好,因?yàn)橄M撞繉?dǎo)航欄不滑動(dòng)這才符合人的預(yù)期需求
所以最終還是選擇不抽離這個(gè)組件,直接寫在了 app.vue 里面了
通用樣式庫(kù) common scss 目錄 base.scss mixin.scss 通過(guò) 一個(gè) index.scss 導(dǎo)入
引入 axios ,由于 axios 不支持jsonp,所以還得引入 jsonp
npm install axios jsonp --save
在 common/js/ajax.js 下使用這兩個(gè)庫(kù)
import axios from "axios"
import jsonp from "jsonp"
將 ajax 請(qǐng)求,封裝在 一個(gè)通用的 js 文件里,方便統(tǒng)一處理 ajax
即前后端協(xié)作時(shí) 定義的一些返回值代表的意義,都可以在此方法里統(tǒng)一處理
遇到個(gè)問(wèn)題不知道怎么解決
我想有 loading.vue 組件,就是可以在通用的 ajax.js 文件里引用,
問(wèn)題是,我發(fā)現(xiàn) 當(dāng)加載 ajax.js 文件時(shí) ,loading.vue 組件 import 不進(jìn)來(lái)的,所以無(wú)法使用
但我又想要 當(dāng)用統(tǒng)一 ajax 處理的時(shí)候,統(tǒng)一執(zhí)行 loading
最終我想了一個(gè)下下策,把 loading組件的內(nèi)容直接寫在了index.html 文件里,這樣就可以加載到了,就可以在 ajax處理的時(shí)候集中使用 loading.vue 了
不僅 loading 組件,還有 通用彈框組件,(就是想在一個(gè)通用的 js 文件里,每次只要在使用的地方 import 這個(gè) js 文件,就能使用這些 通用組件,而不必每次都要 import 這些組件)
現(xiàn)在的解決辦法太渣,看以后能不能想到什么好的辦法
如果各位大大,有什么好的方法,希望能告知 小弟 一聲
index.vue 文件頂部 x-header 組件 ,感覺(jué)使用不夠靈活
不知道如何 自定義左右圖標(biāo)
因?yàn)?vux 的 icon 是引自 icon圖標(biāo)css庫(kù)
右側(cè)icon 是我引用 阿里媽媽圖標(biāo)庫(kù)里面的圖標(biāo)的
標(biāo)簽導(dǎo)航一欄 本來(lái)是用 vux 的scroller 組件寫的,但看到官方文檔上寫 ,此組件已不在維護(hù),且不建議開發(fā)者繼續(xù)使用
自己按著 demo 用了一下發(fā)現(xiàn)不知道 如何 refresh,就放棄了
自己 用 better-scroll 處理滾動(dòng) tab 標(biāo)簽欄橫線滾動(dòng)沒(méi)碰到問(wèn)題
新聞內(nèi)容列表滾動(dòng)也是用的 better-scroll 碰到了一個(gè)問(wèn)題,
下拉刷新的logo 總是無(wú)法藏在 列表后面,無(wú)論怎么設(shè)置 z-index
最后才發(fā)現(xiàn)問(wèn)題,自己還真的是蠢,列表容器沒(méi)寫背景顏色,自然永遠(yuǎn)都能看到loading圖標(biāo)
在糾結(jié)的過(guò)程中也發(fā)現(xiàn)了幾個(gè)問(wèn)題:
移動(dòng)端百分比布局時(shí):html,body一定要設(shè)置寬高百分比,不然會(huì)遇到很多坑
better-scroll 滾動(dòng)容器一定要有明確的寬高,建議最好用絕對(duì)定位,背景顏色,overflow:hidden
最大的一個(gè)坑,列表總是有一部分滾動(dòng)不上來(lái),碰到這個(gè)問(wèn)題,首先想到:
列表高度是否大于容器高度
refresh 時(shí)機(jī)不對(duì)最終,發(fā)現(xiàn)確實(shí)時(shí)是 refresh 時(shí)機(jī)不對(duì),
但接下來(lái)糾結(jié)的時(shí)刻到了,無(wú)論放在哪都不對(duì),最終寫了 setTimeout(fn,3000),可以正常工作,但這肯定不是解決辦法
最后想到:因?yàn)榱斜碇械膱D片容器高度,是靠圖片撐開的,但圖片加載的比較慢所以 better-scroll 計(jì)算不到準(zhǔn)確的高度,
解決辦法:圖片容器高度事先寫死,完美的解決了
圖片懶加載 vue-lazyload 插件,超好用
懶加載引用的圖片地址:loading 圖片
如果 在js 引用靜態(tài)圖片,因?yàn)閣ebpack 不會(huì)解析 js 文件里的圖片,
所以要用 import 引用 import logo from "./assets/loading.gif"
或是把圖片放在頂層的 static 目錄里
微信左右滾動(dòng)效果(切換底部tab時(shí))---以下是通用思路在 全局路由 beforeEach(function(to,from,next){***}) 鉤子里 要做下面的事情
假如待切換的組件為 index1,index2
在 sessionStorage 里面 創(chuàng)建 一個(gè) __router__ 值
__router__的值包括:count, transitionName , to.path ,from.path
count 初識(shí)值為 0;
transitionName 初始值為 ""
to.path 初始值為 undefined
form.path 初始值為 undefined
首次進(jìn)入時(shí) to.index(index1) 為空 執(zhí)行 else
count++
判斷 to.path !== "/" && history[to.path] = historyCount
history["transitionName"] = "forward"; 為前進(jìn)狀態(tài)
此時(shí): index1:1,count:1
二次 進(jìn)入(路由已跳轉(zhuǎn)過(guò)一次) 此時(shí) to.path 依舊 為 undefined ,而 from.path 為 to.path 的值
繼續(xù)走 else 里面,重復(fù)上面的步驟 此時(shí) index2:2,count2,index1:1
在繼續(xù)點(diǎn)第一個(gè) tab 相當(dāng)于回到第一個(gè) tab
此時(shí):to.path == index1, from.path == index2
假如 :!fromIndex || parseInt(toIndex) > parseInt(fromIndex
或:toIndex === "0" && fromIndex === "0"
為 forward 前進(jìn)狀態(tài)
否則: 為 reserve 后退狀態(tài)
這樣就能判斷是前進(jìn)狀態(tài)還是后退狀態(tài),就可以用樣式控制滾動(dòng)方向了
Do not bb ,show me code
router.beforeEach(function (to, from, next) { let history = window.sessionStorage.__router__; if(!history){ history = {}; }else{ history = JSON.parse(history); } let historyCount = history.count * 1; //記錄走過(guò)的 tab 頁(yè)數(shù)量 const toIndex = history[to.path]; // 要去的索引 const fromIndex = history[from.path]; //要離開的索引 if (toIndex) { if (!fromIndex || parseInt(toIndex) > parseInt(fromIndex) || (toIndex === "0" && fromIndex === "0")) { history["transitionName"] = "forward"; } else { history["transitionName"] = "reverse"; } } else { //第一次沒(méi)有記錄session-storage 的情況 ++historyCount; history["count"] = historyCount; to.path !== "/" && (history[to.path] = historyCount); history["transitionName"] = "forward"; } history = JSON.stringify(history); window.sessionStorage.__router__ = history; if (//http/.test(to.path)) { let url = to.path.split("http")[1]; window.location.href = `http${url}` } else { next() } });遇到問(wèn)題(2017-08-10)
當(dāng)?shù)谝淮芜M(jìn)入頁(yè)面時(shí) ,如果不是處在第一個(gè) tab 時(shí),history 里面記錄的索引就會(huì)出現(xiàn)錯(cuò)亂現(xiàn)象
解決辦法:事先設(shè)置好 首頁(yè)出現(xiàn)的四個(gè) tab 的索引,設(shè)置好 初始的 count 為 4
這樣就不會(huì)發(fā)生索引錯(cuò)亂現(xiàn)象
切換時(shí)的一個(gè)小問(wèn)題當(dāng)左右華東切換時(shí),要注意將各個(gè) tab 頁(yè)頂層設(shè)置 ,position:absolute,這樣才會(huì)排在同一排,否則會(huì)出現(xiàn)一上一下的現(xiàn)象
具體實(shí)現(xiàn)查看 github-項(xiàng)目地址 里面的 main.js app.vue通過(guò) watch 選項(xiàng)監(jiān)測(cè) $route 動(dòng)態(tài)的改變transitionName 的值
sessionStorage 和 localStorage 本地存儲(chǔ)問(wèn)題watch: { "$route" (to, from) { console.log(to,from); this.transitionName = JSON.parse(window.sessionStorage.__router__).transitionName; } }, 樣式: //微信切換樣式 ,左右滾動(dòng) //前進(jìn)動(dòng)畫樣式 .forward-enter-active,.forward-leave-active{ transition: all 0.3s; } .forward-enter{ transform: translateX(100%); } .forward-leave-to{ transform: translateX(-100%); } // 后退動(dòng)畫樣式 .reverse-enter-active,.reverse-leave-active{ transition: all 0.3s; } .reverse-enter{ transform: translateX(-100%); } .reverse-leave-to{ transform: translateX(100%); }
sessionStorage 本地會(huì)話存儲(chǔ),會(huì)話結(jié)束-瀏覽器關(guān)閉(不包括刷新頁(yè)面,恢復(fù)頁(yè)面),存儲(chǔ)結(jié)果清除
localStorage 本地存儲(chǔ),除非手動(dòng)清除,否則永不清除
大小傳說(shuō) 5M
方法1:getItem(key),setItem(key,value),clear()
方法2:利用 . 或 [] 語(yǔ)法,訪問(wèn)或設(shè)置
事件:
如果你監(jiān)聽storage變更事件你就會(huì)發(fā)現(xiàn),當(dāng)數(shù)據(jù)發(fā)生變化時(shí)本頁(yè)是監(jiān)聽不到storage事件變更消息的。而同域的其他打開的頁(yè)面反而監(jiān)聽到了該消息。悲劇不?
解決辦法百度
storage只能存儲(chǔ)字符串 不能存儲(chǔ)其他類型數(shù)據(jù)存儲(chǔ)對(duì)象,讀取對(duì)象:
let history = window.sessionStorage.__router__; if(!history){ history = {}; }else{ //讀取 history = JSON.parse(history); } //存儲(chǔ) history = JSON.stringify(history); window.sessionStorage.__router__ = history;activated 鉤子
在
keep-alive 組件在第二次渲染時(shí)不會(huì)觸發(fā) create mounted updated 鉤子
但是會(huì)觸發(fā) activated 鉤子
使用場(chǎng)景: 列表頁(yè)==> 詳情頁(yè)的切換
第一次從列表頁(yè)進(jìn)詳情頁(yè)時(shí)會(huì)加載數(shù)據(jù) 觸發(fā) created,mounted,updated 鉤子
第二次以上鉤子就不會(huì)被觸發(fā)了, 需要加上一個(gè) activated 生命周期鉤子,在里面加載請(qǐng)求數(shù)據(jù)
路由跳轉(zhuǎn)時(shí) 需要用到 動(dòng)態(tài)路由 即在 路徑后面加個(gè) id
我用query 進(jìn)行傳遞參數(shù),如果不主動(dòng)傳遞參數(shù),跳轉(zhuǎn)后的子頁(yè)面刷新時(shí)數(shù)據(jù)就丟失了(原計(jì)劃用 vuex 做收藏功能)
index.js {path: "/newsDetails/:key", name: "newsDetails",component:newsDetails },
導(dǎo)航寫法:
或者//路由外鏈
列表頁(yè) ==> 詳情頁(yè)
從列表頁(yè)到詳情頁(yè)不適合用嵌套路由嵌套路由寫法
因?yàn)槠涫莾蓚€(gè)多帶帶的頁(yè)面,并不會(huì)同時(shí)出現(xiàn)在一屏上
route.js
{path: "/index", name:"index", component: index, children:[ {path: "/index/newsDetails/:id", name: "newsDetails",component:newsDetails }, ] }
index.vue
路由傳參:to = ""index/newsDetails" + item.source_url"
不僅僅傳遞一個(gè)動(dòng)態(tài)路由id還可以 通過(guò) params 和 query進(jìn)行傳遞,但都會(huì)顯示在 url上
列表頁(yè) ==> 將該項(xiàng)所有參數(shù)傳遞到詳情頁(yè),可以現(xiàn)將對(duì)象數(shù)據(jù) 序列化為字符串,放在 query li
在詳情頁(yè)時(shí),取值時(shí)反序列化,繼而可以在詳情頁(yè)里面使用
由于數(shù)據(jù)是存在 url 里 故可以在刷新頁(yè)面仍可以拿到數(shù)據(jù)
路由小結(jié)路由中的三個(gè)基本概念: route routes router
route 一條路由(單條路由的走向) routes 一組路由(靜止的一組路由的集合)
router 是一種機(jī)制相當(dāng)于一個(gè)管理者(當(dāng)用戶點(diǎn)擊時(shí) 去 routes 去執(zhí)行相應(yīng)的路由)
普通路由
動(dòng)態(tài)路由
嵌套路由
編程式導(dǎo)航
組件內(nèi)的掛載到 根實(shí)例上的兩個(gè)對(duì)象 路由源信息對(duì)象: this.$route 和 路由實(shí)例對(duì)象 this.$router
父子組件通訊父組件 => 子組件
父組件傳遞:
簡(jiǎn)寫方式(直接傳值)數(shù)組形式 ==> : props:["flag"]
默認(rèn)值寫法: 對(duì)象形式
props:{ flag:{ type:Bollean, dafault(){ return false; } } }
子組件 ==> 父組件
v-on 綁定 子組件派發(fā)而來(lái)的事件
父組件接收:
-
methods:{ scroll_to(childmsg){ //執(zhí)行 。。。 childmsg 為子組件向父組件傳遞的參數(shù) } }
子組件
methods:{ xxx(){ this.$emit("scrolltoTop","aaa向父組件傳遞的參數(shù)") } }
注意不能直接使用 $on 監(jiān)聽子組件拋出的事件,而必須在模板里使用 v-on 綁定收藏頁(yè) ==> vuex
在詳情頁(yè)進(jìn)行 收藏/取消 操作
將該操作的數(shù)據(jù)存在 vuex 里,然后存在 localStorage 里,
store.js 里建一個(gè) newsItem字段,值為數(shù)組,然后通過(guò) mutations 操作,
向數(shù)組里添加或刪除元素
在收藏組件里進(jìn)行渲染
原計(jì)劃收藏頁(yè)的新聞是可以 收藏/取消收藏的收藏 存進(jìn)vuex,取消收藏從vuex里刪除
但今日頭條的數(shù)據(jù)結(jié)構(gòu)感覺(jué)有點(diǎn)亂
想著真實(shí)開發(fā)中,后臺(tái)肯定會(huì)返回一個(gè)字段告訴該條新聞本人是否已經(jīng)收藏過(guò)
只做了收藏,暫無(wú)取消收藏功能,收藏之后存進(jìn) vuex ==> localstorage
bug ==> 同一條新聞可重復(fù)收藏
vuex 操作流程
store.js
import Vue from "vue" import Vuex from "vuex" import mutations from "./mutations" Vue.use(Vuex); const store = new Vuex.Store({ state:{ //數(shù)據(jù)管理中心 count:0, }, mutations, //使用處進(jìn)行 commit getters:{ //外界在此處獲得 vuex 數(shù)據(jù) nowTime(state){ return new Date() - 0 + "-" + state.count; } } }); export default store;
mutations.js
//全局觸發(fā)事件 export default { increment (state){ // 只有通過(guò)此處的方法才能改變vuex 內(nèi)的數(shù)據(jù) state.count++; }, decrement (state){ state.count--; }, }
使用的時(shí)候 引入 import {mapState,mapMutations,mapGetters} from "vuex"
然后通過(guò) this.$store 對(duì)象進(jìn)行操作
vuex 待續(xù)。。。 處理資源js 引用圖片 必須用 import 導(dǎo)入 import logo.png from "相對(duì)路徑"
放在 src 目錄里的文件都是交由 webpack 處理的
放在 static 目錄里面的文件 webpack 不會(huì)處理,而是在 build 之后,直接拷貝 相應(yīng)目錄里
所以在 項(xiàng)目里如果要引用 static 目錄里的文件 必須要使用絕對(duì)路徑 /static/[filename]
main.js 里 引用 圖片懶加載 的加載中圖片時(shí) 路徑必須為 "./static/img/loading.gif"(我也不知道原因)
具體可參考此回答: vue static目錄資源使用
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/87403.html
摘要:這是用高仿今日頭條的移動(dòng)端項(xiàng)目,結(jié)合了原生的部分功能以及網(wǎng)頁(yè)版。前言本人是今日頭條的重度用戶,在學(xué)習(xí)過(guò)程中,在上看到了很多高仿的好項(xiàng)目。因?yàn)閿?shù)據(jù)原因,首頁(yè)請(qǐng)求的數(shù)據(jù)接口來(lái)自網(wǎng)頁(yè)版今日頭條,修改了一些參數(shù)收藏頁(yè)面數(shù)據(jù)由本地文件獲取。 vue-toutiao 這是用 vue.js 2.0 高仿 今日頭條 的移動(dòng)端項(xiàng)目,結(jié)合了原生app的部分功能以及網(wǎng)頁(yè)版。 前言 本人是 今日頭條 的重度用...
摘要:前言上次初學(xué)用寫了個(gè)后臺(tái)管理,這次便尋思寫個(gè)移動(dòng)端的項(xiàng)目。便有了這次的這個(gè)項(xiàng)目。然后通過(guò)來(lái)判斷如何動(dòng)畫具體處理異步用來(lái)書寫跟配置還有一些零零散散的知識(shí)點(diǎn),就不介紹了,具體可以到上查看。個(gè)人博客在線觀看地址 前言 上次初學(xué)用 react 寫了個(gè)后臺(tái)管理,這次便尋思寫個(gè)移動(dòng)端的項(xiàng)目。便有了這次的這個(gè)項(xiàng)目。 這個(gè)項(xiàng)目以前寫了個(gè) vue 的版本。有興趣的可以 點(diǎn)擊進(jìn)入 模擬數(shù)據(jù)用的是 Eas...
摘要:但由于這里僅僅是實(shí)現(xiàn)一個(gè),因此存儲(chǔ)功能僅通過(guò)一個(gè)單例類來(lái)模擬實(shí)現(xiàn)。 本文旨在通過(guò)重寫GridView,配合系統(tǒng)彈窗實(shí)現(xiàn)仿今日頭條的頻道編輯頁(yè)面 注:由于代碼稍長(zhǎng),本文僅列出關(guān)鍵部分,完整工程請(qǐng)參見(jiàn)【https://github.com/G9YH/YHChannelEdit】 在開始講解盜版的實(shí)現(xiàn)方案前,讓我們先來(lái)看看正版與盜版的實(shí)際使用效果對(duì)比,首先是正版 showImg(https:...
閱讀 1824·2021-10-20 13:49
閱讀 1363·2019-08-30 15:52
閱讀 2869·2019-08-29 16:37
閱讀 1038·2019-08-29 10:55
閱讀 3072·2019-08-26 12:14
閱讀 1655·2019-08-23 17:06
閱讀 3239·2019-08-23 16:59
閱讀 2549·2019-08-23 15:42