炸鸡音乐,vue,spa项目分析

项目描述:Web App,QQ音乐界面风格,SPA应用

技术描述:

1.fast-click处理移动端点击事件的延迟

2.create-keyframes-animation处理css动画

3.jsonp npm封装,跨域获取数据

4.vue-lazyload实现页面懒加载

5.loading实现网络加载过程中的界面效果

6.axios数据请求

7.webpack+vue-cli自动化构建项目

8.vue,mixins的运用

9.vuex状态管理器

10.mintui,组件实现区域滚动,首页,歌手详情页面的图片轮播效果

11.webpack实现路由懒加载(异步加载),优化代码,提高首页访问速度

具体实现,要点分析:

 1 . 文件目录结构

dist目录: 

build 打包编译 生成 dist目录(index,js,css,image)vendor文件是打包后的node_modules文件
线上 gzip 压缩 减少代码量 例如 300kb代码 gzip 后是: --》100kb
vendor打包后的 hash值不变 ( static/js/vendor.52caf94d568661fbe99f.js.map)
build打包后dist文件问们可以在启动的node服务器里面进行静态托管(也就是将资源放本地服务器),参照prod.server.js
 
prod.server.js 文件
 
import { match } from "./C:/Users/Administrator/AppData/Local/Microsoft/TypeScript/2.6/node_modules/@types/minimatch";
import { response } from "./C:/Users/Administrator/AppData/Local/Microsoft/TypeScript/2.6/node_modules/@types/spdy
 
const express = require("express")
const config = require("./config/index")
const axios = require("axios")
const app = express();
const apiRoutes = express.Router()    // server的路由分发代理

apiRoutes.get("/getDiscLisc", (req, res) => {
let url = "https://c.y.qq.com/splcloud/fcgi-bin/fcg_get_diss_by_tag.fcg"
axios.get(url, {
headers: {        // 请求数据的时候 采取了两种:  一种是 jsonp npm封装  一种是node代理这种方式:请求后端发起请求数据服务器,设置headers的referer(请求来源地址)host:来源主机, 绕过同源策略,“欺骗数据服务器”
referer: "https://c.yy.qq.com/",
host: "c.y.qq.com"
},
params: req.query
}).then((response) => {
res.json(response.data)
}).catch((e) => {
console.log(e)
})
})

apiRoutes.get("/lyric", (req, res) => {
const url = 'https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg'

axios.get(url, {
headers: {
referer: "https://c.yy,qq.com/",
host: "c.yy.com"
},
params: req.query
}).then((response) => {
let ret = response.data
if (typeof ret === 'string') {
let reg = /^w+(({[^()]+}))$/
let matches = ret.match(reg)
if (matches) {

}
}
})

// apiRoutes.get("/lyric", (req, res) => {


// })
})

app.use("/api", apiRoutes)          //  /api 作为代理地址,前端请求使用这个来请求后端数据     /api+你的前端路由
// 直接将静态资源(托管后的dist目录)作为 托管
app.use(express.static("./dist"))         //这个就是之前说的 将 build 后的静态资源托管,优化,
   // index/.html 里面的img icon 资源 可以放在  托管  static目录下
let port = process.env.PORT || config.build.port
module.exports = app.listen(port, (err) => {
if (err) {
console.log(err)
return
}
console.log("LIstening at http://localhost:" + port + " ")
})
 
main.js:
import store from './store' // ./store -- > 直接载入我的index.js文件
 
state.js 定义数据初始值 : 如下
const state ={
singer : {},
playing: false,
fullScreen:true,
playList:[],
sequenceList:[],
mode:playMode.sequence,
currentIndex:-1,

// 这几个test数据
songs_test:[]
}
export default state
 
 
mutations.js 文件定义对state.js数据的修改函数
import * as types from "./mutation-type"       // 导入预定义变量 * as 写法:代表以 types 点的方式获取变量
 
mutation-type文件
// mutations.js 文件数据: 函数名 在mutations-types 里面配置
export const SET_SINGER = 'SET_SINGER'
export const SET_PLAYING_STATE = 'SET_PLAYING_STATE'
export const SET_FULL_SCREEN = "SET_FULL_SCREEN"
export const SET_PLAYLIST = "SET_PLAYLIST"
export const SET_SEQUENCE_LIST = "SET_SEQUENCE_LIST"
export const SET_PLAY_MODE = "SET_PLAY_MODE"
export const SET_CURRENT_INDEX = "SET_CURRENT_INDEX"
 

const mutations = {
// import * as xx from " " 引入的: 使用的时候 [xx....]
[types.SET_SINGER](state,singer){
state.singer = singer
console.log(state.singer);
console.log("state.singer!!!");
} ,
[types.SET_PLAYING_STATE](state,flag){
state.playing = flag
},
[types.SET_FULL_SCREEN](state,flag){
state.fullScreen = flag
},
[types.SET_PLAYLIST](state,list){
state.playList = list
},
[types.SET_SEQUENCE_LIST](state,list){
state.sequenceList = list
},

[types.SET_PLAY_MODE](state,list){
state.mode = list
},
[types.SET_CURRENT_INDEX](state,index){
state.currentIndex = index
},

// songs_test
songs_test(state,test){
state.songs_test = test
}
}
export default mutations
 
getters.js 文件
 
// 在getters 中取数据 映射到 state上
export const singer = state => {
return state.singer // 返回值必须加 stste => state.singer || (state) =>{ return ...}
}

export const playing = state => state.playing
export const fullScreen = state => state.fullScreen
export const playList = state => state.playList
export const sequenceList = state => state.sequenceList
export const mode = state => state.mode
export const currentIndex = state => state.currentIndex
export const currentSong = (state) => {
return state.playList[state.currentIndex] || {}
}


// songs_test 数据
export const songs_test = state=>state.songs_test
 
 
actions.js 是作为对mutations的提交
// 一个动作多次提交修改mutations 封装actions文件
import * as types from "./mutation-type"

export const selectPlay = function ({commit,state},{list,index}){
 
// commit 去改变 mutations -- 从而改变 state  commit第二个参数是传入到了 对应函数的第二个参数位置上
commit(types.SET_SEQUENCE_LIST,list)
commit(types.SET_PLAYLIST,list)
commit(types.SET_CURRENT_INDEX,index)
commit(types.SET_FULL_SCREEN,true)
commit(types.SET_PLAYING_STATE,true)

}
 
 
router文件 index.js 
// 路由懒加载: 首页加载速度的优化 !!!!!!
 
// 路由懒加载 语法:
const MyRecommend = (resolve) => {
import('@/components/MyRecommend/MyRecommend').then((module) => {
resolve(module)
})
}
 
main.js 

import 'babel-polyfill'
import Vue from 'vue'
import App from './App'
import router from './router' // vue-router
import store from './store' // vuex

import '@/common/scss/index.scss'

// 消除 click 移动浏览器300ms延迟
import attachFastClick from 'fastclick'
attachFastClick.attach(document.body)

// 图片懒加载
import VueLazyload from 'vue-lazyload'
Vue.use(VueLazyload, {  // 懒加载
loading: require('@/common/img/default.png')
})

Vue.config.productionTip = false

new Vue({
el: '#app',
router,
store,
template: '<App/>', // render: h => h(App)
components: { App }
})

原文地址:https://www.cnblogs.com/ccnNL/p/9365442.html