Vue基础篇一:编写第一个Vue程序
Vue基础篇二:Vue组件的核心概念
Vue基础篇三:Vue的计算属性与侦听器
Vue基础篇四:Vue的生命周期(秒杀案例实战)
Vue基础篇五:Vue的指令
Vue基础篇六:Vue使用JSX进行动态渲染
Vue提高篇一:使用Vuex进行状态管理
Vue提高篇二:使用vue-router实现静态路由
Vue提高篇三:使用vue-router实现动态路由
Vue提高篇四:使用Element UI组件库
Vue提高篇五:使用Jest进行单元测试
Vue提高篇六: 使用Vetur+ESLint+Prettier插件提升开发效率
Vue实战篇一: 使用Vue搭建注册登录界面
Vue实战篇二: 实现邮件验证码发送
Vue实战篇三:实现用户注册
Vue实战篇四:创建多步骤表单
Vue实战篇五:实现文件上传
Vue实战篇六:表格渲染动态数据
Vue实战篇七:表单校验
Vue实战篇八:实现弹出对话框进行交互
Vue实战篇九:使用省市区级联选择插件
Vue实战篇十:响应式布局
Vue实战篇十一:父组件获取子组件数据的常规方法
Vue实战篇十二:多项选择器的实际运用
Vue实战篇十三:实战分页组件
Vue实战篇十四:前端excel组件实现数据导入
Vue实战篇十五:表格数据多选在实际项目中的技巧
Vue实战篇十六:导航菜单
Vue实战篇十七:用树型组件实现一个知识目录
Vue实战篇十八:搭建一个知识库框架
Vue实战篇十九:使用printjs打印表单
Vue实战篇二十:自定义表格合计
Vue实战篇二十一:实战Prop的双向绑定
Vue实战篇二十二:生成二维码
Vue实战篇二十三:卡片风格与列表风格的切换
Vue实战篇二十四:分页显示
Vue实战篇二十五:使用ECharts绘制疫情折线图
Vue实战篇二十六:创建动态仪表盘
Vue实战篇二十七:实现走马灯效果的商品轮播图
Vue实战篇二十八:实现一个手机版的购物车
Vue实战篇二十九:模拟一个简易留言板
Vue项目实战篇一:实现一个完整的留言板(带前后端源码下载)
Vue实战篇三十:实现一个简易版的头条新闻
Vue实战篇三十一:实现一个改进版的头条新闻
<template>
<ul class="infinite-list" v-infinite-scroll="load" style="overflow:auto">
<li v-for="i in count" class="infinite-list-item">{{ i }}</li>
</ul>
</template>
<script>
export default {
data () {
return {
count: 0
}
},
methods: {
load () {
this.count += 2
}
}
}
</script>
methods: {
// 自动加载方法,获取下一页新闻
load() {
// 从状态管理器中获取当前新闻列表是第几页
let start = this.$store.state.news.start
start++
// 接口限制最大不超过400页
if (start < 400) {
this.getNews(this.$store.state.news.channel, start, this.$store.state.news.num).then(res => {
console.log('loading more news', res)
if (res && res.data.result) {
const newsData = this.$store.state.news.newsData
newsData.push.apply(newsData, res.data.result.list)
this.$store.commit('SET_NEWS', newsData)
this.$store.commit('SET_START', start)
}
})
}
},
...
}
// 用于存储各种变量
const news = {
state: {
// 频道
channel: '',
// 起始位置
start: 0,
// 一次向接口接取新闻的条数
num: 10,
// 存放拉取下来的新闻
newsData: [],
// 当前正在查看的新闻
newsIndex: -1,
// 是否加载状态
loading: false
},
mutations: {
SET_CHANNEL: (state, channel) => {
state.channel = channel
},
SET_START: (state, start) => {
state.start = start
},
SET_NUM: (state, num) => {
state.num = num
},
SET_NEWS: (state, news) => {
state.newsData = news
},
SET_NEWS_INDEX: (state, newsIndex) => {
state.newsIndex = newsIndex
},
SET_LOADING: (state, loading) => {
state.loading = loading
}
},
actions: {
setChannel({ commit }, channel) {
return new Promise(resolve => {
commit('SET_CHANNEL', channel)
})
},
setStart({ commit }, start) {
return new Promise(resolve => {
commit('SET_START', start)
})
},
setNum({ commit }, num) {
return new Promise(resolve => {
commit('SET_NUM', num)
})
},
setNews({ commit }, news) {
return new Promise(resolve => {
commit('SET_NEWS', news)
})
},
setNewsIndex({ commit }, newsIndex) {
return new Promise(resolve => {
commit('SET_NEWS_INDEX', newsIndex)
})
},
setLoading({ commit }, loading) {
return new Promise(resolve => {
commit('SET_LOADING', loading)
})
}
}
}
export default news
1、在新闻列表中引入无限滚动加载功能,并关联自动加载方法
2、在底部放入加载条,显示正在努力加载
3、向接口获取数据成功后,重新渲染新闻列表
<template>
<div>
<!-- 标题栏 -->
<div class="header">
<span />
<span>新闻</span>
<span />
</div>
<channel />
<div ref="container" class="nav-content">
<!-- 在新闻列表中引入无限滚动加载功能 -->
<div v-if="loading == false" v-infinite-scroll="load" class="news-list">
<div
v-for="(item, index) in newData"
:key="index"
class="section"
@click="toNews(index)"
>
<div class="news">
<div class="news-left">
<img :src="item.pic" alt="">
</div>
<div class="news-right">
<div class="newsTitle">{{ item.title }}</div>
<div class="newsMessage">
<span>{{ item.time }}</span>
<span>{{ item.src }}</span>
</div>
</div>
</div>
</div>
<!-- 在底部放入加载条 -->
<div class="loading-more">正在努力加载</div>
</div>
<el-main
v-else
v-loading="loading"
class="load"
element-loading-background="rgba(0,0,0,0)"
element-loading-text="正在加载中"
/>
</div>
</div>
</template>
<script>
import Channel from './channel'
import { getNewList } from '@/api/news'
export default {
name: 'Home',
components: { Channel },
data() {
return {
}
},
computed: {
newData() {
return this.$store.state.news.newsData
},
loading() {
return this.$store.state.news.loading
}
},
methods: {
load() {
// 获取下一页新闻
console.log('已到达底部,自动触发加载方法')
let start = this.$store.state.news.start
start++
if (start < 400) {
this.getNews(this.$store.state.news.channel, start, this.$store.state.news.num).then(res => {
console.log('加载下一页新闻列表', res)
if (res && res.data.result) {
const newsData = this.$store.state.news.newsData
newsData.push.apply(newsData, res.data.result.list)
this.$store.commit('SET_NEWS', newsData)
this.$store.commit('SET_START', start)
}
})
}
},
// 异步获取新闻
async getNews(channel, start, num) {
const data = await getNewList(channel, start, num)
return data
},
// 打开新闻阅读
toNews(index) {
this.$store.commit('SET_NEWS_INDEX', index)
this.$router.push('/news')
}
}
}
</script>
<style lang="scss" scoped>
.header {
width: 100%;
height: 1.2rem;
background-color: #d43d3d;
display: flex;
justify-content: space-between;
align-items: center;
color: #fff;
font-size: 20px;
font-weight: 700;
letter-spacing: 3px;
z-index: 99;
position: fixed;
top: 0;
img {
width: 0.67rem;
height: 0.67rem;
cursor: pointer;
}
}
.nav-content {
margin-top: 2.4rem;
}
.news-list {
position: relative;
height:calc(100vh - 2.4rem - 49px);
overflow-y:auto;
width: 100%;
}
.section {
width: 100%;
height: 2.5rem;
border-bottom: 1px solid #ccc;
}
.news {
height: 2.25rem;
box-sizing: border-box;
margin: 10px 10px;
display: flex;
}
.news-left {
height: 100%;
width: 2.8rem;
display: inline-block;
}
.news-left img {
width: 100%;
height: 100%;
}
.news-right {
flex: 1;
padding-left: 10px;
}
.newsTitle {
width: 100%;
height: 62%;
color: #404040;
font-size: 17px;
overflow: hidden;
}
.newsMessage {
width: 100%;
height: 38%;
display: flex;
align-items: flex-end;
color: #888;
justify-content: space-between;
}
.load {
width: 100%;
height: 100%;
overflow: hidden;
}
.loading-more {
margin-top: 5px;
width: 100%;
height: 20px;
text-align: center;
}
</style>