成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Vue全家桶實(shí)現(xiàn)還原豆瓣電影wap版

Near_Li / 546人閱讀

摘要:豆瓣電影版用全家桶仿寫豆瓣電影版。原計(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,prstar 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)跨域請求

線上使用expresshttp-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]

歡迎issuepr,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

相關(guān)文章

  • 前端--通用知識(shí) - 收藏集 - 掘金

    摘要:閉包有多重前端知識(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)頁面也有...

    王笑朝 評(píng)論0 收藏0
  • Vue.js全家還原網(wǎng)易云音樂(Windows PC)

    摘要:項(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)樽龅?..

    sf_wangchong 評(píng)論0 收藏0
  • Vue2.0開發(fā)仿豆瓣電影WebApp

    摘要:從之前黃軼老師的高仿外賣開始接觸過這個(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...

    gplane 評(píng)論0 收藏0
  • vue開發(fā)一個(gè)貓眼電影web app

    摘要:前言之前一直在學(xué)習(xí)原生的,但是無奈功力太淺,學(xué)了很長時(shí)候也只能寫一些簡單的小,知道遇見了,一切都變了,他的雙向綁定和組件化思想讓我迅速的愛上了他,可是光學(xué)不練是沒有什么成就感的,想著豆瓣提供了免費(fèi)的接口,不如就利用這個(gè)接口做一個(gè)電影網(wǎng)站,想 前言:之前一直在學(xué)習(xí)原生的javascript,但是無奈功力太淺,學(xué)了很長時(shí)候也只能寫一些簡單的小demo,知道遇見了vue,一切都變了,他的雙向...

    habren 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<