环境搭建好了,开始写业务和后端接口代码,这一篇讲的内容也比较简单,只适合小白参考;
环境搭建请参考 《手动搭建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后台管理,结构已经有了,剩下的基本上就是板砖了,再也不赘述。
到目前为止的目录结构: