• Stars
    star
    149
  • Rank 248,619 (Top 5 %)
  • Language Vue
  • License
    MIT License
  • Created over 7 years ago
  • Updated about 6 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

🎥The douban-movie Application built with webpack + vue + vuex + vue-router + iView.

douban-movie

downloads-image npm-image travis-image appveyor-image codeship-image david-dm-image david-dm-dev-image

It is the douban-movie Application built with webpack + vue + vuex + vue-router + iView.

中文文档

because the limit of open API is 40 times / minute.I recommended you clone this project to you own local environment.

Enter GitHub to see code!

Thanks for you support, waiting for your issue, pr, star or follow!I will release more interesting project in the future!

Online

Click Here

Or you can clone this project to you own local environment, then enjoy this project online:

git clone https://github.com/xingbofeng/douban-movie.git

cd douban-movie

yarn install

yarn run server

Then open your browser, and go to http://localhost:3000/ to enjoy it!

Development

git clone https://github.com/xingbofeng/douban-movie.git

cd douban-movie

yarn install 

yarn run dev

Then open your browser, and go to http://localhost:8080/ to enjoy it!

Preview

Technology stack

  • vue + vuex+ vue-router vue based project
  • webpack + webpack-dev-server + http-proxy-middleware dev environment we use webpack-dev-server and http-proxy-middleware.
  • express + http-proxy-middleware online we use express and http-proxy-middleware
  • iView UI components library
  • vue-lazyload help us lazyload images
  • rem + flex + grid responsive layout in mobile
  • yarn package manager.
  • postman test our interface

Functions

src/containers/Home.vue

  • hot-movie, comming-soon, top250 and us-box.
  • horizontal scrolling.
  • preview the score of the movie.

src/containers/Search.vue

You should input some word which is you want to search, then press Enter and begin to search, or you can click the button of search.

  • search.
  • save the hot search record.

src/containers/More.vue

  • preview the score of the movie.
  • loading when you scroll.
  • save the data you accessd to vuex.

src/containers/MovieDetail.vue

  • score of the movie.
  • information of the movie.
  • actors list.
  • the plot.
  • save the data you accessd to vuex.

src/containers/Tah.vue

  • turn the page.
  • lazyload images.
  • preview the information of the movie.
  • cache your browsing.

Directory

|
|—— build 
|—— config
|—— server
| |—— index.js : the entry of the server.
| |—— static/ : static files after packaging.
| |__ index.html : the entry of this application.
|
|——src : dev resources.
| |—— assets : images
| |—— components/
| |    |____ Common/ : reusable components
| |    |____ ... : other components of the own page.
| |
| |—— router/
| |    |____ index.js : the entry of router.
| |    |____ server.js : export ajax function.
| |    |____ serverConfig.js : export the server detail.
| |    |____ routes/ : every page's router, changing the state of `vuex` at its lifecycle function.
| |
| |—— store : vuex
| |—— App.vue : douban-movieSPA
| |__ main.js : the entry of douban-movieSPA
|
|__ static : static files

What did I learnt in this project?

How to save data in vuex?

{
  [`${A.id}`]: A,
  ...store.state
}

see the codes of /src/router/routes.

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后台接口的数据,并把NET_ERROR的数据置空,并把加载中的状态置为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 = '出错啦 Oops… - 豆瓣';
    store.commit(types.NET_STATUS, error);
    store.commit(types.LOADING_FLAG, false);
  });
  next();
}

How to turn the page and load?

We set a state named currentPage,everytime we change this state, the page will rerender.

see the codes of /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;
      // 每次请求十条数据
      this.getMoreTagData({
        tag: currentTagId,
        count: 10,
        start: count + start,
      });
      // 需要使用localStorge保存当前的页码信息,再次进入可以有这个页码信息。
      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);
  },

How to scroll and load?

like the waterfall layout,when user scroll to some location , we request the data form back-end.

see the codes of src/containers/More.vue

handleScroll() {
  // 函数的作用是滚动加载电影详情信息
  // 判断是否为请求后台中的状态,如果是则返回
  const { start, count, total } = this.currentSeeMore;
  if (!this.requestFlag) {
    return;
  }
  // 不同浏览器top展现会不一致
  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);
  // 但如果已把所有数据加载完毕了,则不请求
  if (proportion > 0.6 && (start + count) < total) {
    this.getMoreData({
      count,
      start: start + count,
      title: this.$route.params.title,
    });
    this.requestFlag = false;
  }
}

How to throttle when user scroll?

To implementation throttle of scrolling, we set a flag.when flag === true, we return the scroll function.

see the codes of src/containers/More.vue.

scrolling() {
  // scrolling函数用于作函数节流
  if (this.scrollFlag) {
    return;
  }
  this.scrollFlag = true;
  setTimeout(() => {
    this.handleScroll();
    this.scrollFlag = false;
  }, 20);
}

404 and loading

set two states in vuex.

see the codes of src/App.vue

<template>
  <div id="app">
    <net-error
      v-if="netStatus"
      :netStatus="netStatus"
    />
    <loading
      v-else-if="!netStatus && loadingFlag"
    />
    <router-view v-else></router-view>
  </div>
</template>

How to change the asynchronous state?

We often use universal-router in Reactproject.in that case, we can dispatch an action to change the state of redux, when we entry/change the router, and we use async/await fuction.

Like this code of React:

async action({ store, params }) {
  // 判断store里的id和当前id是否一致,若一致,则不请求后台
  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));
  }
}

And in this project, I had imitated it!

see the codes of /src/router/routes

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后台接口的数据,并把NET_ERROR的数据置空,并把加载中的状态置为false。
    store.commit(types.HOME_DATA, homeData);
    store.commit(types.LOADING_FLAG, false);
    store.commit(types.NET_STATUS, '');
  }).catch((error) => {
    document.title = '出错啦 Oops… - 豆瓣';
    store.commit(types.NET_STATUS, error);
    store.commit(types.LOADING_FLAG, false);
  });
  next();
}

Ajax

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(`错误: ${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}`);
// 当前电影详情信息
export const currentMovie = currentMovieId =>
  Ajax(`${serverConfig}/v2/movie/subject/${currentMovieId}`);
// 当前标签详情信息
export const getTagData = (tag, count, start) =>
  Ajax(`${serverConfig}/v2/movie/search?tag=${tag}&count=${count}&start=${start}`);

How to set proxy?

In dev environment we use webpack-dev-server and http-proxy-middleware, and online we use express and http-proxy-middleware.

proxyTable: {
  '/v2': {
    target: 'http://api.douban.com',
    changeOrigin: true,
    pathRewrite: {
      '^/v2': '/v2'
    }
  }
},
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);

Responsive layout in mobile

Use rem! In this project 1rem = 100px!

The browser run the codes following,change the font-size of the document.

<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no">
(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);

Chinese document referencing my friend ShanaMaid!

Support

Thanks for you support,being glad for your star, pr, follow and issue.

When you see bugs.You can mail to me! [email protected] !

More Repositories

1

xingbofeng.github.io

counterxing的博客
JavaScript
174
star
2

wx-audio

🎵 A music-player built with weixin platform.
JavaScript
164
star
3

css-grid-flex

📖An introduction about grid and flex of css.
CSS
126
star
4

JavaScript-design-patterns

暑期任务系列之精读《JavaScript设计模式与开发实践》
HTML
65
star
5

cornerstone-chinese-document

cornerstone( https://github.com/cornerstonejs/cornerstone )中文文档,用代码挽救生命,为天朝医学做一点微小的工作!
60
star
6

terminal-chat-robot

👽A chat-robot which runs in terminal.
JavaScript
43
star
7

webpack-jQuery-cli

📦基于webpack的jQuery脚手架,快速进行移动端的jQuery页面开发。
JavaScript
20
star
8

vuex-typescript-commit-dispatch-prompt

vuex typescript commit dispatch prompt
TypeScript
17
star
9

simple-virtual-dom

a simple virtual dom
JavaScript
11
star
10

Reading-Note

Reading Note of Encounter.
11
star
11

gallery-by-react

🌞A gallery based on React.js
JavaScript
7
star
12

protobuf-to-ts-api

通过protobuf文件,自动你的生成ts定义文件和api请求文件。
TypeScript
5
star
13

vue-draw-something

🎨It is the draw-something Application. Front-End is built with Vue.js, and Back-End will be build with Node.js and Python3.
JavaScript
4
star
14

getShell-by-modation

👏通过generator-modation在浏览器中打开linux命令行的小应用
JavaScript
4
star
15

weight-event-emmitter

一个好用的带权重的事件监听器
JavaScript
3
star
16

generator-naive

generator-naive:a Node.js generator based on yeoman!
JavaScript
2
star
17

UNP-reading

阅读《UNP》(《UNIX网络编程》)的读书笔记
1
star
18

vue-music-player-SPA

🎵 A Vue Audio Player.
JavaScript
1
star
19

vue-one

📖The One Reading Application based on vue.js.
JavaScript
1
star
20

cpu-bound-demo

Node.js cpu-bound-demo
JavaScript
1
star
21

message-by-modation

😡基于generator-modation的一个小型留言板
JavaScript
1
star