手動搭建vue+node單頁面(二)
環境搭建好了,最先寫營業和後端接口代碼,這一篇講的內容也比較簡樸,只合適小白參考;
環境搭建請參考 《手動搭建vue+node單頁面(一)》:https://segmentfault.com/a/11…
項目地點:https://github.com/liubingyan…
內容提要:
1.jsonp獵取baidu搜刮框內容;
2.node挪用juejin接口獵取前端文章列表;
開闢過程當中不會講的太細,有疑問多百度;
一、獵取baidu搜刮框內容
就是輸入的同時下來框展現的內容;
在用node挪用百度接口時刻發明返回的是gbk花樣的內容,node剖析遇到困難,所以改用jsonp的體式格局;
首先在控制台剖析接口:
返回值:
很輕易看出內容中json數據的‘s’就是我們想要的內容;
接口地點的url內容太長,我們將這個地點複製到地點欄中經由重複測試,終究獲得:
對我們有用的參數只要兩個:wd(輸入框的內容)和cb(返回時挪用的要領名),接下來就能夠開闢了;
這個小功用的開闢觸及的:
1.app.vue:將導航和路由寫在个中,並做簡樸規劃;
改之前在src目次下建立common文件夾,寄存大眾款式和要領(base.css等):
比方:
//base.css
//...
.fl{float:left}
.fr{float:right}
//...
//相似如許的預定義款式
app.vue做以下修正:(今後的款式都不再做細緻申明)
<template>
<div>
<div class="clearfix wrap">
<!-- 左側 -->
<div class="app_left fl">
<!-- 導航欄 -->
<ul class="nav">
<li><router-link to="/">首頁</router-link></li>
<li><router-link to="/forum">魔獸論壇</router-link></li>
</ul>
<!-- 路由頁面展現 -->
<router-view></router-view>
</div>
<!-- 右側 -->
<div class="app_aside fr">
</div>
</div>
</div>
</template>
<script>
export default {
}
</script>
<style lang="scss">
/*這裏運用@import的體式格局,假如要在js頂用import引入,在webpack設置中module里增添/\.css$/婚配就好了;*/
@import "./common/reset.css";
@import './common/base.css';
.wrap{
min-height: 100%;
background: #eee;
}
.app_left{
width: 75%;
background: white;
min-height:100vh;
box-shadow: -1px 0 0 0 #ccc inset;
}
.app_aside{
width: 25%;
}
</style>
看效果之前先引入路由,不然頁面沒東西,src/router文件夾下建立index.js,建立router文件夾的緣由照樣模塊化開闢的頭腦,將作用雷同的代碼放在一同,利於保護和開闢;
//router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import Home from '../views/home'
Vue.use(Router)
export default new Router({
routes: [{
path: '/',
name: 'home',
component: Home
}]
})
別忘了裝置插件
npm i vue-router -save
main.js引入路由設置
//main.js
import Vue from 'vue'
import App from './app'
import router from "./router"//默許加載index文件
new Vue({
el: '#app',
router,//註冊到vue實例
render: h => h(App)
})
效果以下:
導航和路由頁面放在左側,右側欄留着放小插件;
3.依據導航最起碼要有一個首頁,一個論壇頁,先做首頁,在src下建立home.vue;
home頁內容有兩個,搜刮框和juejin拿到的列表,先做搜刮框;
//home.vue
<template>
<transition name='fade'>
<div class="wrap clearfix">
<!-- 搜刮框組件 -->
<div class="search">
<search></search>
</div>
</div>
</transition>
</template>
<script>
//運用vue組件步驟:import援用->components註冊->標籤的體式格局展現
import search from "./views/search"
export default {
name: 'home',
components:{
search
},
}
</script>
<style lang="less" scoped>
</style>
編寫搜刮框組件,在src/views下建立search.vue
//search.vue
<template>
<div class="searchWrap">
<div class="search clearfix">
<!-- 綁定輸入內容,綁定keyup事宜挪用接口,很簡樸不是-->
<input type="text" name="" v-model='searchInfo' @keyup='inputKeyUp()'>
<!--因為baidu及各大搜刮引擎的搜刮功用返回的是html頁面並從新襯着,這裏就不做搜刮功用了;-->
<div class="submit" onselectstart="return false;" @click=''>
搜刮
</div>
<!--展現搜刮效果-->
<transition name='fade'>
<div class="searchResult" v-show='searchResult.length>0'>
<ul>
<li v-for='(item,i) in searchResult' v-show='i<5' @click='choseSearch(item)'>{{item}}</li>
</ul>
</div>
</transition>
</div>
</div>
</template>
<script>
export default {
name: 'search',
data(){
return {
searchInfo:'',//綁定輸入框內容
searchResult:[],//存儲返回效果
}
},
created(){
//點擊body讓搜刮效果框小時,可有可無
this.removeSearchResult();
},
methods:{
inputKeyUp(){
let url='https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd='+this.searchInfo+'&cb=searchFunction';
//這裡是經由過程jsonp的體式格局挪用接口,要先在window下註冊creatScript和searchFunction要領,下面有形貌;
window.creatScript(url).then(data=>{
log(data)
this.searchResult=data.s;
});
},
//挑選搜刮效果替換搜刮框內容
choseSearch(item){
this.searchInfo=item;
//vue沒法檢測數組屬性length的轉變
this.searchResult.splice(0)
},
//body綁定點擊事宜,使搜刮顯現框消逝
removeSearchResult(){
document.body.addEventListener('click',ev=>{
if(!(ev&&ev.target.className.indexOf('searchResult')>-1)){
this.searchResult.splice(0)
}
})
}
}
}
</script>
<style lang="less" scoped>
/*款式本身花點時候寫一下吧*/
</style>
在src/common下建立base.js增加大眾要領(vue有本身的體式格局將自定義函數屬性增加到實例上,本身百度進修吧,是經由過程組件的體式格局引入,然後經由過程vue.的體式格局挪用),這裏東西不多,我們就簡樸粗獷點兒,直接在windows下增加要領,挪用也簡樸;
//src/common/base.js代碼比較簡樸,不多詮釋了
window.log=console.log;
window.searchFunction = function(val) {
window.searchInfo = val
//將搜刮效果保存在searchInfo 中
};
window.creatScript=function(url) {
//挑選promise是它的then要領用起來輕易
return new Promise((resolve, reject) => {
let script = document.createElement('script');
script.id = 'removeScript';
script.src = url;
document.body.appendChild(script);
script.onload = function() {
resolve(window.searchInfo);
document.body.removeChild(document.getElementById('removeScript'));
}
});
};
在main.js中引入
import './common/base'
再看頁面,效果出來了:
二、獵取juejin文章列表
到目前為止照樣沒有寫後端代碼,接下來經由過程挪用juejin接口來看看一個簡樸接口怎樣寫
寫之前先整頓下思緒:要寫個展現組件,一個後端接口,在把它們聯繫起來;
1.寫組件,在src/views下建立juejinResources.vue文件
//juejinResources.vue(營業代碼不再贅述)
<template>
<div class="juejinResources w60">
<ul>
<li class="" v-for='(item,i) in juejinResources'>
<div class="clearfix littleTop">
<div class="fl red" v-show='!item.original'>熱·</div>
<div class="fl pink" v-show='i<10'>專欄·</div>
<div class="fl inherit">{{item.user.jobTitle}}·</div>
<div class="fl inherit" @click='getJuejinResourcesUserInfo(item.user)'>{{item.user.username}}·</div>
<div class="fl inherit">{{item.createdAt|lastTime}}</div>
</div>
<div><a :href="item.originalUrl" class="title" target="_blank">{{item.title}}</a></div>
</li>
</ul>
</div>
</template>
<script>
export default {
data(){
return {
juejinResources:[],
}
},
created(){
this.getJuejinResources();
},
filters:{
lastTime(v){
if(v){
let val=new Date()-new Date(v)
let days = parseInt(val / (1000 * 60 * 60 * 24));
let hours = parseInt((val % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
let minutes = parseInt((val % (1000 * 60 * 60)) / (1000 * 60));
let seconds = ((val % (1000 * 60)) / 1000).toFixed(1);
return days>0?days+'天':hours>0?hours+'小時':minutes>0?minutes+'分鐘':seconds+'秒'
}else{
return ''
}
}
},
methods:{
//運用vue-resource插件挪用ajax;
getJuejinResources(){
this.$http.get('http://localhost:3000/juejinResources').then(data=>{
//像如許的接口地點應當像base.js一樣有一個大眾的設置文件統一治理,這裏就不麻煩了直接寫;
log(data)
this.juejinResources=data.body.d.entrylist;
})
},
getJuejinResourcesUserInfo(item){
window.toNewPage('https://juejin.im/user/'+item.objectId)
//base中增加的用js跳新頁面的要領,模仿a標籤,很簡樸
//base.js
//window.toNewPage=function(url){
// let a=document.createElement('a');
// a.href=url;
// a.target='_blank';
// document.body.appendChild(a);
// a.click();
// document.body.removeChild(a);
// }
},
}
}
</script>
<style lang="less" scoped>
/*css照樣本身寫吧,哈哈*/
</style>
裝置vue-resource插件
npm i vue-resource -save
將vue-resource註冊到vue中,修正main.js
//main.js
//....
import VueResource from 'vue-resource'
Vue.use(VueResource)
//....
2.寫後端接口,在service目次下建立juejinResources.js
//juejinResources.js
var http = require('http');
var log = console.log;
var express = require('express');
var router = express.Router();
//如許的地點獵取體式格局跟baidu的一樣,逐步試;
var url = "http://timeline-merger-ms.juejin.im/v1/get_entry_by_rank?src=web&limit=20&category=5562b415e4b00c57d9b94ac8";
//express自帶路由分派
router.get('/', function(req, res) {
http.get(url, function(resquest) {
var html = '';
resquest.setEncoding('utf-8'); //防備中文亂碼
//監聽data事宜,每次取一塊數據
resquest.on('data', function(chunk) {
html += chunk;
});
//監聽end事宜,假如接口返回獵取終了,就實行回調函數
resquest.on('end', function() {
//接口返回的是字符串,中文是unicode碼,做了處置懲罰才返回給前端
html=JSON.parse(unescape(html.replace(/\\u/g, '%u')))
res.status(200)
res.json(html)
})
})
})
module.exports=router;
3.接口寫好今後就把它們聯繫起來,修正server.js
//server.js
//....在代碼末了增加
//node分派路由的體式格局,多個效勞就多寫幾個分派就好了
//juejinResources.js頂用的router.git("/")會自動把"/juejinResources"拼在前面
app.use('/juejinResources',require('./service/juejinResources'))
實在挺簡樸,來看看效果:
假如接口是https要求,node環境可能會湧現如許的報錯:
處理辦法網上有許多,但不肯定有用,我的就不曉得怎樣處理了,所以都改成了http要求;
到這裏:單頁面組件-路由-後端接口-效勞就都有了,開闢形式,臨盆形式也都具有,爬蟲也是用http或則https屢次接見,獵取體式格局跟這個實際上是一樣的,拿到數據想怎樣玩都可以,放到本身數據庫都沒題目。
這個demo項目還不完全,缺乏數據庫和admin背景治理,構造已經有了,剩下的基本上就是板磚了,不再贅述。
到目前為止的目次構造: