1.1.数据接口
聚合数据:https://www.juhe.cn/ 申请 “新闻头条” 数据接口:https://www.juhe.cn/docs/api/id/235 (不可直接跨域访问)
注意:按照聚合数据网站的规定,进行注册以及实名认证,然后申请 “新闻头条” 数据接口。
1.2.工程目录结构
1.3.package.json文件
{
"name": "topnews",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build"
},
"dependencies": {
"axios": "^0.19.2",
"core-js": "^3.6.5",
"vue": "^2.6.11",
"vue-router": "^3.2.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^4.4.0",
"@vue/cli-plugin-router": "^4.4.0",
"@vue/cli-service": "^4.4.0",
"vue-template-compiler": "^2.6.11"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}
1.4.vue.config.js而文件
module.exports = {
devServer:{
port:8080,
proxy: {
'/juheNews':{
target:'http://v.juhe.cn/', //需要跨域的url
ws:true, //代理webSocket
changeOrigin:true, //允许跨域
pathRewrite:{
'^/juheNews':'' //重写路径
}
}
}
}
}
1.5.main.js文件
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import axios from 'axios'
Vue.prototype.$axios = axios;
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App)
}).$mount('#app')
1.6.路由配置文件
import Vue from 'vue'
import VueRouter from 'vue-router'
import TopNews from '../views/TopNews.vue'
import TypeNews from '../views/TypeNews.vue'
Vue.use(VueRouter)
const routes = [{
path: '/',
name: 'Home',
component: TopNews
},{
path: '/topNews',
name: 'TopNews',
component: TopNews
},{
path: '/typeNews',
name: 'TypeNews',
component: TypeNews
}]
const router = new VueRouter({
routes
})
export default router
1.7.App.vue文件
<template>
<div id="app">
<header>新闻头条</header>
<nav>
<ul>
<li :class="{navinit:isActive=='topNews'}" @click="changeNav('topNews')">头条新闻</li>
<li :class="{navinit:isActive=='typeNews'}" @click="changeNav('typeNews')">分类新闻</li>
</ul>
</nav>
<router-view />
</div>
</template>
<script>
export default{
data(){
return {
isActive:'typeNews'
}
},
created() {
let path = location.href;
this.isActive = path.substring(path.lastIndexOf('/')+1);
},
methods:{
changeNav(param){
this.isActive = param;
if(param=='topNews'){
this.$router.push('/topNews');
}else if(param=='typeNews'){
this.$router.push('/typeNews');
}
}
}
}
</script>
<style>
/******************** css reset ********************/
html,body,div,header,nav,h1,h2,h3,h4,h5,h6,ul,li{
margin: 0;
padding: 0;
font-family: "微软雅黑";
}
ul{
list-style: none;
}
a{
text-decoration: none;
}
header{
width: 100%;
height: 48px;
background-color: #E03D3E;
display: flex;
justify-content: center;
align-items: center;
font-size: 20px;
color: #fff;
/*设置字间距*/
letter-spacing: 4px;
}
nav{
width: 100%;
height: 56px;
display: flex;
justify-content: center;
align-items: center;
}
nav ul{
width: 160px;
height: 26px;
display: flex;
justify-content: space-between;
}
nav ul li{
width: 70px;
height: 26px;
display: flex;
justify-content: center;
align-items: center;
}
.navinit{
color: #E03D3E;
border-bottom: solid 2px #E03D3E;
}
</style>
1.8.NewsList.vue共通组件
<template>
<div>
<ul>
<li v-for="item in data" @click="toNews(item.url)">
<div class="img-box">
<img :src="item.thumbnail_pic_s">
</div>
<div class="text-box">
<h3>{{item.title | titleFilter}}</h3>
<p>{{item.author_name}} {{item.date}}</p>
</div>
</li>
</ul>
</div>
</template>
<script>
export default{
props:['data'],
methods:{
toNews(url){
location.href = url;
}
},
filters:{
titleFilter(value){
if(value.length>24){
value=value.substr(0,24)+'...';
}
return value;
}
}
}
</script>
<style scoped>
ul{
width: 100%;
}
ul li{
box-sizing: border-box;
padding: 6px;
width: 100%;
height: 93px;
display: flex;
border-bottom: dashed 1px #AAA;
user-select: none;
cursor: pointer;
}
ul li .img-box{
flex: 0 0 100px;
height: 80px;
}
ul li .img-box img{
width: 100px;
height: 80px;
}
ul li .text-box{
flex: 1;
box-sizing: border-box;
padding-left: 10px;
}
ul li .text-box h3{
font-size: 16px;
font-weight: 300;
}
ul li .text-box p{
font-size: 14px;
text-align: right;
}
</style>
1.9.TopNews.vue组件
<template>
<div>
<img src="../assets/logo.png">
<NewsList :data="newsList"></NewsList>
</div>
</template>
<script>
import NewsList from '../components/NewsList'
export default{
data(){
return {
newsList:[]
}
},
created() {
this.$axios.get('/juheNews/toutiao/index',{
params:{
type:'top',
key:'自己的key'
}
}).then(response=> {
this.newsList = response.data.result.data;
})
.catch(error=> {
console.log(error);
});
},
components:{
NewsList
}
}
</script>
<style scoped>
img{
width: 100%;
height: 100px;
display: block;
}
</style>
1.10.TypeNews组件
<template>
<div>
<div class="news-img">
<a :href="news.url">
<img :src="news.thumbnail_pic_s">
</a>
</div>
<div class="type-news">
<ul>
<li v-for="item in typeList" :class="{typeinit:isAlive==item.id}" @click="change(item.id)">
{{item.name}}
</li>
</ul>
</div>
<NewsList :data="newsList"></NewsList>
</div>
</template>
<script>
import NewsList from '../components/NewsList';
export default{
data(){
return {
typeList:[
{id:'shehui',name:'社会'},
{id:'guonei',name:'国内'},
{id:'guoji',name:'国际'},
{id:'yule',name:'娱乐'},
{id:'tiyu',name:'体育'},
{id:'junshi',name:'军事'},
{id:'keji',name:'科技'},
{id:'caijing',name:'财经'},
{id:'shishang',name:'时尚'}
],
isAlive:'shehui',
newsList:[],
news:{}
}
},
created() {
this.getNews('shehui');
},
methods:{
getNews(type){
this.$axios.get('/juheNews/toutiao/index',{
params:{
type:type,
key:'自己的key'
}
}).then(response=> {
this.newsList = response.data.result.data;
this.news = this.newsList[Math.floor(Math.random()*this.newsList.length)];
})
.catch(error=> {
console.log(error);
});
},
change(id){
this.isAlive = id;
this.getNews(id);
}
},
components:{
NewsList
}
}
</script>
<style scoped>
.news-img img{
width: 100%;
height: 200px;
display: block;
}
.type-news{
width: 100%;
margin-top: 8px;
}
.type-news ul{
width: 100%;
display: flex;
justify-content: center;
flex-wrap: wrap;
}
.type-news ul li{
box-sizing: border-box;
width: 48px;
height: 22px;
border: solid 1px #E03D3E;
border-radius: 11px;
margin: 5px 10px;
font-size: 14px;
color: #E03D3E;
display: flex;
justify-content: center;
align-items: center;
}
.typeinit{
background-color: #E03D3E;
color: #fff !important; /*!important:将优先级提升最高*/
}
</style>
[