你好!欢迎阅读我的博文,你可以跳转到我的个人博客网站,会有更好的排版效果和功能。

此外,本篇博文为本人Pushy原创,如需转载请注明出处:https://pushy.site/posts/1519817324

如果你了解前端,肯定对AJAX不陌生,那么通过AJAX技术能够达到更新网页部分内容来达到加载其他信息的效果。通过AJAX我们可以来对文章进行优化,如果我们的博客在首页载入时就加载全部的文章,势必会影响加载速度,所以我们要来异步加载文章的内容,通过分页或者向下加载的方式来加载更多的文章内容。这样大大降低了网页最初加载的速度,并且也能受用户的意愿加载更多的内容。

1. 后端实现:

其实后端实现分页的功能十分的简单,如果使用是mysql,通过原生的SQL语句也可以轻松地实现,page是指查询字符串,为当前请求的页数;l_num为每页限制的文章个数:

SELECT * FROM posts LIMIT ( page -1 ) * l_num,l_num

那么一般后端我们都不使用原生的SQL语句,因为这样处理事务过于繁琐且效率不高。在Flask的ORM框架flask_sqlalchemy中,我们可以使用paginate()方法来实现,这个方法返回值是一个由该模块定义的一个Pagination对象。这个对象包含了很多的属性,如果你采用的是jinja2引擎渲染文章内容的方式,可以参考《Flask Web Development》一书中11.3.3的相关内容。

但是如果你采用的是前端向后端请求AJAX请求的话,那么将不用操作这个对象的其他属性,而是直接通过其items得到当前页面(指查询字符串所对应的当前页面)中的记录,为当前页面所有的文章ORM实例的列表:

@app.route('/posts')
def return_page_posts():
page = request.args.get('page', 1, type=int) # 得到查询字符串
pagination = Post.query.order_by(Post.create_time.desc()).paginate(
page,per_page=6, # per_page定义一页限制的文章个数
error_out=False
)
posts_list = pagination.items
return jsonify(
data = [each.return_dict() for each in posts_list]
)

将得到的posts_list通过列表生成式得到包含当前页面的所有文章内容的字典列表,并且通过jsonify()方法转换为JSON格式。这样前端在调用/post/page=1API时,后端将会返还第一页的所有文章内容的JSON数据,例如这样:

{
"data": [
{
"content": "content1",
"post_id": "1",
"title": "title1"
},
{
"content": "content2",
"post_id": "2",
"title": "title2"
},
...
]
}

如果你的后端是nodeJS,也有相应的方法来容易地实现:

router.get('/posts', (req, res) => {
let pageNum = req.query.page
Post.findAll({ limit: 6,offset:(pageNum-1) * 6}).then(posts => {
if (posts.length != 0) {
res.send(posts);
} else {
res.json({data:''})
}
})
});

2. 前端实现:

Vue中实现分页的功能需要用到状态管理的插件Vuex,因为要记录当前阅读到页数,因为如果没有进行状态管理,当用户点击到其他页面再后退到文章首页时,文档内容又会重新加载为第一页的内容,这样用户体验自然不好。所以需要有一个变量来记录当前阅读当的页数,以及用来存放已经加载的文档数组。

所以实现分页功能的大致思路为:在首次加载文档首页时请求第一页的内容,并将其存放到数组当中,然年通过“查看更多按钮”(或者通过下一页)触发点击事件,来分发action中请求下一页的内容,并且在每次触发点击事件之后,用来记录当前阅读的页数变量自加1,并通过mutation来更新用来存放文章内容的数组:

state:{
pageNum:1, // 记录当前阅读页数的变量
postsArray:[], // 存放文章内容的数组
}

然后我们在mutations.js文件中定义增加页数和合并文章数组的mutation

[types.PAGE_INCREMENT] (state) {
state.pageNum ++
},
[types.FETCH_INDEX_POST] (state, newPostsObj) {
// 将已经加载的数组和新的数组合并:
state.postsArray = state.postsArray.concat(newPostsObj)
}

接着我们来action.js文件中定义一个action,这里包含了主要的异步操作,用来向后端请求文章:

fetchPosts ({ commit }) {
var nextPageNum = store.state.pageNum
axios.get('http://api.example/posts/?page=' + nextPageNum).then(response=>{
if (response.data.data.length == 0){
commit(types.NO_ANY_POSTS) // 显示没有更多文章
} else {
commit('HIDDEN_INDEX_LOADING') // 取消显示loading
commit(types.FETCH_INDEX_POST,response.data.data)
}
}
}).catch(error=>{
commit('HIDDEN_INDEX_LOADING')
})
}

在后端返回的JSON数组的data字段中不等于0的情况下(可以看到我在等于0的时候定义了一个NO_ANY_POSTSmutation来触发,用来提示用户没有更多的文章加载了,当然可以是一个弹窗也可以是一个提示行,这样会有更好的用户体验),我们通过commit去触发合并的mutation来合并加载的数组。

到这里主要的业务逻辑基本完成,那么在前端的UI中我们如果实现呢异步加载的功能呢?可以选择分页的界面,由用户点击不同的分页数来请求响应页数的文章内容;也可以通过安放一个“查看更多”的按钮,每次点击后请求下一页的文章内容,这里我主要说下后者,首先我们定义一个"查看更多的按钮",并绑定一个readMore的点击事件:

<button @click="readMore">READ MORE</button>

然后定义一个readMore方法,并且在触发后去commitmutation的事件,将记录页数的值加1,并且去分发action请求下一页的文章内容:

readMore:function(){
this.$store.commit('PAGE_INCREMENT')
this.$store.dispatch('fetchPosts')
}

还有一个问题——总不可能让用户首次进入文章首页时就看到一个查看更多的按钮吧,这肯定不现实。所以在生命周期的created阶段,我们要去请求第一页的文章内容:

created:function() {
if (this.pageNum == 1) {
this.$store.dispatch('fetchPosts')
}

可以看到这里有一个判断条件:当记录页数值为1才会去分发action。这么做的目的呢,是因为如果用户在点击到其他路由后,点击后退键到文章首页时,Vue的生命周期将会重新执行,因此会重复分发action,导致文章数组存在重复的内容。PS.当时在遇到这个问题时满脑子的骚操作,想法是将已有的数组和新加载的数组做比较,判断是否存在重复的内容,看来遇到问题还是需要从简单的入口解决啊。

至此异步加载文章的功能大致完成,如果你对分页的样式比较感兴趣也可以尝试写下,两者的思路都差不多,不过决定你想要那种用户体验。

Vue中结合Flask与Node.JS的异步加载功能实现文章的分页效果的更多相关文章

  1. Node.js require 模块加载原理 All In One

    Node.js require 模块加载原理 All In One require 加载模块,搜索路径 "use strict"; /** * * @author xgqfrms ...

  2. js的异步加载你真的懂吗

    面试高频之js的异步加载 讲这个问题之前, 我们从另一个面试高频问题来切入, 我们的web页面从开始解析到页面渲染完成都经历了什么 ?  1  ,  创建document对象, 开始解析页面,    ...

  3. 【译】深入理解python3.4中Asyncio库与Node.js的异步IO机制

    转载自http://xidui.github.io/2015/10/29/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3python3-4-Asyncio%E5%BA%93% ...

  4. Vue中import from的来源--省略后缀与加载文件夹

    Vue使用import ... from ...来导入组件,库,变量等.而from后的来源可以是js,vue,json.这个是在webpack.base.conf.js中设置的: module.exp ...

  5. node.js的包加载机制

    加载一个模块 require('moduleName'); 现在核心模块中加载,如果核心模块中没有,那么就去node_modules目录下去找,核心模块的优先级最高. 如果加载模块式省略了文件的后缀名 ...

  6. Node.js实现热加载

    不管是node.js原生开发,还是借助express,kora等框架开发node.js的情况下,在对代码做出更新后,都是需要重启已生效我们的文件的. 本文记录一次在原生node.js开发的时候,为项目 ...

  7. 如何在vue中监听scroll,从而实现滑动加载更多

    首先需要明确3个定义: 文档高度:整个页面的高度 可视窗口高度:你看到的浏览器可视屏幕高度 滚动条滚动高度: 滚动条下滑过的高度 当 文档高度 = 可视窗口高度 + 滚动条高度  时,滚动条正好到底. ...

  8. js滚动异步加载数据的思路

    <body> <div style="width:200px; height:1000px; border:1px solid red;" id="to ...

  9. Vue.js 子组件的异步加载及其生命周期控制

    前端开发社区的繁荣,造就了很多优秀的基于 MVVM 设计模式的框架,而组件化开发思想也越来越深入人心.这其中不得不提到 Vue.js 这个专注于 VM 层的框架. 本文主要对 Vue.js 组件化开发 ...

随机推荐

  1. [学习OpenCV攻略][002][Ubuntu下OpenCV安装]

    配置环境 操作系统 Ubuntu 12.04 OpenCV版本 opencv-1.0.0 学习书籍 <学习OpenCV> Liunx软件安装方法主要有3种: 1.编译安装,也就是通过编译源 ...

  2. LockSupport理解

    一.背景 在看并发包源码的时候看见过LockSupport,今天恰巧看到LockSupport字眼,于是看下jdk1.7中的源码结构.想着它应该是运用多线程的锁工具的,到底似乎怎么实现的呢? 二.使用 ...

  3. JavaScript URL传值过程中遇到的问题及知识点总结

    JavaScript URL传值过程中遇到的问题及知识点总结 Web系统开发过程中经常用到URL进行传值,刚刚接触时不太会解析,会出现中文乱码问题等. 1.父子页面之间的传值(在一个页面中以加载ifr ...

  4. Spring MVC 用post方式提交表单到Controller乱码问题,而get方式提交没有乱码问题

    在web.xml中添加一个filter,即可解决post提交到Spring MVC乱码问题 <!-- 配置请求过滤器,编码格式设为UTF-8,避免中文乱码--> <filter> ...

  5. mysql-SQL优化总结

    1.查询首先考虑在where和order by设计的列上建立索引,尽量避免全表扫描. 2.尽量避免在where子句中对字段进行null值判断,否则将导致引擎放弃使用索引而进行全表扫描. select ...

  6. Linux 性能搜集【top/vmstat/iostat】

    为方便问题发生后,问题原因的分析排查,我们可以在服务器中事先部署如下脚本,方便故障发生后,问题原因的分析排查 脚本部署方法: 1.将脚本[top_monitor.sh]上传到服务器 2.登陆虚拟机,并 ...

  7. Django 类方式view进行进行用户验证

    问题: Django中,view的书写方式有两种,一种是def函数方式,一种是class方式,函数方式通过@login_required装饰器标记函数,就必须通过用户验证,而类,则没办法通过此方法进行 ...

  8. linkin大话设计模式--适配器模式

    linkin大话设计模式--适配器模式 大家知道,在java中只允许单继承,但是在实际问题中往往都需要多继承,java引入了接口这一概念.(一个类可以实现多个接口) 由于接口中都是抽象方法,那么我们在 ...

  9. PhpStudy 升级 MySQL 版本到5.7

    1:备份当前数据库数据. 最好是导成 SQL 文件 2:备份 PhpStudy 下的 MySQL 文件夹.以防升级失败.还可以使用旧版本的数据库 3:下载MySQL5.7.解压.然后放在 PhpStu ...

  10. Request.getparameternames 获取form表单里面所有的请求参数 。 返回一个Enumeration类型的枚举.

    通过Enumeration的hasMoreElements()方法遍历.再由nextElement()方法获得枚举的值.此时的值是form表单中所有控件的name属性的值. 最后通过request.g ...