環境搭建好了,開始寫業務和後端接口代碼,這一篇講的內容也比較簡單,只適合小白參考;
環境搭建請參考 《手動搭建vue+node單頁面(一)》:https://segmentfault.com/a/11...css
項目地址:https://github.com/liubingyan...html
內容提要:
1.jsonp獲取baidu搜索框內容;
2.node調用juejin接口獲取前端文章列表;前端
開發過程當中不會講的太細,有疑問多百度;vue
1、獲取baidu搜索框內容
就是輸入的同時下來框展現的內容;
在用node調用百度接口時候發現返回的是gbk格式的內容,node解析遇到困難,因此改用jsonp的方式;node
首先在控制檯分析接口:
webpack
返回值:
git
很容易看出內容中json數據的‘s’就是咱們想要的內容;github
接口地址的url內容過長,咱們將這個地址複製到地址欄中通過反覆測試,最終獲得:
web
對咱們有用的參數只有兩個:wd(輸入框的內容)和cb(返回時調用的方法名),接下來就能夠開發了;ajax
這個小功能的開發涉及的:
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'
再看頁面,效果出來了:
2、獲取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後臺管理,結構已經有了,剩下的基本上就是板磚了,再也不贅述。
到目前爲止的目錄結構: