想必你們都看過鬥魚直播吧?此次在下使用從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>
如今看下頁面,是否是已經出來了呢?