今天主要写的是关于首页——文章列表的渲染
一、文章列表——首页
- 导航栏:使用组件搭建框,然后再渲染样式
// 在src/wiews/home/index.vue
<template>
<div class="home-container">
<!-- 导航栏 -->
// 1. 使用组件搭建
<van-nav-bar class="page-nav-bar" fixed>
<van-button
class="search-btn"
slot="title"
type="info"
size="small"
round
icon="search"
>
搜索
</van-button>
</van-nav-bar>
<!-- /导航栏 -->
</div>
</template>
<script>
....
</script>
<style scoped lang="less">
// 2.调整样式
.home-container {
/deep/ .van-nav-bar__title { // 使用了外届的组件或者自己开发一个组件,修改一处就可能会影响到用这个组件的所有样式,所以就需要有一个方法或者方式,既不影响到别的地方,又能修改子组件在当前的样式。/deep/就能实现
max-width: unset;
}
.search-btn {
width: 555px;
height: 64px;
background-color: #5babfb;
border: none;
font-size: 28px;
.van-icon {
font-size: 32px;
}
}
}
</style>
二、文章列表——频道列表
// 在src/wiews/home/index.vue
<template>
<div class="home-container">
......
<!-- /导航栏 -->
// 1.先在vant组件库找到对应的组件---> Tab标签页
// 下面大括号包起来部分是没有渲染之前,使用Tab标签页组件定义的样式
// {<van-tabs class="channel-tabs" v-model="active" swipeable animated border>
<van-tab title="标签 1">内容 1内容 1内容 1内容 1内容 1内容 1内容 1内容 1内容 1</van-tab>
<van-tab title="标签 2">内容 2内容 1内容 1内容 1内容 1内容 1内容 1</van-tab>
<van-tab title="标签 3">内容 3内容 1内容 1内容 1内容 1内容 1</van-tab>
<van-tab title="标签 4">内容 4</van-tab>
<van-tab title="标签 6">内容 6</van-tab>
<van-tab title="标签 7">内容 7</van-tab>
<van-tab title="标签 8">内容 8</van-tab>
<!-- 右侧自定义内容 -->
<!-- 占位元素 -->
<div class="placeholder"></div>
<!-- 右侧按钮 -->
<template #nav-right>
<div class="hamburger-btn">
<i class="toutiao toutiao-gengduo"></i>
</div>
</template>
</van-tabs>}
// 10.获取数据后,渲染到页面中
<van-tabs class="channel-tabs" v-model="active" swipeable animated border>
<van-tab v-for="channels in UserChannels" :key="channels.id">
<div slot="title">{{channels.name}}</div>
{{channels.name}}的内容
</van-tab>
<!-- 右侧自定义内容 -->
<!-- 占位元素 -->
<div class="placeholder" slot="nav-right"></div>
<!-- 右侧按钮 -->
<div class="hamburger-btn" slot="nav-right">
<i class="toutiao toutiao-gengduo"></i>
</div>
</van-tabs>
</div>
</template>
<script>
import { getUserChannels } from "@/api/user"; // 6.导入
export default {
name: "HomeIndex",
components: {},
props: {},
data() {
return {
...
UserChannels: [], // 5.定义频道列表变量名来接收
};
},
computed: {},
watch: {},
created() {
this.loadUserChannels(); // 9.调用
},
mounted() {},
methods: {
// 8.获取频道列表数据并展示
async loadUserChannels() {
try {
const { data } = await getUserChannels();
console.log(data);
this.UserChannels = data.data.channels;
} catch (err) {
this.$toast("获取频道列表失败");
}
},
},
};
</script>
<style scoped lang="less">
.....
// 2.定义样式
/deep/ .channel-tabs {
// 3.设置一个距离上面tabar栏的距离,不要设置全局的,就在这里就可以了
margin-top: 90px;
.van-tab {
border-right: 1px solid #edeff3;
min-width: 200px;
font-size: 30px;
color: #777777;
}
.van-tab--active {
color: #333333;
}
.van-tabs__nav {
padding-bottom: 0;
}
.van-tabs__line {
bottom: 8px;
width: 31px !important;
height: 6px;
background-color: #3296fa;
}
.placeholder {
flex-shrink: 0;
width: 66px;
height: 82px;
}
.hamburger-btn {
position: fixed;
right: -1px;
display: flex;
justify-content: center;
align-items: center;
width: 67px;
height: 82px;
background-color: #fff;
background-color: rgba(255, 255, 255, 0.902);
i.toutiao {
font-size: 33px;
}
&:before {
content: "";
position: absolute;
left: 0;
width: 1px;
height: 58px;
background-image: url(~@/assets/gradient-gray-line.png);
background-size: contain;
}
}
}
</style>
// src/api/user.js
......
// 4.基本样式定义后,首先先获取频道列表
export const getUserChannels = () => {
return request({
method: 'GET',
url: '/v1_0/user/channels',
})
};
三、文章列表—加载文章列表的具体数据
// 1.创建文章的列表组件:src/views/home/components/article-list.vue
<template>
<div class="article-list">
// 1.1.使用组件搭建框架
<van-list
v-model="loading"
:finished="finished"
finished-text="没有更多了"
@load="onLoad"
>
<van-cell v-for="item in list" :key="item" :title="item" />
</van-list>
</div>
</template>
<script>
import {getArticle} from '@/api/article'// 10.导入
export default {
name: "ArticleList",
components: {},
props: {
// 设置一个props用来接收
属于自己的频道信息数据
channels: { // 6.传入数据
type: Object,
required: true,
},
},
data() {
return {
list: [], //存储数据
loading: false, // 控制加载的状态
finished: false,// 控制加载完成的状态
};
},
computed: {},
watch: {},
created() {},
mounted() {},
methods: {
onLoad() {
// 异步更新数据
// setTimeout 仅做示例,真实场景中一般为 ajax 请求 可以修改里面的时间,来延长加载的时间,
// { setTimeout(() => {
// for (let i = 0; i < 10; i++) {
// this.list.push(this.list.length + 1);
}
// 加载状态结束
// this.loading = false;
// 数据全部加载完成
// if (this.list.length >= 40) {
this.finished = true;
}
}, 2000); }
try {
// 11.1.发送请求获取的数据
const { data } = await getArticles({
channel_id: this.channels.id, // 频道id
timestamp: this.pre_timestamp || Date.now(), // 时间戳,请求新的推荐数据传当前的时间戳,请求历史推荐传指定的时间戳
with_top: 1
})
// if(Math.random() > 0.5){
// throw new Error('错误')
// } // 测试代码,测试完删除掉,为了出现错误情况
// console.log(data);
// 11.2.将数据追加到data,数据中保存
const { results } = data.data
// console.log(results,'-----------');
this.list = [...this.list, ...results]
// this.list =data.data.results 这种写法也可以
// console.log(this.list); 打印结果
// 11.3.将loading 设置为false
this.loading = false
this.pre_timestamp = data.data.pre_timestamp
// 11.4.判断数据是否加载完成
if (data.data.pre_timestamp === null) {
this.finished = true
}
} catch (err) {
this.loading = false
this.error = true
this.$toast('获取当前频道的文章列表失败')
}
},
},
};
</script>
<style scoped lang="less">
</style>
// 2.在src/views/home/index.vue中导入
<van-tabs class="channel-tabs" v-model="active" swipeable animated border>
<van-tab v-for="channels in UserChannels" :key="channels.id">
<div slot="title">{{channels.name}}</div>
<div slot="default">
<ArtilceList :channels="channels" // 7.接收></ArtilceList> // 5.使用
</div>
</van-tab>
<script>
import ArtilceList from '@/views/home/components/article-list' // 3.导入组件
components: {
ArtilceList, // 4.定义
},
</script>
// 8.创建:在src/api/article.js
// 9.封装:
import request from '@/utils/request'
export const getArticles = (params) => {
return request({
method: 'GET',
url: '/v1_0/articles',
params
})
};
四、文章列表—下拉刷新
- 这里会使用到 vant 组件库中的 PullRefresh 下拉刷新 组件
<van-pull-refresh
v-model="isLoading"
@refresh="onRefresh"
:success-text="successText">
<!-- <p>刷新次数: {{ count }}</p> -->
<van-list
v-model="loading"
:error.sync="error"
error-text="请求失败,点击重新加载"
:finished="finished"
finished-text="没有更多了"
@load="onLoad"
>
<van-cell v-for="(article,index) in list" :key="index">
<div slot="title">
<ArticleItem :article="article"></ArticleItem>
</div>
</van-cell>
</van-list>
</van-pull-refresh>
data () {
return {
list: [], // 存储数据
loading: false, // 控制加载的状态
finished: false, // 控制加载完成的状态
pre_timestamp: null, // 保存历史的时间戳
error: false,
count: 0,
isLoading: false, // 控制下拉刷新加载中的状态
successText: '刷新成功'
}
},
methods:{
async onRefresh () {
// setTimeout(() => {
// this.$toast('刷新成功');
// this.isLoading = false;
// this.count++;
// }, 1000);
try {
const { data } = await getArticles({
channel_id: this.channels.id, // 频道id
timestamp: Date.now(), // 时间戳,请求新的推荐数据传当前的时间戳,请求历史推荐传指定的时间戳
with_top: 1
})
// console.log(data);
const { results } = data.data
// console.log(results,'-----------');
this.list = [...results, ...this.list]
this.successText = `刷新了${results.length}条数据`
// this.$toast('刷新成功')
this.isLoading = false
} catch (err) {
this.isLoading = false
this.$toast('刷新失败')
}
}
}
五、文章列表—记住滚动条的位置
<style scoped lang="less">
.article-list {
// 设置记住滚动条的位置,这样体验效果比较好,当滚动到某个位置后,我左或右滑动,再返回此页面时,位置没有变化
// 百分比单位是相对于父元素的
// height: 100%;
// 视口(在移动端是布局视口)单位:vw 和 vh,不受父元素影响
// 1vw = 视口宽度的百分之一
// 1vh = 视口高度的百分之一
height: 79vh;
overflow-y: auto;
}
</style>
六、文章列表—列表中的内容
// 1.创建src/components/article-item/index.vue
<template>
// 2.使用Cell 单元格 组件搭建框架
<van-cell class="article-item">
<!-- 标题插槽 -->
<template #title>
<div class="title van-multi-ellipsis--l2">{{ article.title }}</div>
</template>
<!-- 标题下方的内容 -->
<template #label>
<!-- 文章封面信息 -->
<div v-if="article.cover.type === 3" class="cover-wrap">
<div
class="cover-item"
v-for="(img, index) in article.cover.images"
:key="index"
>
<van-image class="cover-item-img" fit="cover" :src="img" />
</div>
</div>
<!-- 文章标注信息 -->
<div class="label-info-wrap">
<span>{{ article.aut_name }}</span>
<span>{{ article.comm_count }}评论</span>
<span>{{ article.pubdate }}</span>
</div>
</template>
<!-- 默认的插槽: 右边的内容 -->
<van-image
v-if="article.cover.type === 1"
class="right-cover"
fit="cover"
:src="article.cover.images[0]"
/>
</van-cell>
</template>
<script>
export default {
name: 'ArticleItem',
components: {},
props: {
article: {
type: Object,
required: true
}
},
data () {
return {}
},
computed: {},
watch: {},
created () {},
mounted () {},
methods: {}
}
</script>
<style scoped lang="less">
// 3.添加样式
.article-item {
.title {
font-size: 32px;
color: #3a3a3a;
}
.van-cell__title {
display: flex;
flex-direction: column;
justify-content: space-between;
}
.van-cell__value {
flex: unset;
width: 232px;
height: 146px;
padding-left: 25px;
}
.right-cover {
width: 100%;
height: 146px;
}
.label-info-wrap span {
font-size: 22px;
color: #b4b4b4;
margin-right: 25px;
}
.cover-wrap {
display: flex;
padding: 30px 0;
.cover-item {
flex: 1;
height: 146px;
&:not(:last-child) {
padding-right: 4px;
}
.cover-item-img {
width: 100%;
height: 146px;
}
}
}
}
</style>