携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第24天,点击查看活动详情
一。要求
制作头条页面,并通过 Vue 完成数据初始化,实现 axios 请求数据并绑定新闻数据、点击新闻列表跳转到
详情页、利用路由功能传递每一条新闻对应 id 并在详情页展示。根据提供的图片、文本等素材,通过 vue-cli
脚手架工具完成项目搭建,并根据页面创建对应组件,还原页面效果。
(1)、在 components 目录下创建 Header.vue 组件、News.vue 组件;
2)、在 src 目录先新建 page 文件夹,在 page 文件夹下新建 Home.vue 组件、Detail.vue 组件;
3)、img 文件夹(提供)、data 文件夹(提供)放在 static 目录下;
1.App组件
<template>
<div id="app">
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "App",
components: {},
};
</script>
<style>
* {
margin: 0;
padding: 0;
list-style: none;
box-sizing: border-box;
}
</style>
2.Home组件
<template>
<div class="home">
<Header />
<News />
<router-view></router-view>
</div>
</template>
<script>
import Header from "../components/Header.vue";
import News from "../components/News.vue";
export default {
components: { Header, News },
};
</script>
<style>
</style>
3.Header组件
<template>
<div class="header">
<div class="top">
<div><img src="../../public/image/index/message.png" /></div>
<div class="top_a">
<p><img src="/image/index/wap_logo.png" /></p>
<p><img src="../../public/image/index/titlebar_refresh.png" /></p>
</div>
<div><img src="/image/index/search_normal.png" /></div>
</div>
</div>
</template>
<script>
export default {};
</script>
<style scoped >
.top {
display: flex;
width: 100vw;
background: #cf3b3f;
height: 3.125rem;
justify-content: space-around;
align-items: center;
}
.top > div {
height: 3.125rem;
display: flex;
align-items: center;
}
.top_a p:nth-of-type(1) img {
width: 4.375rem;
height: 1.5rem;
}
.top_a p:nth-of-type(2) img {
width: 1.125rem;
height: 1.125rem;
margin-left: 5px;
}
img {
width: 1.5rem;
height: 24px;
}
</style>
4.News组件
(1)、新建 News.vue 组件之后,在 Home.vue 组件中引入新闻列表组件使用
2)、使用 npm 安装 axios 库,并使用 get 方法请求 data 文件中的 data.json 中的数据;
3)、分析 data.json 中的数据,并利用 HTML+CSS 进行页面布局,使用 v-for 遍历解析数据并展示;
4)、使用 router-link 包裹每一条新闻列表,动态绑定 to 属性跳转到详情页面,并且传递每一条新闻
列表对应的 id 值
<template>
<div class="news">
<router-link
v-for="(item, index) in list"
:key="item.id"
:to="`/news/${item.id}`"
>
<div class="news_aa">
<div class="content">
<div>{{ item.title }}</div>
<div class="news_a">
<p>置顶</p>
<p>{{ item.from }}</p>
<p>{{ item.commentLength }}</p>
</div>
</div>
<div>
<img v-show="item.img !== ''" :src="item.img" alt="" />
</div>
</div>
</router-link>
<router-view></router-view>
</div>
</template>
<script>
import axios from "axios";
export default {
data() {
return {
list: [],
number: 0,
};
},
mounted() {
this.loadlist();
},
methods: {
async loadlist() {
let { data } = await axios.get("/data/data.json");
this.list = data;
console.log(this.list);
},
},
};
</script>
<style scoped>
.news_aa div:nth-of-type(2) {
display: flex;
}
.news_aa {
display: flex;
justify-content: space-between;
border-bottom: 1px solid #ccc;
margin: 0 0.3125rem;
align-items: center;
padding: 0.3125rem;
}
img {
width: 7.5rem;
}
.content div:nth-of-type(1) {
margin-bottom: 0.3125rem;
}
.news p {
font-size: 12px;
margin-right: 0.3125rem;
color: #ccc;
}
.news_a p:nth-of-type(1) {
color: red;
border: 1px solid red;
border-radius: 0.3125rem;
}
a {
text-decoration: none;
color: black;
}
</style>
5。Detail组件
(1)、Detail.vue 组件需要在 router 文件夹下注册使用,路由的配置中的 path 需要设置为'/detail/:id',这
样才能接收列表组件传递的每一条新闻的 id
2)、利用 HTML+CSS 进行页面布局,先根据列表页的数据和详情页截图把详情页布局出来
3)、页面数据可以直接把提供的 data.json 导入到详情页中,拿到所有的数据之后,利用列表页传递
的 id,调用 filter 方法,把对应的那条新闻筛选出来进行数据绑定到页面中去进行展示
<template>
<div class="tail">
<div v-for="(item, index) in lists" :key="index">
<h2>{{ item.title }}</h2>
<div class="top">
<div>
<img src="../../public/image/datails/author.jpg" alt="" />
</div>
<div class="contents">
<div>
{{ item.from }}
</div>
<div class="from_a">
<p>
{{ item.time | filterTime }}
</p>
<p>{{ item.commentLength }}评论</p>
<p>关注</p>
</div>
</div>
</div>
<div class="content_a" v-html="item.content"></div>
</div>
</div>
</template>
<script>
import axios from "axios";
export default {
props: ["id"],
data() {
return {
lists: [],
};
},
mounted() {
axios.get("/data/data.json").then(({ data }) => {
this.lists = data.filter((r) => r.id == this.id);
// let a=data.find(r=>r.id==this.id)
// console.log(a);
});
},
filters: {
filterTime(val) {
let froms = +new Date(val);
let tows = +new Date();
let date = (tows - froms) / 1000;
let ye = (date / 60 / 60 ).toFixed(2) + "小时前";
return ye;
},
},
};
</script>
<style scoped>
.tail {
margin: 0 14px;
text-align: left;
}
img {
width: 20px;
height: 20px;
border-radius: 50%;
}
.top {
display: flex;
height: 3.4375rem;
align-items: center;
}
.from_a {
display: flex;
align-items: center;
}
.contents {
margin-left: 8px;
}
.contents > div:nth-of-type(1) {
font-size: 14px;
font-weight: bold;
}
.contents > div:nth-of-type(2) p {
font-size: 12px;
margin-right: 10px;
}
.contents > div:nth-of-type(2) p:nth-of-type(1) {
color: #ccc;
}
.contents > div:nth-of-type(2) p:nth-of-type(2) {
color: red;
}
.contents > div:nth-of-type(2) p:nth-of-type(3) {
color: white;
background: red;
padding: 4px 10px;
}
</style>
6.路由配置
import Vue from "vue";
import VueRouter from "vue-router";
Vue.use(VueRouter);
let routes = [
{
path: "/",
name: "home",
component: () => import("../page/Home.vue"),
},
{
path: "/news/:id",
name: "news",
props: true,
component: () => import("../page/Detail.vue"),
props: true,
},
];
const router = new VueRouter({
routes,
});
export default router;