├── src
├── store
│ ├── getters.js
│ ├── index.js
│ └── modules
│ │ ├── collect.js
│ │ ├── searchHistory.js
│ │ ├── song.js
│ │ └── location.js
├── scss
│ ├── index.scss
│ ├── base.scss
│ ├── variable.scss
│ ├── mixin.scss
│ └── reset.scss
├── assets
│ ├── logo.png
│ ├── avatar.jpeg
│ ├── img-error.jpg
│ ├── img-error.png
│ ├── douban-logo.png
│ ├── img-loading.gif
│ └── wangyi-logo.gif
├── components
│ ├── my-ui
│ │ ├── packages
│ │ │ ├── tabs
│ │ │ │ ├── index.js
│ │ │ │ └── src
│ │ │ │ │ └── main.vue
│ │ │ ├── swipe
│ │ │ │ ├── index.js
│ │ │ │ └── src
│ │ │ │ │ └── main.vue
│ │ │ ├── loading
│ │ │ │ ├── index.js
│ │ │ │ └── src
│ │ │ │ │ └── main.vue
│ │ │ ├── tab-item
│ │ │ │ ├── index.js
│ │ │ │ └── src
│ │ │ │ │ └── main.vue
│ │ │ └── swipe-item
│ │ │ │ ├── index.js
│ │ │ │ └── src
│ │ │ │ └── main.vue
│ │ └── src
│ │ │ ├── mixins
│ │ │ ├── findParent.js
│ │ │ └── emitter.js
│ │ │ └── index.js
│ ├── wy-skeleton
│ │ └── index.vue
│ ├── header
│ │ └── index.vue
│ ├── horizontal-list
│ │ └── index.vue
│ ├── vertical-list
│ │ └── index.vue
│ ├── song-list
│ │ └── index.vue
│ └── progress
│ │ └── index.vue
├── directive
│ ├── loading
│ │ ├── loading.gif
│ │ └── index.js
│ ├── index.js
│ └── drag
│ │ └── index.js
├── views
│ ├── rank
│ │ └── index.vue
│ ├── layout
│ │ ├── index.vue
│ │ └── components
│ │ │ ├── AppMain.vue
│ │ │ └── AppTabs.vue
│ ├── movie-detail
│ │ ├── components
│ │ │ ├── MovieInfo.vue
│ │ │ ├── MovieComment.vue
│ │ │ ├── Operate.vue
│ │ │ └── CastDetail.vue
│ │ └── index.vue
│ ├── user
│ │ └── index.vue
│ ├── welcome
│ │ └── index.vue
│ ├── song-list-detail
│ │ └── index.vue
│ ├── music
│ │ └── index.vue
│ ├── search
│ │ └── index.vue
│ ├── movie-list
│ │ └── index.vue
│ └── music-player
│ │ └── index.vue
├── createApi.js
├── mixins
│ ├── popup.js
│ ├── showMovieDetail.js
│ └── location.js
├── App.vue
├── vant.js
├── main.js
├── utils
│ ├── searchHistory.js
│ ├── request.js
│ ├── song.js
│ ├── common.js
│ ├── collect.js
│ └── dom.js
├── router.js
└── api
│ ├── wangyi.js
│ └── douban.js
├── public
├── favicon.ico
└── index.html
├── babel.config.js
├── .gitignore
├── vue.config.js
├── package.json
└── README.md
/src/store/getters.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/scss/index.scss:
--------------------------------------------------------------------------------
1 | @import 'base.scss';
2 | @import 'reset.scss';
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OuZuYu/vue-vant-douban-wangyiyun/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OuZuYu/vue-vant-douban-wangyiyun/HEAD/src/assets/logo.png
--------------------------------------------------------------------------------
/src/components/my-ui/packages/tabs/index.js:
--------------------------------------------------------------------------------
1 | import MyTabs from './src/main';
2 |
3 | export default MyTabs;
--------------------------------------------------------------------------------
/src/assets/avatar.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OuZuYu/vue-vant-douban-wangyiyun/HEAD/src/assets/avatar.jpeg
--------------------------------------------------------------------------------
/src/components/my-ui/packages/swipe/index.js:
--------------------------------------------------------------------------------
1 | import MySwipe from './src/main';
2 |
3 | export default MySwipe;
--------------------------------------------------------------------------------
/src/assets/img-error.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OuZuYu/vue-vant-douban-wangyiyun/HEAD/src/assets/img-error.jpg
--------------------------------------------------------------------------------
/src/assets/img-error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OuZuYu/vue-vant-douban-wangyiyun/HEAD/src/assets/img-error.png
--------------------------------------------------------------------------------
/src/components/my-ui/packages/loading/index.js:
--------------------------------------------------------------------------------
1 | import MyLoading from './src/main';
2 |
3 | export default MyLoading;
--------------------------------------------------------------------------------
/src/components/my-ui/packages/tab-item/index.js:
--------------------------------------------------------------------------------
1 | import MyTabItem from './src/main';
2 |
3 | export default MyTabItem;
--------------------------------------------------------------------------------
/src/assets/douban-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OuZuYu/vue-vant-douban-wangyiyun/HEAD/src/assets/douban-logo.png
--------------------------------------------------------------------------------
/src/assets/img-loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OuZuYu/vue-vant-douban-wangyiyun/HEAD/src/assets/img-loading.gif
--------------------------------------------------------------------------------
/src/assets/wangyi-logo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OuZuYu/vue-vant-douban-wangyiyun/HEAD/src/assets/wangyi-logo.gif
--------------------------------------------------------------------------------
/src/components/my-ui/packages/swipe-item/index.js:
--------------------------------------------------------------------------------
1 | import MySwipeItem from './src/main';
2 |
3 | export default MySwipeItem;
--------------------------------------------------------------------------------
/src/directive/loading/loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OuZuYu/vue-vant-douban-wangyiyun/HEAD/src/directive/loading/loading.gif
--------------------------------------------------------------------------------
/src/views/rank/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
16 |
--------------------------------------------------------------------------------
/src/scss/base.scss:
--------------------------------------------------------------------------------
1 | .iconfont{
2 | font-family:"iconfont" !important;
3 | font-size:16px;font-style:normal;
4 | -webkit-font-smoothing: antialiased;
5 | -webkit-text-stroke-width: 0.2px;
6 | -moz-osx-font-smoothing: grayscale;
7 | }
--------------------------------------------------------------------------------
/src/scss/variable.scss:
--------------------------------------------------------------------------------
1 | $white: #fff;
2 | $theme: #42bd56;
3 | $red: #FF8C69;
4 | $green: #00CD00;
5 | $yellow: #FFB90F;
6 | $gray-light: #eee;
7 | $gray-deep: #777;
8 | $black-light: #333;
9 | $wrap-padding: 16px;
10 |
11 | $theme-wy: #58C976;
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/app'
4 | ],
5 |
6 | plugins: [
7 | ['import', {
8 | libraryName: 'vant',
9 | libraryDirectory: 'es',
10 | style: true
11 | }, 'vant']
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw*
22 |
--------------------------------------------------------------------------------
/src/directive/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 |
3 | import loading from './loading';
4 | import drag from './drag';
5 |
6 | const directive = [
7 | { name: 'loading', content: loading },
8 | { name: 'drag', content: drag }
9 | ];
10 |
11 | directive.forEach(directive => {
12 | Vue.directive(directive.name, directive.content);
13 | });
--------------------------------------------------------------------------------
/src/createApi.js:
--------------------------------------------------------------------------------
1 | import CreateAPI from 'vue-create-api';
2 | import Vue from 'vue';
3 | import MovieDetail from '@/views/movie-detail';
4 | import CastDetail from '@/views/movie-detail/components/CastDetail';
5 | import SongList from '@/views/song-list-detail';
6 |
7 | Vue.use(CreateAPI);
8 |
9 | Vue.createAPI(MovieDetail)
10 | Vue.createAPI(CastDetail)
11 | Vue.createAPI(SongList)
--------------------------------------------------------------------------------
/src/mixins/popup.js:
--------------------------------------------------------------------------------
1 | const EVENT_SHOW = 'show'
2 | const EVENT_HIDE = 'hide'
3 |
4 | export default {
5 | data() {
6 | return {
7 | visible: false
8 | }
9 | },
10 | methods: {
11 | show() {
12 | this.visible = true
13 | this.$emit(EVENT_SHOW)
14 | },
15 | hide() {
16 | this.visible = false
17 | this.$emit(EVENT_HIDE)
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/views/layout/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
16 |
17 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | baseUrl: './',
3 | css: {
4 | loaderOptions: {
5 | sass: {
6 | // 引入全局变量
7 | data: `@import "@/scss/variable.scss";`
8 | }
9 | }
10 | },
11 | devServer: {
12 | proxy: {
13 | '/v2': {
14 | target: 'https://api.douban.com',
15 | changeOrigin: true
16 | }
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 | import getters from './getters';
4 | import location from './modules/location'
5 | import collect from './modules/collect'
6 | import searchHistory from './modules/searchHistory'
7 | import song from './modules/song'
8 |
9 | Vue.use(Vuex)
10 |
11 | export default new Vuex.Store({
12 | modules: {
13 | location,
14 | collect,
15 | searchHistory,
16 | song
17 | },
18 |
19 | getters
20 | });
--------------------------------------------------------------------------------
/src/views/layout/components/AppMain.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
14 |
15 |
--------------------------------------------------------------------------------
/src/components/my-ui/src/mixins/findParent.js:
--------------------------------------------------------------------------------
1 | export default {
2 | methods: {
3 | findParent (componentName) {
4 | let parent = this.$parent || this.$root;
5 | let name = parent.$options.name;
6 |
7 | while (parent && (!name || name !== componentName)) {
8 | parent = parent.$parent;
9 |
10 | if (parent) {
11 | name = parent.$options.name;
12 | }
13 | }
14 |
15 | if (parent) return parent;
16 | }
17 | }
18 | };
--------------------------------------------------------------------------------
/src/components/my-ui/src/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 |
3 | import MyTabs from '../packages/tabs/index.js';
4 | import MyTabItem from '../packages/tab-item/index.js';
5 | import MySwipe from '../packages/swipe/index.js';
6 | import MySwipeItem from '../packages/swipe-item/index.js';
7 | import MyLoading from '../packages/loading';
8 |
9 | const components = [
10 | MyTabs,
11 | MyTabItem,
12 | MySwipe,
13 | MySwipeItem,
14 | MyLoading
15 | ];
16 |
17 | components.map(component => {
18 | Vue.component(component.name, component);
19 | });
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
25 |
26 |
32 |
--------------------------------------------------------------------------------
/src/vant.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import { Cell, Row, Col, Notify, Tag, Lazyload, List, Rate, Tab, Tabs, button, Field, Icon, Toast, Dialog } from 'vant';
3 | import errImg from './assets/img-error.png';
4 | import loadingImg from './assets/img-loading.gif';
5 |
6 | [
7 | Cell,
8 | Row,
9 | Col,
10 | Notify,
11 | Tag,
12 | List,
13 | Rate,
14 | Tab,
15 | Tabs,
16 | button,
17 | Field,
18 | Icon,
19 | Toast,
20 | Dialog
21 | ].forEach(component => {
22 | Vue.use(component);
23 | });
24 |
25 | Vue.use(Lazyload, {
26 | preLoad: 1.3,
27 | error: errImg,
28 | loading: loadingImg
29 | })
--------------------------------------------------------------------------------
/src/scss/mixin.scss:
--------------------------------------------------------------------------------
1 | @mixin fixedLayout($top: 0, $right: 0, $bottom: 0, $left: 0, $bg: #fff) {
2 | position: fixed;
3 | left: $left;
4 | top: $top;
5 | right: $right;
6 | bottom: $bottom;
7 | background: $bg;
8 | overflow: auto;
9 | }
10 |
11 | @mixin absoluteLayout($top: 0, $right: 0, $bottom: 0, $left: 0) {
12 | position: absolute;
13 | left: $left;
14 | top: $top;
15 | right: $right;
16 | bottom: $bottom;
17 | }
18 |
19 | @mixin heightLineHeight($height) {
20 | height: $height;
21 | line-height: $height;
22 | }
23 |
24 | @mixin textEllipsis () {
25 | white-space: nowrap;
26 | overflow: hidden;
27 | text-overflow: ellipsis;
28 | }
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 | import router from './router'
4 | import store from './store/index'
5 | import 'lib-flexible/flexible.js'
6 | import { delLoading } from '@/utils/dom'
7 |
8 | import './scss/index.scss';
9 |
10 | import './directive';
11 |
12 | import './vant';
13 |
14 | import './createApi';
15 |
16 | // 引入自定义ui组件
17 | import '@/components/my-ui/src';
18 |
19 | Vue.config.productionTip = false
20 |
21 | // 这个是删除loading指令生成的元素的,现已弃用loading指令,改用loading组件了。
22 | router.beforeEach((to, from, next) => {
23 | delLoading();
24 | next();
25 | })
26 |
27 | new Vue({
28 | router,
29 | store,
30 | render: h => h(App)
31 | }).$mount('#app')
32 |
--------------------------------------------------------------------------------
/src/components/my-ui/packages/tab-item/src/main.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
30 |
31 |
34 |
--------------------------------------------------------------------------------
/src/mixins/showMovieDetail.js:
--------------------------------------------------------------------------------
1 | export default {
2 | data () {
3 | return {
4 | detailComp: null,
5 | selectedMovie: {}
6 | }
7 | },
8 |
9 | methods: {
10 | handleMovieSelect(movie) {
11 | this.selectedMovie = movie;
12 | this.showDetail();
13 | },
14 |
15 | showDetail() {
16 |
17 | // 创建movieDetail组件api
18 | this.detailComp = this.detailComp || this.$createMovieDetail({
19 | $props: {
20 | movie: 'selectedMovie'
21 | }
22 | })
23 | this.detailComp.show()
24 | this.$nextTick(_ => {
25 | this.detailComp.init()
26 | })
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/src/utils/searchHistory.js:
--------------------------------------------------------------------------------
1 | export function getSearchHistory () {
2 | return localStorage.searchHistory ? JSON.parse(localStorage.searchHistory) : [];
3 | }
4 |
5 | export function setSearchHistory (keyword) {
6 | let searchHistory = getSearchHistory();
7 |
8 | if (!searchHistory.includes(keyword)) {
9 | searchHistory.unshift(keyword);
10 | localStorage.searchHistory = JSON.stringify(searchHistory);
11 | return searchHistory;
12 | } else {
13 | return false;
14 | }
15 | }
16 |
17 | export function delSearchHistory (keyword) {
18 | let searchHistory = getSearchHistory(),
19 | index = searchHistory.findIndex(val => val === keyword);
20 |
21 | searchHistory.splice(index, 1);
22 | localStorage.searchHistory = JSON.stringify(searchHistory);
23 | return searchHistory;
24 | }
--------------------------------------------------------------------------------
/src/store/modules/collect.js:
--------------------------------------------------------------------------------
1 | import {
2 | getWantSeeMovies,
3 | setWantSeeMovie,
4 | getHaveSeenMovies,
5 | setHaveSeenMovie } from '@/utils/collect';
6 |
7 | const collect = {
8 | state: {
9 | wantSeeMovies: getWantSeeMovies(),
10 | haveSeenMovies: getHaveSeenMovies()
11 | },
12 |
13 | mutations: {
14 | SET_WANT_SEE: (state, wantSeeMovies) => {
15 | state.wantSeeMovies = wantSeeMovies;
16 | },
17 |
18 | SET_HAVE_SEEN: (state, haveSeenMovies) => {
19 | state.haveSeenMovies = haveSeenMovies;
20 | }
21 | },
22 |
23 | actions: {
24 | SetWantSee({ commit }, movie) {
25 | commit('SET_WANT_SEE', setWantSeeMovie(movie))
26 | },
27 |
28 | SetHaveSeen({ commit }, movie) {
29 | commit('SET_HAVE_SEEN', setHaveSeenMovie(movie))
30 | }
31 | }
32 | }
33 |
34 | export default collect;
--------------------------------------------------------------------------------
/src/router.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 |
4 | Vue.use(Router)
5 |
6 | export default new Router({
7 | // mode: 'history',
8 | base: process.env.BASE_URL,
9 | routes: [
10 | {
11 | path: '/',
12 | redirect: '/douban'
13 | },
14 | {
15 | path: '/douban',
16 | component: () => import('@/views/layout/index.vue'), // layout component
17 | redirect: '/douban/movie-list',
18 | children: [{
19 | path: 'movie-list',
20 | component: () => import('@/views/movie-list/index.vue')
21 | },
22 | {
23 | path: 'my-profile',
24 | component: () => import('@/views/user/index.vue')
25 | }]
26 | },
27 | {
28 | path: '/douban/search',
29 | component: () => import('@/views/search/index.vue')
30 | },
31 | {
32 | path: '/wangyi',
33 | component: () => import('@/views/layout/index.vue'),
34 | children: [{
35 | path: 'music',
36 | component: () => import('@/views/music/index.vue')
37 | }]
38 | }
39 | ]
40 | })
41 |
--------------------------------------------------------------------------------
/src/directive/drag/index.js:
--------------------------------------------------------------------------------
1 | function drag (el, binding) {
2 | el.ontouchstart = function (ev) {
3 | let touches = ev.touches[0];
4 | let documentW = document.body.clientWidth;
5 | let documenth = document.body.clientHeight;
6 | let maxLeft = documentW - el.clientWidth;
7 | let maxTop = documenth - el.clientHeight;
8 | let disX = touches.clientX - el.offsetLeft;
9 | let disY = touches.clientY - el.offsetTop;
10 |
11 | document.ontouchmove = function (ev) {
12 | let touches = ev.touches[0];
13 | let l = touches.clientX - disX;
14 | let t = touches.clientY - disY;
15 | el.style.left = l < 0 ? 0 : l > maxLeft ? maxLeft + 'px' : l + 'px';
16 | el.style.top = t < 0 ? 0 : t > maxTop ? maxTop + 'px' : t + 'px';
17 | };
18 | document.ontouchend = function () {
19 | document.ontouchmove = null;
20 | document.ontouchend = null;
21 | };
22 | };
23 | }
24 |
25 | export default {
26 | bind (el, binding) {
27 | drag(el, binding);
28 | }
29 | }
--------------------------------------------------------------------------------
/src/store/modules/searchHistory.js:
--------------------------------------------------------------------------------
1 | import {
2 | getSearchHistory,
3 | setSearchHistory,
4 | delSearchHistory
5 | } from '@/utils/searchHistory';
6 |
7 | const searchHistory = {
8 | state: {
9 | history: getSearchHistory(),
10 | },
11 |
12 | mutations: {
13 | SET_SEARCH_HISTORY(state, history) {
14 | state.history = history;
15 | },
16 |
17 | CLEAR_SEARCH_HISTORY (state) {
18 | state.history = [];
19 | }
20 | },
21 |
22 | actions: {
23 | SetSearchHistory ({ commit }, keyword) {
24 | let searchHistory = setSearchHistory(keyword);
25 | if (!searchHistory) return;
26 | commit('SET_SEARCH_HISTORY', searchHistory)
27 | },
28 |
29 | DelSearchHistory ({ commit }, keyword) {
30 | commit('SET_SEARCH_HISTORY', delSearchHistory(keyword));
31 | },
32 |
33 | ClearSearchHistory ({ commit }) {
34 | localStorage.removeItem('searchHistory');
35 | commit('CLEAR_SEARCH_HISTORY');
36 | }
37 | }
38 | }
39 |
40 | export default searchHistory;
--------------------------------------------------------------------------------
/src/components/my-ui/packages/swipe-item/src/main.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
42 |
43 |
56 |
--------------------------------------------------------------------------------
/src/utils/request.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 |
3 | // 取消前面请求
4 | let pending = [];
5 | let cancelToken = axios.CancelToken;
6 | let removePending = (config) => {
7 | for(let p in pending){
8 | if(pending[p].u === config.url + '&' + config.method) {
9 | pending[p].f();
10 | pending.splice(p, 1);
11 | }
12 | }
13 | }
14 |
15 | const service = axios.create({
16 | baseURL: '',
17 | timeout: 50000
18 | })
19 |
20 | // 请求拦截
21 | service.interceptors.request.use(
22 | config => {
23 | removePending(config); //在一个ajax发送前执行一下取消操作
24 | config.cancelToken = new cancelToken((c)=>{
25 | pending.push({ u: config.url + '&' + config.method, f: c });
26 | });
27 | return config;
28 | },
29 | error => {
30 | Promise.reject(error)
31 | }
32 | )
33 |
34 | // 响应拦截
35 | service.interceptors.response.use(
36 | response => {
37 | removePending(response.config);
38 | return response.data
39 | },
40 | error => {
41 | console.log('err' + error)
42 | return Promise.reject(error)
43 | }
44 | )
45 |
46 | export default service
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vant-shop",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build"
8 | },
9 | "dependencies": {
10 | "axios": "^0.18.0",
11 | "lib-flexible": "^0.3.2",
12 | "vant": "^1.5.1",
13 | "vue": "^2.5.21",
14 | "vue-create-api": "^0.2.0",
15 | "vue-router": "^3.0.1",
16 | "vuex": "^3.0.1"
17 | },
18 | "devDependencies": {
19 | "@vue/cli-plugin-babel": "^3.2.0",
20 | "@vue/cli-service": "^3.2.0",
21 | "babel-plugin-import": "^1.11.0",
22 | "node-sass": "^4.9.0",
23 | "postcss-pxtorem": "^4.0.1",
24 | "sass-loader": "^7.0.1",
25 | "vue-template-compiler": "^2.5.21"
26 | },
27 | "postcss": {
28 | "plugins": {
29 | "autoprefixer": {
30 | "browsers": [
31 | "Android >= 4.0",
32 | "iOS >= 7"
33 | ]
34 | },
35 | "postcss-pxtorem": {
36 | "rootValue": 37.5,
37 | "propList": [
38 | "*"
39 | ]
40 | }
41 | }
42 | },
43 | "browserslist": [
44 | "> 1%",
45 | "last 2 versions",
46 | "not ie <= 8"
47 | ]
48 | }
49 |
--------------------------------------------------------------------------------
/src/components/my-ui/src/mixins/emitter.js:
--------------------------------------------------------------------------------
1 | function broadcast(componentName, eventName, params) {
2 | this.$children.forEach(child => {
3 | var name = child.$options.name;
4 |
5 | if (name === componentName) {
6 | child.$emit.apply(child, [eventName].concat(params));
7 | } else {
8 | broadcast.apply(child, [componentName, eventName].concat([params]));
9 | }
10 | });
11 | }
12 | export default {
13 | methods: {
14 | dispatch(componentName, eventName, params) {
15 | var parent = this.$parent || this.$root;
16 | var name = parent.$options.name;
17 |
18 | while (parent && (!name || name !== componentName)) {
19 | parent = parent.$parent;
20 |
21 | if (parent) {
22 | name = parent.$options.name;
23 | }
24 | }
25 | if (parent) {
26 | parent.$emit.apply(parent, [eventName].concat(params));
27 | }
28 | },
29 |
30 | broadcast(componentName, eventName, params) {
31 | broadcast.call(this, componentName, eventName, params);
32 | }
33 | }
34 | };
35 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | vue-douban-wangyi
18 |
19 |
20 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/components/wy-skeleton/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
18 |
19 |
62 |
--------------------------------------------------------------------------------
/src/scss/reset.scss:
--------------------------------------------------------------------------------
1 | /* http://meyerweb.com/eric/tools/css/reset/
2 | v2.0 | 20110126
3 | License: none (public domain)
4 | */
5 |
6 | html, body, div, span, applet, object, iframe,
7 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
8 | a, abbr, acronym, address, big, cite, code,
9 | del, dfn, em, img, ins, kbd, q, s, samp,
10 | small, strike, strong, sub, sup, tt, var,
11 | b, u, i, center,
12 | dl, dt, dd, ol, ul, li,
13 | fieldset, form, label, legend,
14 | table, caption, tbody, tfoot, thead, tr, th, td,
15 | article, aside, canvas, details, embed,
16 | figure, figcaption, footer, header, hgroup,
17 | menu, nav, output, ruby, section, summary,
18 | time, mark, audio, video {
19 | margin: 0;
20 | padding: 0;
21 | border: 0;
22 | font-size: 100%;
23 | font: inherit;
24 | vertical-align: baseline;
25 | }
26 | /* HTML5 display-role reset for older browsers */
27 | article, aside, details, figcaption, figure,
28 | footer, header, hgroup, menu, nav, section {
29 | display: block;
30 | }
31 | body {
32 | line-height: 1;
33 | }
34 | ol, ul {
35 | list-style: none;
36 | }
37 | blockquote, q {
38 | quotes: none;
39 | }
40 | blockquote:before, blockquote:after,
41 | q:before, q:after {
42 | content: '';
43 | content: none;
44 | }
45 | table {
46 | border-collapse: collapse;
47 | border-spacing: 0;
48 | }
--------------------------------------------------------------------------------
/src/components/header/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
19 |
20 |
61 |
--------------------------------------------------------------------------------
/src/utils/song.js:
--------------------------------------------------------------------------------
1 | class Song {
2 | constructor({ id, name, coverImgUrl, tracks, trackIds }) {
3 | this.id = id;
4 | this.name = name;
5 | this.coverImgUrl = coverImgUrl;
6 | this.tracks = tracks.map(val => new Track(val));
7 | this.trackIds = trackIds;
8 | }
9 | }
10 |
11 | class Track {
12 | constructor ({ id, name, ar, al, publishTime }) {
13 | this.id = id;
14 | this.name = name;
15 | this.artists = ar;
16 | this.album = al;
17 | this.publishTime = publishTime;
18 | }
19 | }
20 |
21 | export function setSongData (data) {
22 | return new Song(data);
23 | }
24 |
25 | // 歌词转换
26 | export function lrc2Json (lrc) {
27 | var arr = lrc.split('\n')
28 | let timeReg = /^\[.*\](.*)/
29 | let json = []
30 | arr = arr.slice(0, arr.length - 1);
31 | arr.forEach(item => {
32 | let match = item.match(timeReg);
33 | let time = match ? match[0].substr(1, 8) : '';
34 | let minute = time.substr(0, 2)
35 | let second = time.substr(3, 2)
36 | let ms = time.substr(6, 2)
37 |
38 | json.push({
39 | time,
40 | ms: parseInt(minute) * 60 * 1000 + parseInt(second) * 1000 + parseInt(ms) * 10,
41 | content: match ? match[1] : ''
42 | })
43 | })
44 | return json;
45 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue+vant实现豆瓣电影加网易云音乐webapp
2 |
3 | ## 说明
4 | 做这个项目最主要的目的是为了**练习与巩固vue**,所以个人是本着**怎么折腾怎么来**的原则做的。怎么折腾法呢?比如豆瓣部分我使用了vant,网易云部分则没有,网易的ui组件则是自己造的轮子,当然在实际开发中肯定不会这么搞啦。。还有个人平时看过的知识,像createApi啥的会应用上,毕竟看过不如写过嘛,所以通过这么“折腾”的项目,能够学习到很多东西哦!
5 |
6 | ## 预览
7 | [点我预览](http://67.216.223.155/dbwy) 或者手机扫描以下二维码 (pc请在移动端模式下预览)。
8 |
9 | 
10 |
11 | ## 运行
12 | ```
13 | git clone git@github.com:OuZuYu/vue-vant-douban-wangyiyun.git
14 | ```
15 | ```
16 | npm install
17 | ```
18 | ```
19 | npm run serve
20 | ```
21 |
22 | ## 动图预览
23 | ##### 豆瓣电影
24 | 
25 |
26 | ##### 网易云音乐
27 | 
28 |
29 | ##### 收藏
30 | 
31 |
32 |
33 | ## 主要功能:
34 |
35 | 1. rem适配
36 |
37 | 2. 欢迎页 骨架屏
38 |
39 | 3. 地区定位 加载地区热映电影 即将上映 top250
40 |
41 | 4. 电影搜索
42 |
43 | 5. 电影详情
44 |
45 | 6. 影人详情
46 |
47 | 7. 跳转到电影网站观看电影
48 |
49 | 8. 电影收藏(想看,看过)
50 |
51 | 9. 歌单查看
52 |
53 | 10. 全屏播放器 可拖拽mini播放器 歌词滚动
54 |
55 | 11. ......
56 |
57 | ### 2019-3-7更新:
58 | - 定位:先使用搜狐,若失败再使用百度地图。
59 | - 优化loading,从loading指令改成了loading组件。
60 |
61 | ### 2019-3-9更新
62 | - 发现歌单背景高斯模糊效果,在小米自带浏览器下过度时卡顿,所以去掉了改了下歌单样式。
63 | - 还是小米自带的浏览器。。修复了获取不了歌曲总长度的bug。
64 | - 修复了歌词过长时文字重叠bug。
65 | - 从一个歌单快速切换到另一个歌单时,可能会出现显示的是前一个歌单的歌曲的情况,所以axios增加请求前先取消前面请求的配置。
66 |
67 | ### 2019-3-22更新
68 | - 加快电影详情滑动速度
69 | - 增加手动输入城市
--------------------------------------------------------------------------------
/src/views/layout/components/AppTabs.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
23 |
24 |
56 |
--------------------------------------------------------------------------------
/src/api/wangyi.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 | import axios from 'axios';
3 |
4 | const BASE = 'http://67.216.223.155:3000';
5 |
6 | export function getBanner (params) {
7 | return request({
8 | url: BASE + '/banner',
9 | method: 'get',
10 | params
11 | })
12 | }
13 |
14 | export function getPersonalized (params) {
15 | return request({
16 | url: BASE + '/personalized',
17 | method: 'get',
18 | params
19 | })
20 | }
21 |
22 | export function getRecommonData (apiNames) {
23 | var api = {
24 | personalizedData: getBanner(),
25 | bannerData: getPersonalized()
26 | },
27 | apiNames = apiNames || ['personalizedData', 'bannerData'],
28 | apiArr = apiNames.map(item => api[item]);
29 |
30 | return axios.all(apiArr).then(axios.spread(function (banner, personalized) {
31 | return Promise.resolve([banner, personalized])
32 | })).catch(err => {
33 | return Promise.reject(err)
34 | })
35 | }
36 |
37 | export function getPlayList (id) {
38 | return request({
39 | url: BASE + '/playlist/detail',
40 | method: 'get',
41 | params: {
42 | id,
43 | t: Date.now()
44 | }
45 | })
46 | }
47 |
48 | export function getMusicUrl (id) {
49 | return request({
50 | url: BASE + '/song/url',
51 | method: 'get',
52 | params: {
53 | id
54 | }
55 | })
56 | }
57 |
58 | export function getLyric (id) {
59 | return request({
60 | url: BASE + '/lyric',
61 | method: 'get',
62 | params: {
63 | id
64 | }
65 | })
66 | }
--------------------------------------------------------------------------------
/src/mixins/location.js:
--------------------------------------------------------------------------------
1 | import { mapState, mapActions, mapMutations } from 'vuex'
2 |
3 | export default {
4 | computed: {
5 | ...mapState({
6 | myCity: state => state.location.myCity
7 | })
8 | },
9 |
10 | methods: {
11 | ...mapActions([
12 | 'GetCity'
13 | ]),
14 |
15 | ...mapMutations({
16 | setCity: 'SET_CITY'
17 | })
18 |
19 | // 直接用百度地图api获取城市
20 | /* getCity() {
21 | return new Promise((resolve, reject) => {
22 | if (this.$store.state.location.hasCity) {
23 | resolve();
24 | }
25 | let myCity = new BMap.LocalCity();
26 | myCity.get(res => {
27 | this.storeCity(res.name);
28 | resolve(res.name);
29 | })
30 | })
31 | }, */
32 |
33 | /* 获取位置h5版
34 | getLocationData () {
35 | if (navigator.geolocation) {
36 | navigator.geolocation.getCurrentPosition(position => {
37 | this.setLocation(position);
38 | }, error => {
39 | this.$notify({
40 | message: '获取位置失败,请稍后再试!',
41 | duration: 2000,
42 | background: '#FF8C69'
43 | });
44 | });
45 | } else {
46 | this.$notify({
47 | message: '您的设备不支持navigator!',
48 | duration: 2000,
49 | background: '#FF8C69'
50 | });
51 | }
52 | },
53 | setLocation (position) {
54 | this.SaveLocation(position);
55 | }*/
56 | }
57 | }
--------------------------------------------------------------------------------
/src/utils/common.js:
--------------------------------------------------------------------------------
1 | /*
2 | @param dom 要滚动的元素
3 | @param fromY 开始位置
4 | @param toY 结束位置
5 | @param duration 滚动速度
6 | */
7 | export function scrollTo (dom, fromY, toY, duration = 500) {
8 | let from = fromY,
9 | to = toY,
10 | s = Math.abs(from - to), // 滚动路程
11 | v = Math.ceil(s / duration * 50); // 速度
12 |
13 | // requestAnimationFrame性能更好更加顺滑
14 | if (!window.requestAnimationFrame) {
15 | window.requestAnimationFrame = (window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) { return window.setTimeout(callback, 1000 / 60); });
16 | }
17 |
18 | function scroll (start, end, step) {
19 | if (start === end) return;
20 |
21 | let d = (start + step > end) ? end : start + step;
22 | if (start > end) {
23 | d = (start - step < end) ? end : start - step;
24 | }
25 |
26 | dom.scrollTo(d, d);
27 |
28 | window.requestAnimationFrame(() => scroll(d, end, step));
29 | }
30 | scroll(from, to, v);
31 | }
32 |
33 | // 节流
34 | export function throttle (fn, wait) {
35 | let timmer = null;
36 |
37 | return function () {
38 | if (!timmer) { // 只有当上一个定时器完成,才把执行fn添加到队列。
39 | timmer = setTimeout(() => {
40 | fn.apply(this, arguments);
41 | timmer = null;
42 | }, wait);
43 | }
44 | }
45 | }
46 |
47 | // 防抖
48 | export function debounce (fn, wait) {
49 | let timmer = null;
50 |
51 | return function () {
52 | if (timmer) clearTimeout(timmer);
53 |
54 | timmer = setTimeout(() => {
55 | fn.apply(this, arguments);
56 | }, wait);
57 | }
58 | }
--------------------------------------------------------------------------------
/src/store/modules/song.js:
--------------------------------------------------------------------------------
1 | const song = {
2 | state: {
3 | tracks: [], // 歌单
4 | curSongIdx: 0,
5 | isFullscreen: false
6 | },
7 |
8 | getters: {
9 | curSong: state => state.tracks[state.curSongIdx]
10 | },
11 |
12 | mutations: {
13 | SET_TRACKS (state, tracks) {
14 | state.tracks = tracks;
15 | state.curSongIdx = 0;
16 | },
17 |
18 | SET_SONG_INDEX (state, index) {
19 | state.curSongIdx = index;
20 | },
21 |
22 | CHANGE_ISFULLSCREEN (state, isFullscreen) {
23 | state.isFullscreen = isFullscreen;
24 | }
25 | },
26 |
27 | actions: {
28 | SetTracks ({ commit }, tracks) {
29 | commit('SET_TRACKS', tracks);
30 | },
31 |
32 | SetSongIndex ({ commit }, index) {
33 | commit('SET_SONG_INDEX', index);
34 | },
35 |
36 | ChangeTrack({ commit, state }, { direction, random }) {
37 | let curIndex = state.curSongIdx,
38 | length = state.tracks.length,
39 | lastIndex = length - 1,
40 | newIndex = 0;
41 |
42 | if (random) {
43 | newIndex = Math.floor(Math.random() * length)
44 | } else {
45 | if (direction === 'next') {
46 | newIndex = curIndex === lastIndex ? 0 : ++curIndex;
47 | } else if (direction === 'prev') {
48 | newIndex = curIndex === 0 ? lastIndex : --curIndex;
49 | }
50 | }
51 |
52 | commit('SET_SONG_INDEX', newIndex);
53 | },
54 |
55 | ChangeIsFullScreen ({ commit }, fullScreen) {
56 | commit('CHANGE_ISFULLSCREEN', fullScreen);
57 | }
58 | }
59 | }
60 |
61 | export default song;
--------------------------------------------------------------------------------
/src/api/douban.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export function getMovie(params) {
4 | params.apikey = '0b2bdeda43b5688921839c8ecb20399b';
5 |
6 | return request({
7 | url: '/v2/movie/in_theaters',
8 | method: 'get',
9 | params
10 | })
11 | }
12 |
13 | export function getTop250Movie(start, count) {
14 | const params = {
15 | apikey: '0b2bdeda43b5688921839c8ecb20399b',
16 | start,
17 | count
18 | }
19 | return request({
20 | url: '/v2/movie/top250',
21 | method: 'get',
22 | params
23 | })
24 | }
25 |
26 | export function getComingSoonMovie(start, count) {
27 | const params = {
28 | apikey: '0b2bdeda43b5688921839c8ecb20399b',
29 | start,
30 | count
31 | }
32 | return request({
33 | url: '/v2/movie/coming_soon',
34 | method: 'get',
35 | params
36 | })
37 | }
38 |
39 | export function getMovieDetail(id) {
40 | const params = {
41 | apikey: '0b2bdeda43b5688921839c8ecb20399b'
42 | }
43 | return request({
44 | url: '/v2/movie/subject/' + id,
45 | method: 'get',
46 | params
47 | })
48 | }
49 |
50 | export function searchMovie (keyword, tag, start, count) {
51 | const params = {
52 | apikey: '0b2bdeda43b5688921839c8ecb20399b',
53 | q: keyword,
54 | tag,
55 | start,
56 | count
57 | }
58 | return request({
59 | url: '/v2/movie/search',
60 | method: 'get',
61 | params
62 | })
63 | }
64 |
65 | export function getCastDetail (id) {
66 | const params = {
67 | apikey: '0b2bdeda43b5688921839c8ecb20399b',
68 | }
69 | return request({
70 | url: '/v2/movie/celebrity/' + id,
71 | method: 'get',
72 | params
73 | })
74 | }
--------------------------------------------------------------------------------
/src/components/horizontal-list/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
40 |
41 |
86 |
--------------------------------------------------------------------------------
/src/utils/collect.js:
--------------------------------------------------------------------------------
1 | export function getWantSeeMovies () {
2 | return localStorage.wantSeeMovies ? JSON.parse(localStorage.wantSeeMovies) : [];
3 | }
4 |
5 | // 在想看数组中添加或移除电影
6 | export function setWantSeeMovie (movie) {
7 | let wantSeeMoviesArr = getWantSeeMovies();
8 | let index = wantSeeMoviesArr.findIndex(movieItem => movieItem.id === movie.id);
9 | if (index > -1) {
10 | wantSeeMoviesArr.splice(index, 1);
11 | } else {
12 | wantSeeMoviesArr.unshift(movie);
13 | }
14 | localStorage.wantSeeMovies = JSON.stringify(wantSeeMoviesArr);
15 | return wantSeeMoviesArr;
16 | }
17 |
18 | export function getHaveSeenMovies() {
19 | return localStorage.haveSeenMovies ? JSON.parse(localStorage.haveSeenMovies) : [];
20 | }
21 |
22 | // 在已看数组中添加或移除电影
23 | export function setHaveSeenMovie(movie) {
24 | let haveSeenMoviesArr = getHaveSeenMovies();
25 | let index = haveSeenMoviesArr.findIndex(movieItem => movieItem.id === movie.id);
26 |
27 | if (index > -1) {
28 | haveSeenMoviesArr.splice(index, 1);
29 | } else {
30 | haveSeenMoviesArr.unshift(movie);
31 | }
32 | localStorage.haveSeenMovies = JSON.stringify(haveSeenMoviesArr);
33 | return haveSeenMoviesArr;
34 | }
35 |
36 | // 电影对象工厂
37 | export function setMovieObj (movie) {
38 | return {
39 | id: movie.id,
40 | title: movie.title,
41 | images: movie.images,
42 | rating: movie.rating,
43 | directors: movie.directors,
44 | casts: movie.casts
45 | }
46 | }
47 |
48 | // 检查是否已经存到了想看
49 | export function checkWantSee (id) {
50 | let wantSeeMovies = getWantSeeMovies();
51 | let index = wantSeeMovies.findIndex(movie => movie.id === id);
52 | return index > -1;
53 | }
54 |
55 | // 检查是否已经存到了已看数组
56 | export function checkHaveSeen (id) {
57 | let wantSeeMovies = getHaveSeenMovies();
58 | let index = wantSeeMovies.findIndex(movie => movie.id === id);
59 | return index > -1;
60 | }
--------------------------------------------------------------------------------
/src/utils/dom.js:
--------------------------------------------------------------------------------
1 | const SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
2 | const MOZ_HACK_REGEXP = /^moz([A-Z])/;
3 |
4 | // 例:-moz-transition 替换为 -Moz-TRANSITION
5 | const camelCase = function (name) {
6 | return name.replace(SPECIAL_CHARS_REGEXP, function (_, separator, letter, offset) {
7 | /**
8 | * _:匹配文本
9 | * separator:第一个匹配组
10 | * letter:第二个匹配组
11 | * offset:匹配文本下标index
12 | */
13 | return offset ? letter.toUpperCase() : letter;
14 | }).replace(MOZ_HACK_REGEXP, 'Moz$1');
15 | };
16 |
17 | export let cssUtils = {
18 | setStyle(el, prop, val) {
19 | el.style[prop] = val;
20 | },
21 |
22 | setCss(el, styles) {
23 | for (let key of Object.keys(styles)) {
24 | this.setStyle(el, key, styles[key]);
25 | }
26 | }
27 | }
28 |
29 | // 获取dom到文档顶部或左边的距离
30 | export function getDistance(element, type) {
31 | let direction = type === 'top' ? 'offsetTop' : type === 'left' ? 'offsetLeft' : '';
32 | let distance = element[direction];
33 | let current = element.offsetParent;
34 | while (current !== null) {
35 | distance += current[direction];
36 | current = current.offsetParent;
37 | }
38 | return distance;
39 | }
40 |
41 | export function delLoading () {
42 | let loadingDoms = document.querySelectorAll('.loading-wrap');
43 | if (loadingDoms) {
44 | for (let loadingDom of loadingDoms) {
45 | document.body.removeChild(loadingDom);
46 | }
47 | }
48 | }
49 |
50 | /* istanbul ignore next */
51 | export const getStyle = function (element, styleName) {
52 | if (!element || !styleName) return null;
53 | styleName = camelCase(styleName);
54 | if (styleName === 'float') {
55 | styleName = 'cssFloat';
56 | }
57 | try {
58 | var computed = document.defaultView.getComputedStyle(element, '');
59 | return element.style[styleName] || computed ? computed[styleName] : null;
60 | } catch (e) {
61 | return element.style[styleName];
62 | }
63 | };
--------------------------------------------------------------------------------
/src/store/modules/location.js:
--------------------------------------------------------------------------------
1 | const SOHU_GETCITY_API = 'http://pv.sohu.com/cityjson?ie=utf-8';
2 | const SCRIPT_ID = 'location';
3 |
4 | function locationBySouhu (commit, state) {
5 | let oldScript = document.getElementById(SCRIPT_ID);
6 | let body = document.getElementsByTagName('body')[0];
7 | let script = document.createElement('script');
8 |
9 | if (oldScript) body.removeChild(oldScript);
10 |
11 | script.id = SCRIPT_ID;
12 | script.type = 'text/javascript';
13 | script.src = SOHU_GETCITY_API + `&t=${Date.now()}`;
14 | body.appendChild(script);
15 |
16 | return new Promise((resolve, reject) => {
17 | script.onload = () => {
18 | if (returnCitySN && returnCitySN.cname && returnCitySN.cname !== '国内未能识别的地区') {
19 | console.log('搜狐定位:' + returnCitySN.cname)
20 | let city = returnCitySN.cname.match(/.+?(省|市|自治区|自治州|县|区)/g);
21 | let index = city.findIndex(val => val.indexOf('市') !== -1); // 找到第一个市
22 | resolve(city[index]);
23 | }
24 | }
25 | });
26 | }
27 |
28 | function locationByBaidu (commit, state) {
29 | let city = new BMap.LocalCity();
30 | return new Promise((resolve, reject) => {
31 | city.get(res => {
32 | console.log('百度定位:' + res.name)
33 | resolve(res.name);
34 | })
35 | });
36 | }
37 |
38 |
39 | const location = {
40 | state: {
41 | longitude: '',
42 | latitude: '',
43 | myCity: '定位中...',
44 | flag: true
45 | },
46 |
47 | mutations: {
48 | SET_CITY: (state, city) => {
49 | state.myCity = city || '广州';
50 | },
51 |
52 | SET_FLAG (state) {
53 | state.flag = !state.flag;
54 | }
55 | },
56 |
57 | actions: {
58 | async GetCity({ commit, state }) {
59 |
60 | // 轮流使用搜狐或百度定位
61 | let city = state.flag ? await locationBySouhu() : await locationByBaidu();
62 | console.log(city)
63 | if (/^.+市$/.test(city)) {
64 | city = city.slice(0, -1)
65 | }
66 | commit('SET_CITY', city);
67 | commit('SET_FLAG');
68 | return city;
69 | },
70 | }
71 | }
72 |
73 | export default location;
--------------------------------------------------------------------------------
/src/directive/loading/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 这个指令操作dom,性能不好,已改用 my-loadingu 组件。
3 | */
4 |
5 | import { getDistance, cssUtils } from '@/utils/dom';
6 | import loadingGif from './loading.gif';
7 |
8 | const LOADING_WRAP_ID = 'loadingWrap';
9 | const LOADING_WRAP_CLASS = 'loading-wrap';
10 | const LOADING_ID = 'loadingGif'
11 | let loadingCount = 1;
12 |
13 | function createLoading(left, top, width, height,) {
14 | let mask = document.createElement('div');
15 | let loading = document.createElement('img');
16 |
17 | mask.id = LOADING_WRAP_ID + loadingCount;
18 | mask.className = LOADING_WRAP_CLASS;
19 | loadingCount++;
20 | cssUtils.setCss(mask, {
21 | 'zIndex': '10000',
22 | 'display': 'flex',
23 | 'justify-content': 'center',
24 | 'align-items': 'center',
25 | 'position': 'fixed',
26 | 'left': left + 'px',
27 | 'top': top + 'px',
28 | 'width': width + 'px',
29 | 'height': height + 'px',
30 | 'background': 'rgba(173, 173, 173, .8)',
31 | 'text-align': 'center'
32 | });
33 |
34 | loading.id = LOADING_ID;
35 | loading.src = loadingGif;
36 | cssUtils.setCss(loading, {
37 | width: '40%',
38 | height: '40%',
39 | 'min-height': '30px'
40 | });
41 |
42 | mask.appendChild(loading);
43 | return mask;
44 | }
45 |
46 | function toggleLoading (el, binding) {
47 | setTimeout(() => {
48 | if (binding.value) { // 开启
49 | let top = getDistance(el, 'top');
50 | let left = getDistance(el, 'left');
51 | let width = el.clientWidth;
52 | let height = el.clientHeight;
53 | let loadingDom = createLoading(left, top, width, height);
54 | document.body.appendChild(loadingDom);
55 | } else { // 关闭
56 | for (let i = 0; i < loadingCount; i++) {
57 | let loadingDom = document.getElementById(LOADING_WRAP_ID + i);
58 | if (loadingDom) document.body.removeChild(loadingDom);
59 | }
60 | loadingCount = 1;
61 | }
62 | }, 0);
63 | }
64 |
65 | export default {
66 | bind(el, binding) {
67 | toggleLoading(el, binding);
68 | },
69 |
70 | update (el, binding) {
71 | toggleLoading(el, binding);
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/components/vertical-list/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
{{ movie.title }}
8 |
9 |
10 | {{ movie.rating.average }}
11 |
12 |
13 | 导演: {{ director.name }}
14 |
15 |
16 | 主演: {{ cast.name }}
17 |
18 |
{{ movie.collect_count }}人看过
19 |
20 |
21 |
22 |
23 |
24 |
50 |
51 |
95 |
--------------------------------------------------------------------------------
/src/views/movie-detail/components/MovieInfo.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ detailData.title }}
5 |
6 | {{ detailData.year }}
7 |
8 | {{ item }} /
9 |
10 |
11 | 原名: {{ detailData.original_title }}
12 | 上映时间: {{ pubdate }}
13 | 片长: {{ detailData.durations && detailData.durations[0] }}
14 |
15 |
16 |
17 | 豆瓣评分
18 | {{ detailData.rating && detailData.rating.average }}
19 |
20 | {{ detailData.collect_count }}人
21 |
22 |
23 |
24 |
25 |
53 |
54 |
94 |
--------------------------------------------------------------------------------
/src/components/song-list/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 | {{ index + 1 }}
6 |
7 |
{{ item.name }}
8 |
{{ artist.name }}
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
40 |
41 |
101 |
--------------------------------------------------------------------------------
/src/views/user/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--没有想看的电影--
15 |
--请先到电影详情中点"想看"--
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--没有看过的电影--
25 |
--请先到电影详情中点"看过"--
26 |
27 |
28 |
29 |
30 |
31 |
32 |
58 |
59 |
107 |
--------------------------------------------------------------------------------
/src/views/welcome/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
跳过 {{ second }}
4 |
welcome
5 |
6 |
{{ currentDate }}
7 |
您位于:{{ myCity }}
8 |
9 |

10 |

11 |
12 |
13 |
14 |
15 |
68 |
69 |
111 |
--------------------------------------------------------------------------------
/src/components/progress/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
67 |
68 |
109 |
--------------------------------------------------------------------------------
/src/components/my-ui/packages/tabs/src/main.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
{{ tab.name }}
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
92 |
93 |
127 |
128 |
--------------------------------------------------------------------------------
/src/views/movie-detail/components/MovieComment.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
19 |
20 | -
21 |
22 |
![]()
23 |
{{ review.author.name }}
24 |
25 |
26 | {{ review.title }}
27 | {{ review.summary }}
28 |
29 |
30 |
31 |
32 |
33 |
34 |
49 |
50 |
117 |
--------------------------------------------------------------------------------
/src/views/movie-detail/components/Operate.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ wantSeeText }}
5 |
6 | {{ haveSeenText }}
7 |
8 |
9 | 去豌豆影视看
10 | 去海兔影视看
11 |
12 |
13 |
14 |
15 |
115 |
116 |
138 |
--------------------------------------------------------------------------------
/src/views/song-list-detail/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
{{ !changeTopStyle ? '歌单' : playListData.name }}
8 |
9 |
{{ playListData.name }}
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
96 |
97 |
159 |
160 |
--------------------------------------------------------------------------------
/src/views/music/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
34 |
35 |
36 | 开发中......
37 |
38 |
39 |
40 |
41 |
42 |
43 |
107 |
108 |
184 |
--------------------------------------------------------------------------------
/src/views/movie-detail/components/CastDetail.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
{{ castData.name }} - {{ castData.name_en }}
10 |
11 |
12 |
13 | - 性别:{{ castData.gender || '暂无信息' }}
14 | - 星座:{{ castData.constellation || '暂无信息' }}
15 | - 出生日期:{{ castData.birthday || '暂无信息' }}
16 | - 出生地:{{ castData.born_place || '暂无信息' }}
17 | - 更多中文名:{{ name }}
18 |
19 |
20 |
21 |
![头像]()
22 |
23 |
24 |
25 |
26 | 搜索
27 |
28 |
29 |
30 |
影人介绍
31 |
32 | {{ summary }}
33 | (展开)
34 |
35 |
36 |
37 |
38 |
代表作品
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
130 |
131 |
214 |
--------------------------------------------------------------------------------
/src/views/movie-detail/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 电影
6 |
7 |
8 |
9 |
![]()
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | 剧情简介
18 |
19 | {{ summary }}
20 | (展开)
21 |
22 |
23 |
24 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
143 |
144 |
222 |
--------------------------------------------------------------------------------
/src/views/search/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 取消
7 |
8 |
9 |
10 |
11 | {{ tag }}
12 |
13 |
14 | {{ tag }}
15 |
16 |
17 | {{ tag }}
18 |
19 |
20 |
21 |
22 |
26 |
27 |
28 |
29 | {{ item }}
30 | ×
31 |
32 |
33 |
34 |
--- 暂无记录 ---
35 |
36 |
37 |
38 |
39 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
147 |
148 |
231 |
--------------------------------------------------------------------------------
/src/components/my-ui/packages/loading/src/main.vue:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
114 |
115 |
273 |
274 |
279 |
--------------------------------------------------------------------------------
/src/views/movie-list/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
13 |
14 |
15 | {{ movieData.title }}
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
179 |
180 |
243 |
--------------------------------------------------------------------------------
/src/components/my-ui/packages/swipe/src/main.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
255 |
256 |
287 |
288 |
--------------------------------------------------------------------------------
/src/views/music-player/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
17 |
18 |
19 |
20 |
21 |
![]()
22 |
23 |
24 |
25 |
26 |
27 |
{{ lyricTip }}
28 |
29 |
34 | {{item.content}}
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
{{ songLoadingText }}
43 |
44 |
{{ formatTime(currentTime) }}
45 |
46 |
{{ formatTime(duration) }}
47 |
48 |
49 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | {{ curSong.name }}
71 |
72 | {{ item.name }}
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
91 |
92 |
93 |
94 |
294 |
295 |
492 |
--------------------------------------------------------------------------------