摘要:豆瓣電影版用全家桶仿寫豆瓣電影版。原計(jì)劃仿寫完所有頁面,礙于豆瓣的接口有限,實(shí)現(xiàn)頁面也有限。由于公開的豆瓣接口具有訪問次數(shù)限制,克隆到本地體驗(yàn)效果更加端訪問已設(shè)置寬度適配。
douban-movie(豆瓣電影wap版)
用vue全家桶仿寫豆瓣電影wap版。
最近在公司項(xiàng)目中嘗試使用vue,但奈何自己初學(xué)水平有限,上了vue沒有上vuex,開發(fā)過程特別難受。
于是玩一玩本項(xiàng)目,算是對相關(guān)技術(shù)更加熟悉了。
原計(jì)劃仿寫完所有頁面,礙于豆瓣的接口API有限,實(shí)現(xiàn)頁面也有限。
由于公開的豆瓣接口具有訪問次數(shù)限制,克隆到本地體驗(yàn)效果更加!
web端訪問已設(shè)置寬度適配。
進(jìn)入GitHub查看本項(xiàng)目源碼
歡迎issue,pr,star or follow!我將繼續(xù)開源更多有趣的項(xiàng)目!
推薦一些之前寫的新手入門項(xiàng)目
wx-audio(微信小程序:音樂播放器)
paintCanvas(vue實(shí)現(xiàn)的你畫我猜)
css-grid-flex(關(guān)于css的grid布局和flex布局的入門心得)
在線版點(diǎn)擊進(jìn)入
部分效果截圖 工具&技能vue + vuex+ vue-router全家桶
webpack + webpack-dev-server + http-proxy-middleware進(jìn)行本地開發(fā)環(huán)境http請求轉(zhuǎn)發(fā),實(shí)現(xiàn)跨域請求
線上使用express的http-proxy-middleware實(shí)現(xiàn)請求轉(zhuǎn)發(fā)
iView一款vue的組件庫
vue-lazyload實(shí)現(xiàn)圖片懶加載
rem + flex + grid實(shí)現(xiàn)移動(dòng)端適配
http-proxy-middleware 一個(gè)http代理的中間件,進(jìn)行http請求轉(zhuǎn)發(fā),實(shí)現(xiàn)跨域請求
postman 接口測試工具
使用git clone https://github.com/xingbofeng/douban-movie.git cd douban-movie npm install npm run dev實(shí)現(xiàn)功能 首頁
[x] 影院熱映、即將上映、top250、北美票房榜
[x] 電影條目可橫向滾動(dòng)
[x] 預(yù)覽電影評(píng)分
搜索頁輸入搜索關(guān)鍵詞,回車鍵搜索,或者點(diǎn)擊搜索按鈕。
[x] 搜索功能
[x] 熱門搜索詞條的記錄
查看更多[x] 預(yù)覽電影評(píng)分
[x] 滾動(dòng)動(dòng)態(tài)加載
[x] 數(shù)據(jù)緩存入vuex
電影詳情[x] 電影評(píng)分
[x] 電影條目
[x] 演員列表
[x] 劇情簡介
[x] 數(shù)據(jù)緩存入vuex
搜索結(jié)果頁[x] 翻頁功能
[x] 圖片懶加載
[x] 預(yù)覽電影條目
[x] 本地緩存瀏覽信息
目錄結(jié)構(gòu)| |—— build |—— config |—— server 服務(wù)端 | |—— app.js 服務(wù)端啟動(dòng)入口文件 | |—— static 打包后的資源文件 | |__ index.html 網(wǎng)頁入口 | |——src 資源文件 | |—— assets 組件靜態(tài)資源庫 | |—— components 組件庫 | |—— router 路由配置 | |—— store vuex狀態(tài)管理 | |—— App.vue douban-movieSPA | |__ main.js douban-movieSPA入口 | |__ static 靜態(tài)資源目錄開發(fā)心得 如何緩存數(shù)據(jù)
這個(gè)問題在我之前的的項(xiàng)目總結(jié)已經(jīng)總結(jié)過。
加入我們有電影條目A、B、C三個(gè)電影條目詳情。進(jìn)入A加載A,進(jìn)入B加載B。此時(shí)也要把A緩存入vuex中。
可以類似于下面的寫法。
{ [`${A.id}`]: A, ...store.state }
具體代碼可見/src/router/routes下列相關(guān)文件
beforeEnter: (to, before, next) => { const currentMovieId = to.params.currentMovieId; if (store.state.moviedetail.currentMovie[`${currentMovieId}`]) { store.commit(types.LOADING_FLAG, false); next(); return; } store.commit(types.LOADING_FLAG, true); currentMovie(currentMovieId).then((currentMovieDetail) => { // 成功則commit后臺(tái)接口的數(shù)據(jù),并把NET_ERROR的數(shù)據(jù)置空,并把加載中的狀態(tài)置為false。 const id = currentMovieDetail.id; store.commit(types.CURRENT_MOVIE, { [`${id}`]: currentMovieDetail, ...store.state.moviedetail.currentMovie, }); store.commit(types.LOADING_FLAG, false); store.commit(types.NET_STATUS, ""); document.title = `${currentMovieDetail.title} - 電影 - 豆瓣`; }).catch((error) => { document.title = "出錯(cuò)啦 Oops… - 豆瓣"; store.commit(types.NET_STATUS, error); store.commit(types.LOADING_FLAG, false); }); next(); }翻頁加載
其實(shí)這個(gè)在之前的React項(xiàng)目中也有做過,設(shè)置一個(gè)currentPage的狀態(tài),然后根據(jù)這個(gè)狀態(tài)來渲染頁面。
具體代碼可見/src/containers/Tag.vue。
computed: { ...mapState({ tagData(state) { return state.tag.tagData[`${this.$route.params.currentTagId}`]; }, }), subjects() { return this.tagData.subjects.slice( (this.currentPage - 1) * 10, this.currentPage * 10, ); }, }, methods: { ...mapActions(["getMoreTagData"]), changePage(flag) { const currentTagId = this.$route.params.currentTagId; const { start, count } = this.tagData; // 第一頁不能往前翻頁,最后一頁不能往后翻頁。 if ((this.currentPage === 1 && flag === "reduce") || (this.currentPage === Math.ceil(this.tagData.total / 10) && flag === "add") ) { return; } if (flag === "add") { this.currentPage = this.currentPage + 1; // 每次請求十條數(shù)據(jù) this.getMoreTagData({ tag: currentTagId, count: 10, start: count + start, }); // 需要使用localStorge保存當(dāng)前的頁碼信息,再次進(jìn)入可以有這個(gè)頁碼信息。 const doubanMovieCurrentPage = JSON.parse(window.localStorage.doubanMovieCurrentPage); window.localStorage.doubanMovieCurrentPage = JSON.stringify({ ...doubanMovieCurrentPage, [`${currentTagId}`]: this.currentPage, }); } else { this.currentPage = this.currentPage - 1; } window.scrollTo(0, 0); },滾動(dòng)加載
類似于瀑布流布局的實(shí)現(xiàn)方式,當(dāng)用戶滾動(dòng)到距離頁面底部一定范圍的時(shí)候去請求后端接口。
具體代碼可見src/containers/More.vue。
handleScroll() { // 函數(shù)的作用是滾動(dòng)加載電影詳情信息 // 判斷是否為請求后臺(tái)中的狀態(tài),如果是則返回 const { start, count, total } = this.currentSeeMore; if (!this.requestFlag) { return; } // 不同瀏覽器top展現(xiàn)會(huì)不一致 let top = window.document.documentElement.scrollTop; if (top === 0) { top = document.body.scrollTop; } const clientHeight = document.getElementById("app").clientHeight; const innerHeight = window.innerHeight; const proportion = top / (clientHeight - innerHeight); // 但如果已把所有數(shù)據(jù)加載完畢了,則不請求 if (proportion > 0.6 && (start + count) < total) { this.getMoreData({ count, start: start + count, title: this.$route.params.title, }); this.requestFlag = false; } }滾動(dòng)節(jié)流
滾動(dòng)節(jié)流主要作用是控制滾動(dòng)事件的頻率,設(shè)置一個(gè)flag。未超過頻率則直接在函數(shù)中返回。
具體代碼可見src/containers/More.vue
scrolling() { // scrolling函數(shù)用于作函數(shù)節(jié)流 if (this.scrollFlag) { return; } this.scrollFlag = true; setTimeout(() => { this.handleScroll(); this.scrollFlag = false; }, 20); }
404與加載頁面的實(shí)現(xiàn)
這里主要是在vuex中設(shè)定兩個(gè)狀態(tài)。根據(jù)這兩個(gè)狀態(tài)返回不同的頁面。
具體代碼可見src/App.vue
在路由鉤子函數(shù)中改變狀態(tài)
之前在公司做React項(xiàng)目的時(shí)候運(yùn)用了universal-router,當(dāng)時(shí)我們可以在進(jìn)入路由的時(shí)候dispatch一個(gè)action改變狀態(tài),并且使用async/await函數(shù)實(shí)現(xiàn)異步。
貼一段之前的React代碼:
async action({ store, params }) { // 判斷store里的id和當(dāng)前id是否一致,若一致,則不請求后臺(tái) console.log("chapter") const chapterInfos = store.getState().home.chapterInfos; if (Object.keys(chapterInfos).length === 0 || chapterInfos.subject.id !== parseInt(params.chapter, 10)) { await store.dispatch(chapter(params.chapter)); } }
類似的,在vue中我們也可以這么做!
具體代碼可見/src/router/routes下的相關(guān)代碼
beforeEnter: (to, before, next) => { document.title = "電影 - 豆瓣"; if (Object.keys(store.state.home.homeData).length !== 0) { store.commit(types.LOADING_FLAG, false); next(); return; } store.commit(types.LOADING_FLAG, true); Promise.all([ hotMovie(8, 0), commingSoon(8, 0), top250(8, 0), usBox(8, 0), ]).then((homeData) => { // 成功則commit后臺(tái)接口的數(shù)據(jù),并把NET_ERROR的數(shù)據(jù)置空,并把加載中的狀態(tài)置為false。 store.commit(types.HOME_DATA, homeData); store.commit(types.LOADING_FLAG, false); store.commit(types.NET_STATUS, ""); }).catch((error) => { document.title = "出錯(cuò)啦 Oops… - 豆瓣"; store.commit(types.NET_STATUS, error); store.commit(types.LOADING_FLAG, false); }); next(); }Ajax的封裝
其實(shí)我就是不想用Ajax操作的相關(guān)庫罷了……
import serverConfig from "./serverConfig"; const Ajax = url => new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open("GET", url); xhr.send(null); xhr.onreadystatechange = () => { if (xhr.readyState === 4) { if (xhr.status === 200) { resolve(JSON.parse(xhr.responseText)); } else { reject(`錯(cuò)誤: ${xhr.status}`); } } }; }); // 影院熱映 export const hotMovie = (count, start) => Ajax(`${serverConfig}/v2/movie/in_theaters?count=${count}&start=${start}`); // 即將上映 export const commingSoon = (count, start) => Ajax(`${serverConfig}/v2/movie/coming_soon?count=${count}&start=${start}`); // top250 export const top250 = (count, start) => Ajax(`${serverConfig}/v2/movie/top250?count=${count}&start=${start}`); // 北美票房榜 export const usBox = (count, start) => Ajax(`${serverConfig}/v2/movie/us_box?count=${count}&start=${start}`); // 當(dāng)前電影詳情信息 export const currentMovie = currentMovieId => Ajax(`${serverConfig}/v2/movie/subject/${currentMovieId}`); // 當(dāng)前標(biāo)簽詳情信息 export const getTagData = (tag, count, start) => Ajax(`${serverConfig}/v2/movie/search?tag=${tag}&count=${count}&start=${start}`);代理的配置
為了解決瀏覽器跨域問題,需要在本地服務(wù)端配合實(shí)現(xiàn)請求轉(zhuǎn)發(fā)。
proxyTable: { "/v2": { target: "http://api.douban.com", changeOrigin: true, pathRewrite: { "^/v2": "/v2" } } },
實(shí)際環(huán)境中,服務(wù)器端配置
var express = require("express"); var proxy = require("http-proxy-middleware"); var app = express(); app.use("/static", express.static("static")); app.use("/v2", proxy({ target: "http://api.douban.com", changeOrigin: true, headers: { Referer: "http://api.douban.com" } } )); app.get("/", function (req, res) { res.sendFile(__dirname + "/index.html"); }); app.listen(3000);移動(dòng)端的適配
我們使用rem作單位,本項(xiàng)目中標(biāo)準(zhǔn)為1rem = 100px,適配750px設(shè)備。
瀏覽器執(zhí)行下列代碼,改變根元素的font-size,做到移動(dòng)端的適配。
(function (doc, win) { var docEl = doc.documentElement, resizeEvt = "orientationchange" in window ? "orientationchange" : "resize", recalc = function () { var clientWidth = docEl.clientWidth > 750 ? 360 : docEl.clientWidth ; if (!clientWidth) return; docEl.style.fontSize = clientWidth / 750 * 100 + "px"; }; if (!doc.addEventListener) return; doc.addEventListener("DOMContentLoaded", recalc, false); if (docEl.clientWidth > 750) return; win.addEventListener(resizeEvt, recalc, false); })(document, window);
文檔借鑒自我的同學(xué)ShanaMaid。
支持BUG提交請發(fā)送郵箱: [email protected]
歡迎issue,pr,star or follow!我將繼續(xù)開源更多有趣的項(xiàng)目!
你的支持將有助于項(xiàng)目維護(hù)以及提高用戶體驗(yàn),感謝各位的支持!
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/82652.html
摘要:閉包有多重前端知識(shí)點(diǎn)大百科全書前端掘金,,技巧使你的更加專業(yè)前端掘金一個(gè)幫你提升技巧的收藏集。 Vue全家桶實(shí)現(xiàn)還原豆瓣電影wap版 - 掘金用vue全家桶仿寫豆瓣電影wap版。 最近在公司項(xiàng)目中嘗試使用vue,但奈何自己初學(xué)水平有限,上了vue沒有上vuex,開發(fā)過程特別難受。 于是玩一玩本項(xiàng)目,算是對相關(guān)技術(shù)更加熟悉了。 原計(jì)劃仿寫完所有頁面,礙于豆瓣的接口API有限,實(shí)現(xiàn)頁面也有...
摘要:項(xiàng)目地址由于網(wǎng)易云的限制,部分功能可能會(huì)失效,如有需要可以項(xiàng)目下來在本地運(yùn)行,如果炸了,麻煩在評(píng)論中告知一下我因?yàn)樽龅氖嵌怂哉堅(jiān)陔娔X端訪問源碼地址項(xiàng)目預(yù)覽評(píng)論和歌單詳情都封了我的暫時(shí)無法使用這兩個(gè)功能了項(xiàng)目描述前端部分實(shí)現(xiàn)了滑塊彈出層歌詞 項(xiàng)目地址 由于網(wǎng)易云的api限制,部分功能可能會(huì)失效,如有需要可以clone項(xiàng)目下來在本地運(yùn)行,如果api炸了,麻煩在評(píng)論中告知一下我 因?yàn)樽龅?..
摘要:從之前黃軼老師的高仿外賣開始接觸過這個(gè)滾動(dòng)庫,感覺體驗(yàn)感很好,用起來也比較順手,所以在后來的項(xiàng)目聯(lián)系中就一直在使用。 前言 雖然在此之前已經(jīng)有類似的仿豆瓣電影的webapp,但或是開發(fā)的有些簡潔功能不太完善,或是體驗(yàn)感覺得可以再完善下,所以自己摸索著對比豆瓣和豆瓣電影兩款app做了一下,初步滿足了自己的想法,經(jīng)過幾次完善基本不會(huì)出現(xiàn)bug,如果發(fā)現(xiàn)存在問題請告訴我修改,謝謝! 2017...
摘要:前言之前一直在學(xué)習(xí)原生的,但是無奈功力太淺,學(xué)了很長時(shí)候也只能寫一些簡單的小,知道遇見了,一切都變了,他的雙向綁定和組件化思想讓我迅速的愛上了他,可是光學(xué)不練是沒有什么成就感的,想著豆瓣提供了免費(fèi)的接口,不如就利用這個(gè)接口做一個(gè)電影網(wǎng)站,想 前言:之前一直在學(xué)習(xí)原生的javascript,但是無奈功力太淺,學(xué)了很長時(shí)候也只能寫一些簡單的小demo,知道遇見了vue,一切都變了,他的雙向...
閱讀 3553·2021-09-08 10:46
閱讀 1205·2019-08-30 13:17
閱讀 2386·2019-08-30 13:05
閱讀 1221·2019-08-29 15:29
閱讀 2908·2019-08-29 11:31
閱讀 561·2019-08-26 12:13
閱讀 1557·2019-08-26 11:42
閱讀 1884·2019-08-23 18:37