想必你们都看过斗鱼直播吧?此次在下使用从github上面摸下来的API,为你们重现一下斗鱼网站的搭建,使用vue-cli-webpack来实现。
文章内容较多,能够慢慢看css
本文章所用API均从网络获取,本文做者不承担任何法律责任,请阅读本文的小伙伴们用于学习用途,不能用于商业!
若有侵权行为,请与做者联系,做者将于2日内删除。html
本文假设您学习了如下相关知识
nodejs
webpack
vue
vue-cli
vue-routervue
pc端node
移动端webpack
好,扯了这么久的淡,该开始构建项目了ios
打开一个新文件夹,在命令行输入:git
vue init webpack
若是显示vue not found,那么该去下载vue-cli,若是webpack未找到就去下载webpackgithub
到这一步之后就ctrl + c ,退出终端web
退出命令行以后,输入如下指令:vue-router
npm install chromedriver --chromedriver_cdnurl=http://cdn.npm.taobao.org/dist/chromedriver
chromedriver 是安装必备的包,镜像好像有问题,咱们提早装一下。
npm install
GFW不是吹的,外网真的很慢,你们泡杯茶慢慢等
趁着等的时候,咱们来下载几个样式和图片,运行
git clone https://github.com/YexChen/douyu_assets.git
来下载assets文件,覆盖 assets文件夹到 项目文件/src 中
npm i -S lib-flexible npm i -S axios npm i -S vue-axios
咱们还须要lib-flexible来解决移动端适配的问题,axios和vue-axios来方便请求咱们的数据
你们能够进入到src目录下,这里简要介绍下各个文件的功能
assets 放静态内容的地方,可是支持预编译 components 放组件的地方,固然也能够别具一格随便创个文件夹代替之 router/index.js router文件夹是放路由的地方,index.js是咱们的根路由 app.vue vue-cli帮咱们生成好的一个组件(根组件),没什么好稀奇的 main.js webpack的入口文件,聚合vue应用里面的东西
咱们来修改main.js,参照下图:
红线区域咱们引入了移动适配的lib-flexible,和font-awesome,style公共样式
接下来,咱们来引入axios和vue-axios,请看下图:
这里咱们引入了vue-axios和axios,并经过vue.use来进行绑定
准备工做已经作完了,接下来能够跑起项目了:
npm run dev
根据命令行的提示打开网页便可看到效果:
好的,咱们的项目初始化就到这里了。
来到根目录下的 config/index.js 这里是配置开发,构建,及路由映射的地方
如图修改proxyTable中内容,这里解释一下几个参数:
target : 目标地址, changeOrigin : 是否跨域, pathRewrite : 键值对中用值替换键的值,其中^是正则中表示开始的符号
进入src/App.vue,以下修改文件:
created是咱们的生命钩子函数,vue实例在created阶段会执行里面的代码。
this.$http至关于this.axios,$http的具体实现能够去node_modules里面看,很简单的
ctrl+c npm run dev
看到以上效果的话,证实数据请求成功了。
咱们要写的应用较为复杂,写vue的项目就是这样,须要清晰的思想,否则很容易崩溃,最后重来
好,接下来为你们讲解一下咱们的组件:
Root是根组件,一切的源(废话)
App,应用组件,对应src/App.vue Side-menu :侧边栏,由于较为容易且不须要改变单页路由来显示不一样内容,因此直接放在app组件里边 router-view : 这是vue-router的子路由显示面板,经过src/router/index.js来控制 home : 主页视图文件 public : 公用组件,亦可在其余页面使用,下降工做量 AppHeader : 应用头部组件 Loading : 加载中的组件,就一张gif
在src/components目录中新建一个文件,名为SideMenu.vue,修改内容为:
<template lang="html"> <div class="side-menu" @click = "hideSide"> <ul> <router-link v-for = "(item,index) in list" :to="item.url" :key = "index"> {{item.title}} <i class = "icon-chevron-right"></i> </router-link> </ul> </div> </template> <script> export default { data(){ return { list : [ {title : "首页",url : "/"}, {title : "所有分类",url : "/category"} ] } }, methods : { hideSide(){ this.$emit("hide") } } } </script> <style lang="css"> .side-menu { background: rgba(10,10,10,.3); height: 100%; position: fixed; width: 100%; top: 0; padding-top: 44px; z-index: 11; } .side-menu ul { width: 70%; background: #282828; height: 100%; border-top: 1px solid #222; } .side-menu ul li { height: 50px; border-bottom: 1px dotted #333; font-size: 14px; line-height: 50px; padding: 0 30px 0 20px; color: #9a9a9a; } .side-menu ul li i { float: right; line-height: 50px; } </style>
这里解释一下文件里面的内容:
文件分为三大块
template script style
这些内容经过script中node的export方法推出去
其中template渲染了几个router-link,用来跳转路由
script定义了data和method
style写了样式
而后打开src/App.vue,修改里面的内容,追加下图内容:
好的,咱们的SideMenu组件就注册完成了。
好的,咱们接下来作router-view的内容
在作以前,咱们须要了解一个新的概念-bus,又称中央总线
好的,又是以前那张思惟导图,不过是否是多出了三台车呢?
没错,这就是咱们的bus。
当appheader想加载侧边栏时,是不能穿越徒步穿越山和大海的,老司机仍是要开车的是否是
这个时候咱们坐公交就好了,告诉app,把我给拉出来
固然,side-menu和app之间相距不远,父子组件是能够直接绑定的
在src目录下建立bus.js,内容为
这是咱们的bus,说白了就是一个对象,只不过借用了vue的消息管道,你们也能够本身写个管道
在src目录下建立pages目录,这个目录咱们用来存放router-vue的内容
而后咱们在src/pages/下建立一个home.vue组件,用来作home的内容,写下如下内容:
<template lang="html"> <div class="mr-root"> <app-header> <p class = "title">斗鱼TV</p> </app-header> <loading v-if="showLoading"></loading> </div> </template> <script> import Public from "../public" export default { mixins : [ Public ], data(){ return { showLoading : true } } } </script> <style lang="css" scoped> </style>
解释一下,这里使用了app-header和loading组件,由Public导入(等会写)。
mixins是一个混合物,可以自动把模组分析,加载到当前实例中。
data中 showLoading和v-if配合使用,用来关闭loading效果
若是不清楚的话能够看下思惟导图
public是一个模组集合,咱们在开发的时候可能不一样页面要使用相同的组件,这时就须要public打包处理了。
在src中新建public.js,内容以下:
import AppHeader from './components/AppHeader' import Loading from './components/Loading' export default{ components: { AppHeader, Loading } }
上文咱们导入了AppHeader和Loading模块,并设置了默认导出
好,那么咱们来写两个子模组,
在components中新建一个文件AppHeader.vue,代码以下
<template lang="html"> <header> <i class = "icon-reorder" @click = "showSlide"></i> <slot></slot> <i class = "icon-user"></i> </header> </template> <script> import bus from "../bus" export default { methods : { showSlide(){ bus.$emit('showSide') } } } </script> <style lang="css" scoped> header { height: 44px; background: #333; position: fixed; left: 0; right: 0; top: 0; z-index: 100; padding: 0 15px; color: #fff; line-height: 44px; font-size: 16px; } header i { color: #999; } .title { margin-left: 15px; display: inline-block; } .icon-user { float: right; line-height: 44px; } </style>
定义了基本的头部,给加载更多绑定了一个事件,经过bus进行传递,由app.vue来实现
src/components/里面新建一个Loading.vue,代码以下:
<style lang="css"> .loading { height: 100%; position: fixed; z-index: 10; width: 100%; background: #062734; opacity: .4; } .loading img { width: 100%; height: auto; position: absolute; top: calc(50% - 140px); } </style>
就添加了一张gif图而已,很是简单的
好的,既然咱们的appheader已经发车了,那么应该在app.vue根路由里面开个公交车站,来接收巴士:
修改App.vue:
<template> <div id="app"> <transition name = "side"> <side-menu v-show = "show" @hide = "hideSide"></side-menu> </transition> <router-view/> </div> </template> <script> import SideMenu from "./components/SideMenu" import bus from "./bus" export default { name: 'app', components : { SideMenu }, created(){ this.$http.get(`/douyuapi/RoomApi/live?offset=1&limit=20`).then(res=>{ console.log(res.data.data); }) }, data(){ return { show : false } }, mounted () { bus.$on("showSide",this.side) }, methods : { side(){ this.show = !this.show }, hideSide(){ this.show = false } } } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
修改根路由/src/router/index.js为:
import Vue from 'vue' import Router from 'vue-router' import Home from '@/pages/Home' Vue.use(Router) export default new Router({ routes: [ { path: '/', name: 'Home', component: Home } ] })
好的,咱们有了以上功能之后呢,还须要在斗鱼主页中增长聊天室列表,在components目录中新建文件HomeItem.vue
<template lang="html"> <div class="mr-item"> <router-link :to="'/room/'+room.room_id"> <img :src="room.room_src" alt=""> <div class="room-info"> <span class = "nickname">{{room.nickname}}</span> <span class = "count"> <i class = "icon-group"></i> {{room.online | number}} </span> </div> <div class="room-title"> <i class = "icon-desktop"></i> {{room.room_name | message}} </div> </router-link> </div> </template> <script> export default { props : ["room"] } </script> <style lang="css" scoped> .mr-item { margin-top: 10px; float: left; width: 4.4rem; margin-right: .3rem; position: relative; } .mr-item img { width: 100%; height: 2.6rem; border-radius: 5px; } .room-info { position: absolute; bottom: 33px; color: #fff; padding: 0 5px; left: 0; right: 0; overflow: hidden; background: rgba(10,10,10,.5); line-height: 24px; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; } .room-info .count { float: right; } .room-title { line-height: 30px; } </style>
上文中咱们定义了两个过滤器,接下来咱们在main.js中定义几个过滤器
打开main.js,在Vue.config.productionTip = false后,如图写下过滤器代码
咱们须要在Home.vue中加载HomeItem,修改home.vue为
<template lang="html"> <div class="mr-root"> <app-header> <p class = "title">斗鱼TV</p> </app-header> <loading v-if="showLoading"></loading> <home-item v-for = "(room,index) in roomList" :room = "room" :key = "index"> </home-item> <p v-if = "error">加载失败,请稍后再试...</p> <div class="clear"></div> <div class="load-more"> <span @click = "loadMore">点击加载更多</span> </div> </div> </template> <script> import Public from "../public" import HomeItem from "../components/HomeItem" export default { mixins : [ Public ], data(){ return { showLoading : true, error : false, roomList : [], page : 0, pageSize : 20 } }, components : { HomeItem }, created(){ this.getInfo(this.page) }, methods : { getInfo(page){ this.$http.get(`/douyuapi/RoomApi/live?offset=${page*this.pageSize}&limit=${this.pageSize}`) .then(res=>{ this.error = false this.roomList = this.roomList.concat(res.data.data) setTimeout(()=>{ this.showLoading = false },1000) }) .catch(err=>{ this.error = true this.showLoading = false }) }, loadMore(){ this.page++ this.getInfo(this.page) } } } </script> <style lang="css"> .mr-content { padding: 44px 0 0 .3rem; overflow: hidden; } .load-more { margin: 10px; text-align: center; } .load-more span { display: inline-block; line-height: 30px; padding: 0 20px; border-radius: 10px; border: 1px solid #000; } </style>
如今看下页面,是否是已经出来了呢?