├── static
└── .gitkeep
├── src
├── assets
│ ├── .gitkeep
│ ├── icon
│ │ ├── iconfont.eot
│ │ ├── iconfont.ttf
│ │ ├── iconfont.woff
│ │ ├── iconfont.css
│ │ └── iconfont.svg
│ ├── header.sass
│ ├── common.sass
│ ├── detail.sass
│ ├── sidebar.sass
│ ├── film.sass
│ ├── loading.sass
│ ├── home.sass
│ ├── reset.sass
│ └── cinema.sass
├── components
│ ├── footer.vue
│ ├── loading.vue
│ ├── header.vue
│ └── sidebar.vue
├── main.js
├── vuex
│ ├── index.js
│ ├── modules
│ │ ├── detail.js
│ │ ├── com.js
│ │ ├── cinema.js
│ │ ├── home.js
│ │ └── film.js
│ ├── types.js
│ └── api.js
├── config
│ └── index.js
├── routers.js
├── pages
│ ├── detail.vue
│ ├── cinema.vue
│ ├── home.vue
│ └── film.vue
└── App.vue
├── .gitignore
├── config
├── prod.env.js
├── dev.env.js
└── index.js
├── readme_img
├── 1.png
├── film.png
├── home.png
├── cinema.png
├── detail.png
├── home_2.png
└── cinema_2.png
├── .babelrc
├── .editorconfig
├── index.html
├── package.json
└── README.md
/static/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/footer.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | dist/
4 | npm-debug.log
5 |
--------------------------------------------------------------------------------
/config/prod.env.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | NODE_ENV: '"production"'
3 | }
4 |
--------------------------------------------------------------------------------
/readme_img/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChuckCZC/vue-demo-maizuo/HEAD/readme_img/1.png
--------------------------------------------------------------------------------
/readme_img/film.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChuckCZC/vue-demo-maizuo/HEAD/readme_img/film.png
--------------------------------------------------------------------------------
/readme_img/home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChuckCZC/vue-demo-maizuo/HEAD/readme_img/home.png
--------------------------------------------------------------------------------
/readme_img/cinema.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChuckCZC/vue-demo-maizuo/HEAD/readme_img/cinema.png
--------------------------------------------------------------------------------
/readme_img/detail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChuckCZC/vue-demo-maizuo/HEAD/readme_img/detail.png
--------------------------------------------------------------------------------
/readme_img/home_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChuckCZC/vue-demo-maizuo/HEAD/readme_img/home_2.png
--------------------------------------------------------------------------------
/readme_img/cinema_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChuckCZC/vue-demo-maizuo/HEAD/readme_img/cinema_2.png
--------------------------------------------------------------------------------
/src/assets/icon/iconfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChuckCZC/vue-demo-maizuo/HEAD/src/assets/icon/iconfont.eot
--------------------------------------------------------------------------------
/src/assets/icon/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChuckCZC/vue-demo-maizuo/HEAD/src/assets/icon/iconfont.ttf
--------------------------------------------------------------------------------
/src/assets/icon/iconfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChuckCZC/vue-demo-maizuo/HEAD/src/assets/icon/iconfont.woff
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "stage-2"],
3 | "plugins": ["transform-runtime"],
4 | "comments": false
5 | }
6 |
--------------------------------------------------------------------------------
/config/dev.env.js:
--------------------------------------------------------------------------------
1 | var merge = require('webpack-merge')
2 | var prodEnv = require('./prod.env')
3 |
4 | module.exports = merge(prodEnv, {
5 | NODE_ENV: '"development"'
6 | })
7 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/src/components/loading.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Create by zechun.chen on 2016/12/22
3 | */
4 |
5 | import Vue from 'vue'
6 | import router from './routers'
7 | import store from './vuex'
8 | import './config'
9 |
10 | Vue.config.debug = true;
11 | //自定义滚动指令
12 | Vue.directive('scroll',{
13 | bind:function(el,binding){
14 | window.addEventListener('scroll',() => {
15 | let fnc = binding.value;
16 | fnc(el);
17 | })
18 | }
19 | })
20 | const app = new Vue({
21 | router,
22 | store,
23 | }).$mount('#app');
--------------------------------------------------------------------------------
/src/vuex/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Create by zechun.chen on 2016/12/22
3 | */
4 |
5 | import Vue from 'vue'
6 | import Vuex from 'vuex'
7 | import com from './modules/com'
8 | import home from './modules/home'
9 | import detail from './modules/detail'
10 | import cinema from './modules/cinema'
11 | import film from './modules/film'
12 |
13 | Vue.use(Vuex)
14 | const store = new Vuex.Store({
15 | modules:{
16 | com,
17 | home,
18 | detail,
19 | cinema,
20 | film
21 | },
22 | strict:process.env.NODE_ENV !== 'production'
23 | })
24 |
25 | export default store;
--------------------------------------------------------------------------------
/src/assets/header.sass:
--------------------------------------------------------------------------------
1 | @import 'common'
2 | #header
3 | background: #282828
4 | color: #999
5 | position: fixed
6 | z-index: 500
7 | width: 100%
8 | height: 50*$px
9 | line-height: 50*$px
10 | @include box(justify,center)
11 | a
12 | display: block
13 | .go-menu,.go-mine
14 | width: 50*$px
15 | text-align: center
16 | height: 48*$px
17 | .go-menu
18 | border-right: 1px solid #222
19 | box-shadow: 1px 0 1px #363636
20 | .title
21 | width: 274*$px
22 | font-size: 16*$px
23 | @include box(justify,center)
24 | a
25 | i
26 | margin-left: 5*$px
27 | font-size: 12*$px
28 | p
29 | color: #fff
30 |
--------------------------------------------------------------------------------
/src/assets/common.sass:
--------------------------------------------------------------------------------
1 | $assetPath : "../img"
2 | $v : 5
3 | //px转rem
4 | $px: 1rem/20
5 |
6 | //公共 基础类
7 | @mixin clearFix
8 | &:before
9 | content: ""
10 | display: table
11 | &:after
12 | content: ""
13 | display: table
14 | clear: both
15 | overflow: hidden
16 | zoom: 1
17 | .clearfix
18 | @include clearFix
19 | //box布局
20 | @mixin box($horizontal: initial, $vertical: initial)
21 | display: -webkit-box
22 | display: box
23 | -webkit-box-pack: $horizontal
24 | box-pack: $horizontal
25 | -webkit-box-align: $vertical
26 | box-align: $vertical
27 | @mixin nowrap
28 | display: block
29 | white-space: nowrap
30 | overflow: hidden
31 | text-overflow: ellipsis
32 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | vue-demo-maizuo
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/components/header.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/src/assets/detail.sass:
--------------------------------------------------------------------------------
1 | @import 'common'
2 | #detail
3 | .cover
4 | img
5 | width: 100%
6 | .desc
7 | font-size: 13*$px
8 | line-height: 230%
9 | padding: 15*$px
10 | .title
11 | border-left: 16*$px solid #e4c89c
12 | font-size: 16*$px
13 | padding-left: 5*$px
14 | margin-bottom: 20*$px
15 | margin-left: -15*$px
16 | .info
17 | p
18 | @include nowrap
19 | span
20 | display: inline-block
21 | margin-right: 1*$px
22 | &:after
23 | content: '|'
24 | &:last-child:after
25 | content: ''
26 | &.p
27 | line-height: 150%
28 | margin-top: 5*$px
29 | .go-pay
30 | width: 160*$px
31 | height: 35*$px
32 | background: #e38700
33 | border-radius: 35*$px
34 | line-height: 35*$px
35 | color: #fff
36 | text-align: center
37 | font-size: 14*$px
38 | margin: 10*$px auto
39 | display: block
--------------------------------------------------------------------------------
/src/vuex/modules/detail.js:
--------------------------------------------------------------------------------
1 | import api from '../api'
2 | import * as types from '../types'
3 |
4 | const state = {
5 | detail:null,
6 | // title:''
7 | }
8 |
9 | const actions = {
10 | //获取影片详情并设置标题
11 | getFilmDetail:function({commit},id){
12 | commit(types.COM_LOADING_STATUS,true);
13 | api.getFilmDetail(id,function(res){
14 | commit(types.COM_CONF,{
15 | title: res.data.film.name
16 | })
17 | commit(types.DETAIL_GET_INFO,res.data);
18 | commit(types.COM_LOADING_STATUS,false);
19 | })
20 | },
21 | }
22 | const getters = {
23 | getFilmDetail: state => state.detail,
24 | }
25 |
26 | const mutations = {
27 | [types.DETAIL_GET_INFO](state,res){
28 | state.detail = res.film
29 | },
30 | }
31 |
32 | export default {
33 | state,
34 | actions,
35 | getters,
36 | mutations
37 | }
--------------------------------------------------------------------------------
/src/vuex/types.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Create by zechun.chen on 2016/12/22
3 | */
4 |
5 | //公共
6 | export const COM_LOADING_STATUS = 'COM_LOADING_STATUS'
7 | export const COM_CONF = 'COM_CONF'
8 | export const CHANGE_LEFTNAV_STATUS = 'CHANGE_LEFTNAV_STATUS'
9 | //home
10 | export const HOME_GET_BANNER_LIST = 'HOME_GET_BANNER_LIST' //获取banner
11 | export const HOME_GET_NOWPLAYING_LIST = 'HOME_GET_NOWPLAYING_LIST' //获取首页热映电影
12 | export const HOME_GET_COMINGSOON_LIST = 'HOME_GET_COMINGSOON_LIST' //获取首页即将上映电影
13 | //detail
14 | export const DETAIL_GET_INFO = 'DETAIL_GET_INFO' //获取影片详情
15 | //cinema
16 | export const CINEMA_GET_LIST = 'CINEMA_GET_LIST' //获取相关影院
17 | //film
18 | export const FILM_GET_NOWPLAYING = 'FILM_GET_NOWPLAYING' //获取热映电影
19 | export const FILE_NOWPLAYING_NUM = 'FILE_NOWPLAYING_NUM' //热映页数
20 | export const FILM_GET_COMINGSOON = 'FILM_GET_COMINGSOON' //获取即将上映电影
21 | export const FILM_COMINGSOON_NUM = 'FILM_COMINGSOON_NUM' // 即将上映页数
--------------------------------------------------------------------------------
/src/assets/icon/iconfont.css:
--------------------------------------------------------------------------------
1 |
2 | @font-face {font-family: "iconfont";
3 | src: url('iconfont.eot?t=1482391322636'); /* IE9*/
4 | src: url('iconfont.eot?t=1482391322636#iefix') format('embedded-opentype'), /* IE6-IE8 */
5 | url('iconfont.woff?t=1482391322636') format('woff'), /* chrome, firefox */
6 | url('iconfont.ttf?t=1482391322636') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
7 | url('iconfont.svg?t=1482391322636#iconfont') format('svg'); /* iOS 4.1- */
8 | }
9 |
10 | .iconfont {
11 | font-family:"iconfont" !important;
12 | font-size:16px;
13 | font-style:normal;
14 | -webkit-font-smoothing: antialiased;
15 | -moz-osx-font-smoothing: grayscale;
16 | }
17 |
18 | .icon-menu:before { content: "\e65b"; }
19 |
20 | .icon-people:before { content: "\e61b"; }
21 |
22 | .icon-right:before { content: "\e650"; }
23 |
24 | .icon-bottom:before { content: "\e625"; }
25 |
26 | .icon-top-copy:before { content: "\e60d"; }
27 |
28 |
--------------------------------------------------------------------------------
/src/config/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Create by zechun.chen on 2016/12/22
3 | * 基础配置
4 | */
5 |
6 | import FastClick from 'fastclick'
7 |
8 | ((doc, win) => {
9 | const docEl = doc.documentElement,
10 | resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
11 | recalc = () => {
12 | let clientWidth = docEl.clientWidth;
13 | if (!clientWidth) return;
14 | docEl.style.fontSize = 16 * (clientWidth / 320) + 'px';
15 | };
16 | if (!doc.addEventListener) return;
17 | win.addEventListener(resizeEvt, recalc, false);
18 | doc.addEventListener('DOMContentLoaded', recalc, false);
19 | //当dom加载完成时,或者 屏幕垂直、水平方向有改变进行html的根元素计算
20 | })(document, window);
21 |
22 |
23 | if ('addEventListener' in document) {
24 | document.addEventListener('DOMContentLoaded', function() {
25 | FastClick.attach(document.body);
26 | }, false);
27 | }
28 |
29 | /**
30 | * 对象数组去重,根据str属性
31 | */
32 | Array.prototype.unique = function(str){
33 | const seen = new Map()
34 | return this.filter((a) => {
35 | return !seen.has(a['name']) && seen.set(a['name'], 1)
36 | })
37 | }
38 |
--------------------------------------------------------------------------------
/src/components/sidebar.vue:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
--------------------------------------------------------------------------------
/src/routers.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Create by zechun.chen on 2016/12/22
3 | * 路由规则
4 | */
5 |
6 | import Vue from 'vue'
7 | import VueRouter from 'vue-router'
8 |
9 | Vue.use(VueRouter);
10 | const routes = [
11 | {
12 | path:'/',
13 | component:require('./App'),
14 | children:[
15 | {
16 | path:'/home',
17 | name:'home',
18 | component:require('./pages/home')
19 | },
20 | {
21 | path:'/detail/:id',
22 | name:'detail',
23 | component:require('./pages/detail')
24 | },
25 | {
26 | path:'/cinema/:id',
27 | name:'cinema',
28 | component:require('./pages/cinema')
29 | },
30 | {
31 | path:'/film/:type',
32 | name:'film',
33 | component:require('./pages/film')
34 | }
35 | ]
36 | }
37 | ];
38 |
39 | const router = new VueRouter({
40 | routes:routes,
41 | history:true,
42 | linkActiveClass:'active', //如果有底部导航栏,这个属性可以为被选中的路由增加相应的选中状态class
43 | });
44 |
45 | export default router;
--------------------------------------------------------------------------------
/config/index.js:
--------------------------------------------------------------------------------
1 | // see http://vuejs-templates.github.io/webpack for documentation.
2 | var path = require('path')
3 |
4 | module.exports = {
5 | build: {
6 | env: require('./prod.env'),
7 | index: path.resolve(__dirname, '../dist/index.html'),
8 | assetsRoot: path.resolve(__dirname, '../dist'),
9 | assetsSubDirectory: 'static',
10 | assetsPublicPath: './',
11 | productionSourceMap: true,
12 | // Gzip off by default as many popular static hosts such as
13 | // Surge or Netlify already gzip all static assets for you.
14 | // Before setting to `true`, make sure to:
15 | // npm install --save-dev compression-webpack-plugin
16 | productionGzip: false,
17 | productionGzipExtensions: ['js', 'css']
18 | },
19 | dev: {
20 | env: require('./dev.env'),
21 | port: 8080,
22 | assetsSubDirectory: 'static',
23 | assetsPublicPath: '/',
24 | proxyTable: {},
25 | // CSS Sourcemaps off by default because relative paths are "buggy"
26 | // with this option, according to the CSS-Loader README
27 | // (https://github.com/webpack/css-loader#sourcemaps)
28 | // In our experience, they generally work as expected,
29 | // just be aware of this issue when enabling this option.
30 | cssSourceMap: false
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/assets/sidebar.sass:
--------------------------------------------------------------------------------
1 | @import 'common'
2 | #sidebar
3 | transition: all ease .4s
4 | .sidebar-enter-active,.sidebar-leave-active
5 | transition: all ease .4s
6 | .sidebar-enter,.sidebar-leave-active
7 | opacity: 0
8 | .leftNav-enter-active,.leftNav-leave-active
9 | transition: right ease .4s
10 | .leftNav-enter,.leftNav-leave-active
11 | right: 380*$px !important
12 | .sidebar-container
13 | position: fixed
14 | top: 0
15 | left: 0
16 | right: 0
17 | bottom: 0
18 | color: #9a9a9a
19 | z-index: 501
20 | a
21 | color: #9a9a9a
22 | font-size: 14*$px
23 | .sidebar-overlay
24 | background: rgba(0,0,0,.5)
25 | position: absolute
26 | top: 50*$px
27 | right: 0
28 | bottom: 0
29 | left: 0
30 | nav
31 | border-top: 1px solid #222
32 | box-shadow: 0 1px 1px #363636 inset
33 | background: #282828
34 | position: absolute
35 | display: block
36 | top: 0
37 | right: 110*$px
38 | bottom: 0
39 | left: 0
40 | li
41 | overflow: hidden
42 | line-height: 50*$px
43 | height: 51*$px
44 | a
45 | display: block
46 | border-bottom: 1px dotted #333
47 | width: 90%
48 | margin: 0 auto
49 | i
50 | float: right
51 | color: #666
52 | font-size: 14*$px
53 |
54 |
--------------------------------------------------------------------------------
/src/assets/film.sass:
--------------------------------------------------------------------------------
1 | @import 'common'
2 | #film
3 | background: #f9f9f9
4 | .tabs
5 | margin: 0 15*$px
6 | border-bottom: 1px solid #fe6e00
7 | @include box(justify,center)
8 | .item
9 | width: 50%
10 | text-align: center
11 | font-size: 16*$px
12 | height: 40*$px
13 | line-height: 40*$px
14 | color: #6a6a6a
15 | &.active
16 | border-bottom: 3px solid #fe6e00
17 | color: #fe6e00
18 | .tab-content
19 | margin: 0 15*$px
20 | .now-playing-list,.coming-soon-list
21 | .item
22 | @include box(justify,start)
23 | padding: 15*$px 0
24 | // display: block
25 | border-bottom: 1px dashed #8e8e8e
26 | &:last-child
27 | border-bottom: none
28 | .avater
29 | width: 60*$px
30 | margin-right: 15*$px
31 | img
32 | width: 60*$px
33 | height: 82*$px
34 | object-fit: contain
35 | .info
36 | width: 250*$px
37 | font-size: 14*$px
38 | h3
39 | font-weight: 400
40 | font-size: 16*$px
41 | margin-top: 5*$px
42 | p
43 | font-size: 13*$px
44 | height: 28*$px
45 | line-height: 28*$px
46 | color: #8e8e8e
47 | span
48 | color: #8aa2bf
49 | .time
50 | color: #fe6e00
51 | .count
52 | width: 50*$px
53 | padding-top: 5*$px
54 | color: #fe6e00
--------------------------------------------------------------------------------
/src/vuex/modules/com.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Create by zechun.chen on 2016/12/22
3 | */
4 | import * as types from '../types'
5 | /**
6 | * App通用配置
7 | */
8 | const state = {
9 | title:'',
10 | loading:0,
11 | leftNavState:false
12 | // isBack:false,
13 | // isShare:false,
14 | // isFooter:false, //本程序没有底部导航栏
15 | }
16 |
17 | const actions = {
18 | //本程序主要设置标题栏,对于通用程序,则可以设置返回按钮,底部导航栏
19 | comConf({commit},settings){
20 | commit(types.COM_CONF,settings)
21 | },
22 | //左侧导航栏的开关
23 | changeLeftNavState({commit},status){
24 | commit(types.CHANGE_LEFTNAV_STATUS,status)
25 | }
26 | }
27 | const getters = {
28 | comConf: state => state,
29 | loading: state => state.loading,
30 | title: state => state.title,
31 | leftNavState: state => state.leftNavState
32 | }
33 | const mutations = {
34 | [types.COM_CONF](state,settings){
35 | state = Object.assign(state,settings)
36 | },
37 | [types.COM_LOADING_STATUS](state,status){
38 | if(state.loading == 0 && !status){
39 | return ;
40 | }
41 | state.loading = status ? ++state.loading : --state.loading;
42 | },
43 | [types.CHANGE_LEFTNAV_STATUS](state,status){
44 | state.leftNavState = status
45 | }
46 | }
47 |
48 | export default {
49 | state,
50 | actions,
51 | getters,
52 | mutations
53 | }
--------------------------------------------------------------------------------
/src/assets/loading.sass:
--------------------------------------------------------------------------------
1 | //loading
2 | @keyframes rotate
3 | 0%
4 | -webkit-transform: rotate(0deg)
5 | transform: rotate(0deg)
6 | 50%
7 | -webkit-transform: rotate(180deg)
8 | transform: rotate(180deg)
9 | 100%
10 | -webkit-transform: rotate(360deg)
11 | transform: rotate(360deg)
12 | .loading-rotate
13 | position: fixed
14 | top: 0
15 | left: 0
16 | right: 0
17 | bottom: 0
18 | background: rgba(0,0,0,.4)
19 | .inner
20 | width: 80px
21 | height: 80px
22 | position: absolute
23 | top: 50%
24 | left: 50%
25 | margin-left: -40px
26 | margin-top: -40px
27 | &>div
28 | animation-fill-mode: both
29 | position: absolute
30 | left: 0px
31 | top: 0px
32 | border: 2px solid #fff
33 | border-bottom-color: transparent
34 | border-top-color: transparent
35 | border-radius: 100%
36 | height: 80px
37 | width: 80px
38 | animation: rotate 1s 0s ease-in-out infinite
39 | &:last-child
40 | display: inline-block
41 | top: 15px
42 | left: 15px
43 | width: 50px
44 | height: 50px
45 | animation-duration: 0.5s
46 | border-color: #fff transparent #fff transparent
47 | animation-direction: reverse
--------------------------------------------------------------------------------
/src/vuex/modules/cinema.js:
--------------------------------------------------------------------------------
1 | import api from '../api'
2 | import * as types from '../types'
3 |
4 | const state = {
5 | list:[],
6 | district:[]
7 | }
8 |
9 | const actions = {
10 | //获取相关影院列表
11 | getCinemaList:function({commit},id){
12 | commit(types.COM_LOADING_STATUS,true);
13 | api.getCinemaList(id,function(res){
14 | commit(types.CINEMA_GET_LIST,res.data);
15 | commit(types.COM_LOADING_STATUS,false);
16 | })
17 | },
18 | }
19 | const getters = {
20 | getCinemaList: state => state.list,
21 | getDistrict: state => state.district
22 | }
23 |
24 | const mutations = {
25 | [types.CINEMA_GET_LIST](state,res){
26 | /**
27 | * 接口没有的区域影院没有进行区分就返回,故只能前端进行分类
28 | * 先将列表遍历一遍,将地区相关归入一个数组
29 | * 进行数组去重并按照拼音首字母进行排列
30 | * 去重unique()在config/index.js中定义
31 | */
32 | let district = [],_json={};
33 | for(let item of res.cinemas){
34 | _json = {
35 | name:item.district.name,
36 | pinyin:item.district.pinyin
37 | }
38 | district.push(_json)
39 | }
40 | district = district.unique('name').sort(function(a,b){
41 | return a.pinyin.localeCompare(b.pinyin.charAt(0))
42 | });
43 | state.district = district;
44 | state.list = res.cinemas;
45 | },
46 | }
47 |
48 | export default {
49 | state,
50 | actions,
51 | getters,
52 | mutations
53 | }
--------------------------------------------------------------------------------
/src/assets/home.sass:
--------------------------------------------------------------------------------
1 | @import 'common'
2 | #home
3 | background: #e1e1e1
4 | .banner-swiper
5 | height: 232*$px
6 | color: #fff
7 | font-size: 30*$px
8 | text-align: center
9 | overflow: hidden
10 | .slide img
11 | width: 100%
12 | .go-more
13 | width: 150*$px
14 | height: 30*$px
15 | line-height: 30*$px
16 | text-align: center
17 | color: #616161
18 | border: 1px solid #aaa
19 | border-radius: 30*$px
20 | font-size: 13*$px
21 | margin: 0 auto
22 | margin-bottom: 15*$px
23 | display: block
24 | .now-playing,.coming-soon
25 | padding: 15*$px
26 | .item
27 | background: #f9f9f9
28 | margin-bottom: 15*$px
29 | box-shadow: 0 0 4px rgba(0,0,0,.4)
30 | img
31 | width: 100%
32 | .desc
33 | @include box(justify,center)
34 | padding: 5*$px 10*$px
35 | .info
36 | font-size: 12*$px
37 | font-weight: 100
38 | p
39 | font-size: 10*$px
40 | color: #9a9a9a
41 | .count
42 | color: #f78360
43 | font-weight: 500
44 | .time
45 | font-size: 12*$px
46 | color: #f78360
47 | .coming-title
48 | width: 100%
49 | height: 1px
50 | background: #a8a8a8
51 | position: relative
52 | margin-bottom: 20*$px
53 | div
54 | position: absolute
55 | color: #eee
56 | background: #a7a7a7
57 | font-size: 14*$px
58 | width: 80*$px
59 | height: 22*$px
60 | text-align: center
61 | line-height: 22*$px
62 | border-radius: 5*$px
63 | top: 50%
64 | left: 50%
65 | margin-top: -11*$px
66 | margin-left: -40*$px
67 |
--------------------------------------------------------------------------------
/src/pages/detail.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
影片简介
6 |
7 |
导 演:{{detail.director}}
8 |
主 演:{{item.name}}
9 |
地区语言:{{detail.nation}}({{detail.language}})
10 |
类 型:{{detail.category}}
11 |
上映日期:{{detail.premiereAt|getDay}}
12 |
{{detail.synopsis}}
13 |
14 |
15 |
立即购票
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/vuex/modules/home.js:
--------------------------------------------------------------------------------
1 | import api from '../api'
2 | import * as types from '../types'
3 |
4 | const state = {
5 | banner:[],
6 | nowplay:[],
7 | coming:[],
8 | }
9 |
10 | const actions = {
11 | //获取banner列表
12 | getBannerList:function({commit}){
13 | commit(types.COM_LOADING_STATUS,true);
14 | api.getBannerList(function(res){
15 | commit(types.HOME_GET_BANNER_LIST,res.data);
16 | commit(types.COM_LOADING_STATUS,false);
17 | })
18 | },
19 | // 获取热映
20 | getNowPlaying:function({commit}){
21 | commit(types.COM_LOADING_STATUS,true)
22 | api.getNowPlaying(function(res){
23 | commit(types.HOME_GET_NOWPLAYING_LIST,res.data)
24 | commit(types.COM_LOADING_STATUS,false)
25 | })
26 | },
27 | // 获取即将上映
28 | getComingSoon:function({commit}){
29 | commit(types.COM_LOADING_STATUS,true)
30 | api.getComingSoon(function(res){
31 | commit(types.HOME_GET_COMINGSOON_LIST,res.data)
32 | commit(types.COM_LOADING_STATUS,false)
33 | })
34 | }
35 | }
36 | const getters = {
37 | getBannerList: state => state.banner,
38 | getNowPlaying: state => state.nowplay,
39 | getComingSoon: state => state.coming,
40 | }
41 |
42 | const mutations = {
43 | [types.HOME_GET_BANNER_LIST](state,res){
44 | state.banner = res.billboards
45 | },
46 | [types.HOME_GET_NOWPLAYING_LIST](state,res){
47 | state.nowplay = res.films
48 | },
49 | [types.HOME_GET_COMINGSOON_LIST](state,res){
50 | state.coming = res.films
51 | }
52 | }
53 |
54 | export default {
55 | state,
56 | actions,
57 | getters,
58 | mutations
59 | }
--------------------------------------------------------------------------------
/src/vuex/api.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Create bu zechun.chen on 2016/12/22
3 | * api配置
4 | */
5 | import axios from 'axios'
6 |
7 | let url = process.env.NODE_ENV !== 'production' ? '/api/' : 'http://m.maizuo.com/v4/api/';
8 |
9 | let func_axios = (api,cb) => {
10 | axios.get(api).then(function(res){
11 | if(res.status >= 200 && res.status <300){
12 | cb(res.data)
13 | }
14 | }).catch((error) => {
15 | // new Error('desc');
16 | return Promise.reject(error)
17 | })
18 | }
19 |
20 | export default {
21 | /**
22 | * 根据请求的时间戳获取banner列表
23 | */
24 | getBannerList:(cb)=>func_axios(url + 'billboard/home?t=' + new Date()*1,cb),
25 | /**
26 | * 获取首页热映电影
27 | */
28 | getNowPlaying:(cb)=>func_axios(url + 'film/now-playing?_t=' + new Date()*1 +'&page=1&count=5',cb),
29 | /**
30 | * 获取热映列表
31 | */
32 | getNowPlayList:(page,cb)=>func_axios(url + 'film/now-playing?page=' + page + '&count=10',cb),
33 | /**
34 | * 获取首页即将上映电影
35 | */
36 | getComingSoon:(cb)=>func_axios(url + 'film/coming-soon?__t=' + new Date()*1 +'&page=1&count=3',cb),
37 | /**
38 | * 获取即将上映列表
39 | */
40 | getComingList:(page,cb)=>func_axios(url + 'film/coming-soon?page=' + page +'&count=10',cb),
41 | /**
42 | * 根据id获取相关影片信息
43 | */
44 | getFilmDetail:(id,cb)=>func_axios(url + 'film/' + id + '?__t=' + new Date()*1,cb),
45 | /**
46 | * 获取相关影院
47 | */
48 | getCinemaList:(id,cb)=>func_axios(url + 'film/' + id + '/cinema?__t=' + new Date()*1,cb),
49 | /**
50 | * 根据影片id跟影院id获取相关电影票时段
51 | */
52 | getScheduleList:(filmid,cinemaid,cb)=>func_axios(url + 'schedule?__t=' + new Date()*1 + '&film=' + filmid + '&cinema=' + cinemaid,cb),
53 | }
54 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-demo-maizuo",
3 | "version": "1.0.0",
4 | "description": "vue-demo-maizuo",
5 | "author": "shadow <822599633@qq.com>",
6 | "private": true,
7 | "scripts": {
8 | "dev": "node build/dev-server.js",
9 | "build": "node build/build.js"
10 | },
11 | "dependencies": {
12 | "axios": "^0.15.3",
13 | "fastclick": "^1.0.6",
14 | "vue": "^2.1.0",
15 | "vue-awesome-swiper": "^2.2.6",
16 | "vue-router": "^2.1.1",
17 | "vuex": "^2.1.1"
18 | },
19 | "devDependencies": {
20 | "autoprefixer": "^6.4.0",
21 | "babel-core": "^6.0.0",
22 | "babel-loader": "^6.0.0",
23 | "babel-plugin-transform-runtime": "^6.0.0",
24 | "babel-preset-es2015": "^6.0.0",
25 | "babel-preset-stage-2": "^6.0.0",
26 | "babel-register": "^6.0.0",
27 | "chalk": "^1.1.3",
28 | "connect-history-api-fallback": "^1.1.0",
29 | "css-loader": "^0.25.0",
30 | "eventsource-polyfill": "^0.9.6",
31 | "express": "^4.13.3",
32 | "extract-text-webpack-plugin": "^1.0.1",
33 | "file-loader": "^0.9.0",
34 | "function-bind": "^1.0.2",
35 | "html-webpack-plugin": "^2.8.1",
36 | "http-proxy-middleware": "^0.17.2",
37 | "json-loader": "^0.5.4",
38 | "node-sass": "^4.1.1",
39 | "opn": "^4.0.2",
40 | "ora": "^0.3.0",
41 | "postcss": "^5.2.6",
42 | "postcss-loader": "^1.2.1",
43 | "sass-loader": "^4.1.1",
44 | "semver": "^5.3.0",
45 | "shelljs": "^0.7.4",
46 | "url-loader": "^0.5.7",
47 | "vue-loader": "^10.0.0",
48 | "vue-style-loader": "^1.0.0",
49 | "vue-template-compiler": "^2.1.0",
50 | "webpack": "^1.13.2",
51 | "webpack-dev-middleware": "^1.8.3",
52 | "webpack-hot-middleware": "^2.12.2",
53 | "webpack-merge": "^0.14.1"
54 | },
55 | "engines": {
56 | "node": ">= 4.0.0",
57 | "npm": ">= 3.0.0"
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/pages/cinema.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
{{item.name}}
5 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/assets/reset.sass:
--------------------------------------------------------------------------------
1 | /*reset*/
2 | *
3 | margin: 0
4 | padding: 0
5 | box-sizing: border-box
6 | body,button,input,select,textarea
7 | font-family: 'Microsoft YaHei', Tahoma, Helvetica, Arial, sans-serif
8 | // -webkit-font-smoothing: antialiased
9 |
10 | h1, h2, h3, h4, h5, h6
11 | font-size: 100%
12 | address, cite, dfn, em, var
13 | font-style: normal
14 | code, kbd, pre, samp
15 | // font-family: couriernew, courier, monospace
16 | small
17 | font-size: 12px
18 | ul, ol
19 | list-style: none
20 | a
21 | text-decoration: none
22 | outline: none
23 | sup
24 | vertical-align: text-top
25 | sub
26 | vertical-align: text-bottom
27 | legend
28 | color: #000
29 | fieldset, img
30 | border: 0
31 | button, input, select, textarea
32 | font-size: 100%
33 | outline: none
34 | table
35 | border-collapse: collapse
36 | border-spacing: 0
37 | a
38 | color: inherit
39 |
40 | @import 'common'
41 |
42 | html,body
43 | height: 100%
44 | background: #e1e1e1
45 |
46 | .go-top
47 | color: #fff
48 | background: rgba(0,0,0,.7)
49 | width: 50*$px
50 | text-align: center
51 | height: 50*$px
52 | line-height: 50*$px
53 | border-radius: 50%
54 | position: fixed
55 | z-index: 499
56 | bottom: -100*$px
57 | right: 20*$px
58 | transition: .3s linear
59 | &.active
60 | bottom: 20*$px
61 | transition: .3s linear
62 | i
63 | font-size: 24*$px
64 | .container
65 | padding-top: 50*$px
66 | .child-view
67 | // position: absolute
68 | width: 100%
69 | transition: all .2s cubic-bezier(.55,0,.1,1)
70 | .slide-left-enter, .slide-right-leave-active
71 | opacity: 0
72 | transform: translate(30*$px,0)
73 | .slide-left-leave-active, .slide-right-enter
74 | opacity: 0
75 | transform: translate(-30*$px 0)
76 |
77 | .list-complete-item
78 | transition: all .6s
79 | display: inline-block
80 | margin-right: 10px
81 | .list-complete-enter, .list-complete-leave-active
82 | opacity: 0
83 | transform: translateY(30px)
84 |
85 | .list-complete-leave-active
86 | position: absolute
87 |
88 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Vue2实战:模仿卖座电影
2 | > 使用Vue2.0全家桶仿制[卖座电影](http://m.maizuo.com/v4/?co=maizuo)
3 | >
4 | > 仓库:[https://github.com/ChuckCZC/vue-demo-maizuo](https://github.com/ChuckCZC/vue-demo-maizuo)
5 |
6 | ## 声明
7 |
8 | 该项目所用到的API均来自 [卖座电影](http://m.maizuo.com/v4/?co=maizuo) ,采用chrome 开发者工具分析出来的,只是为了得到数据进行排版练习,完全出于学习用途,并无恶意,请卖座电影官方海涵。
9 |
10 | ## 参考资料
11 |
12 | vue2.0中文文档 : [https://vuefe.cn/v2/guide/](https://vuefe.cn/v2/guide/)
13 |
14 | vue-router文档 : [https://router.vuejs.org/](https://router.vuejs.org/)
15 |
16 | vuex文档 : [https://vuex.vuejs.org/](https://vuex.vuejs.org/)
17 |
18 | 轮播插件swiper : [https://github.com/surmon-china/vue-awesome-swiper](https://github.com/surmon-china/vue-awesome-swiper)
19 |
20 | 数据请求axios : [https://www.npmjs.com/package/axios](https://www.npmjs.com/package/axios)
21 |
22 | 项目参考 : [https://github.com/zhengguorong/maizuo/tree/master/vuexMaizuo2](https://github.com/zhengguorong/maizuo/tree/master/vuexMaizuo2)
23 |
24 | ## 项目结构
25 |
26 | 
27 |
28 | 项目由vue-cli直接生成手脚架,之后调整`config/index.js`的build>assetsPublicPath为'./',该属性跟打包后index.html的css和js的引入路径有关;开发过程中在build/dev-server.js配置相关代码以跨域
29 |
30 | ```javascript
31 | app.use('/api',proxyMiddleware({
32 | target:'http://m.maizuo.com/v4',
33 | changeOrigin:true
34 | }))
35 | ```
36 |
37 | ## 界面预览
38 |
39 | 
40 |
41 | 
42 |
43 | 
44 |
45 | 
46 |
47 | 
48 |
49 | 
50 |
51 | > ps:只是模仿了以上页面,这几个页面感觉已经包括了vue的常用功能了,后面的页面则是跳去卖座电影的官网了;由于只是几个页面,故各个页面没有将相关的子项分离成组件,如果项目庞大,建议分离成组件形式
52 |
53 | ##### 最后,如果该demo对你学习vue有帮助,麻烦给个star,谢谢#####
54 |
55 |
56 | ## Build
57 |
58 | ``` bash
59 | # install dependencies
60 | npm install
61 |
62 | # serve with hot reload at localhost:8080
63 | npm run dev
64 |
65 | # build for production with minification
66 | npm run build
67 | ```
68 |
69 | For detailed explanation on how things work, checkout the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader).
70 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
72 |
--------------------------------------------------------------------------------
/src/vuex/modules/film.js:
--------------------------------------------------------------------------------
1 | import api from '../api'
2 | import * as types from '../types'
3 |
4 | const state = {
5 | nowPlayingList:[],
6 | comingSoonList:[],
7 | nowPage:0,
8 | comingPage:0,
9 | getNowMore:true,
10 | getComingMore:true,
11 | }
12 |
13 | const actions = {
14 | //获取热映列表
15 | //偷懒没有弄加载更多的效果,故去掉loading
16 | getNowPlayList:function({commit}){
17 | if(state.getNowMore){
18 | // commit(types.COM_LOADING_STATUS,true);
19 | commit(types.FILE_NOWPLAYING_NUM);
20 | api.getNowPlayList(state.nowPage,function(res){
21 | commit(types.FILM_GET_NOWPLAYING,res.data)
22 | // commit(types.COM_LOADING_STATUS,false);
23 | })
24 | }
25 |
26 | },
27 | //获取即将上映列表
28 | getComingList:function({commit}){
29 | if(state.getComingMore){
30 | // commit(types.COM_LOADING_STATUS,true);
31 | commit(types.FILM_COMINGSOON_NUM);
32 | api.getComingList(state.comingPage,function(res){
33 | commit(types.FILM_GET_COMINGSOON,res.data)
34 | // commit(types.COM_LOADING_STATUS,false);
35 | })
36 | }
37 | }
38 | }
39 | const getters = {
40 | getNowPlayList: state => state.nowPlayingList,
41 | getComingList: state => state.comingSoonList,
42 | }
43 |
44 | const mutations = {
45 | [types.FILM_GET_NOWPLAYING](state,res){
46 | console.log(state.getNowMore,res.page)
47 | state.nowPlayingList = state.nowPlayingList.concat(res.films)
48 | //根据current跟total的关系判断是否还有下一页
49 | state.getNowMore = res.page.current.title
5 | width: 100%
6 | height: 40*$px
7 | line-height: 40*$px
8 | border-bottom: 1px solid #fff
9 | color: #636363
10 | font-size: 14*$px
11 | padding-left: 15*$px
12 | &:last-child
13 | .title
14 | border-bottom: none
15 | .list
16 | .shop
17 | background: #fff
18 | border-bottom: 1px solid #e1e1e1
19 | font-size: 14*$px
20 | padding: 15*$px
21 | line-height: 180%
22 | @include box(justify,start)
23 | .desc
24 | width: 300*$px
25 | .title
26 | font-size: 16*$px
27 | span
28 | font-size: 10*$px
29 | display: inline-block
30 | vertical-align: middle
31 | border-radius: 50%
32 | width: 16*$px
33 | height: 16*$px
34 | text-align: center
35 | line-height: 14*$px
36 | color: #fd9c77
37 | border: 1px solid #fd9c77
38 | margin-left: 5*$px
39 | span:last-child
40 | color: #a5c1d5
41 | border: 1px solid #a5c1d5
42 | .tip
43 | padding: 5*$px 10*$px
44 | span
45 | display: inline-block
46 | color: #fff
47 | font-size: 11*$px
48 | padding: 0*$px 4*$px
49 | border-radius: 4*$px
50 | &.sundry
51 | background: #51add0
52 | margin-right: 8*$px
53 | &.discount
54 | background: #ff9658
55 | .area
56 | color: #ccc
57 | font-size: 13*$px
58 | @include nowrap
59 | .extra
60 | color: #ccc
61 | font-size: 13*$px
62 | .price
63 | width: 45*$px
64 | color: #fc8637
65 | font-size: 16*$px
66 |
67 |
68 |
--------------------------------------------------------------------------------
/src/pages/home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
{{item.name}}
20 |
{{item.cinemaCount}}家影院上映 {{item.watchCount}}人购票
21 |
22 |
{{item.grade}}
23 |
24 |
25 |
26 |
27 | 更多热映电影
28 |
29 |
30 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
{{item.name}}
40 |
41 |
{{item.premiereAt|formatDate}}
42 |
43 |
44 |
45 |
46 | 更多即将上映电影
47 |
48 |
49 |
50 |
51 |
97 |
--------------------------------------------------------------------------------
/src/assets/icon/iconfont.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
54 |
--------------------------------------------------------------------------------
/src/pages/film.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
11 |
12 |
{{item.name}}
13 |
{{item.intro}}
14 |
15 | {{item.cinemaCount}}家影院上映
16 | {{item.watchCount}}人购票
17 |
18 |
19 | {{item.grade}}
20 |
21 |
22 |
23 |
24 |
25 |
26 |
{{item.name}}
27 |
{{item.intro}}
28 |
29 | {{item.premiereAt|formatDate}}
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------