平時會常常瀏覽一些網站充電,可是總是須要切換網站也很麻煩,因此就有了作這個小項目的想法。經過爬蟲抓取一些網站,而後整合在一個應用中。雖然是個簡單應用,可是五臟六腑俱全,適合 Vue 的新手學習。javascript
項目地址css
使用 express 作接口,在請求接口時,同時使用 superagent 請求對應的地址抓取數據前端
app.get('/api/zaoduke', function (req, res, next) {
// 請求接口附帶的參數
let page = req.query.page
superagent.get(`https://toutiao.io/subjects/11907?f=new&page=${page}`)
.end(function (err, sres) {
...
});
});複製代碼
而後經過 cheerio 解析返回的網頁源代碼 (相似 jqury) 的寫法,得到本身須要的數據,而後經過 express 回傳vue
var $ = cheerio.load(sres.text)
var items = []
var data = {
items: items,
hasMore: true
}
if ($('.post').length < 30) {
data.hasMore = false
}
$('.post').each(function (idx, element) {
var $element = $(element)
// cheerio 沒有 innterText 的方法,因此經過 nodeType 去取只屬於這個元素的文本
var $author = $element.find('.meta').contents().filter(function () {
return this.nodeType === 3;
});
// 這裏取數據的方式和jqury是同樣的
items.push({
title: $element.find('.title>a').text().trim(),
href: 'https://toutiao.io' + $element.find('.title>a').attr('href'),
author: $author.text().trim()
})
})
res.send(data)複製代碼
在 Vue 中使用插件必須調用 Vue.use(xxx)
。java
路由懶加載,固然小項目不作異步也徹底沒問題。當項目大了,可使用這個功能分割不一樣路由組件,這個能夠作到訪問才加載路由。node
const Lists = type => () => import('../page/Lists.js').then(m => m.default(type))複製代碼
由於主體內容樣式是同樣的,因此我經過使用不一樣 type 的方式來複用代碼。git
let router = new Router({
// 想使用 scrollBehavior 必須用這個 mode
mode: 'history',
// 切換路由時內容滑動到底部
scrollBehavior: () => ({
y: 0
}),
routes: [{
path: '/',
redirect: '/zaoduke'
},
// 如下就是經過不一樣類型的 type 去複用代碼
{
path: '/raywenderlich/:page(\\d+)?',
component: Lists('raywenderlich')
},
{
path: '/csstricks/:page(\\d+)?',
component: Lists('csstricks')
}
...
]
})複製代碼
項目使用 Vuex 去管理數據,可是當手動刷新瀏覽器的時候,由於 Vuex 是全局變量,因此變量被銷燬,不能獲取正確的數據了。有種方式是將 state 存到 localStorage 中,在這裏我使用了還有種方法。Vue route 有個全局鉤子 beforeEach
他會在進入路由前調用。github
router.beforeEach((to, from, next) => {
// 去獲取路由當前的頁碼,用於請求數據
store.state.page = to.params.page || 1
// 獲取 type
store.state.type = to.path.match(/[a-zA-Z0-9]+/)[0]
// 這裏必須調用 next,不然進不了路由
next()
})複製代碼
接下來導出 router 便可,到這裏路由部分結束。vuex
export default router複製代碼
使用 Vuex 仍是要注意下場景,畢竟使用這個插件仍是很繁瑣的。在這個項目中其實不使用 Vuex 也是能夠的,直接使用瀏覽器內置的方式去管理數據便可。由於代碼中 Vuex 用的不多,就一筆略過了express
PS: 在使用 Vuex 和 Vue route 要注意必須在 Vue 的實例中傳入。
new Vue({
el: '#app',
router,
store,
render: h => h(App)
})複製代碼
先看一下複用組件的代碼
// 內容組件
import List from './ray.vue'
export default function createListView(type) {
return {
// 經過 type 渲染,這個 type 須要在 List 中的 props 定義
render(h) {
return h(List, {
props: {
type
}
})
}
}
}複製代碼
List 組件中包含了三個子組件,分別爲頂部進度條,分頁組件,單個 li 組件。具體的 HTML 和 CSS 代碼你們能夠本身看一下,沒有任何難度。
在頁面中請求數據的代碼我選擇放在 mounted
中,由於只有在這個鉤子及之後才能夠訪問到 $refs
實例
async getData(page = 1) {
// 已經在加載了,就返回
if (this.isLoad) {
return
}
this.isLoad = true
// 調用進度條的 start 方法
this.$refs.progress.start()
// 這種異步請求方法寫起來簡單
let data = await getRaywenderlichData(this.type, page)
// 給數據賦值
this.list = data.items
// 判斷下一頁還有沒有數據,沒有的話禁用下一頁按鈕
if (!data.hasMore) {
this.noMore = true
} else {
this.noMore = false
}
this.isLoad = false
this.$refs.progress.finish()
}複製代碼
子組件給父組件通訊
// 當點擊上一頁或下一頁時調用
routerPush() {
// 改變路由
this.$router.push(`/${this.type}/${this.pageIndex}`)
// 發送消息
this.$emit('changePage', this.pageIndex)
}
// 而後在父組件使用
<pageBreak class="pageBreak"
:type="type"
:isLoad="isLoad"
:noMore="noMore"
@changePage="changePage">複製代碼
你們有興趣的能夠在這個 issus 中回覆以爲不錯的網站,我會添加進項目。
若是在項目中發現了有什麼不解或者發現了 bug,歡迎提交 PR 或者 issue,歡迎大神們多多指點小弟🙏🙏🙏
項目地址,若是喜歡這個項目,歡迎 Star!