开发一个微信小程序(3):编写公众号文章列表
本篇讲一下如何把微信公众号中发布的文章移植到小程序中
具体展示内容以及列表样式,我参考了订阅号助手中的「历史图文素材」,如下
所以在小程序中需要实现以下功能:
- 获取已发布的素材;
- 将数据渲染到前端,每条数据包含标题、概要、图片(这些字段接口都有返回);
- 调整列表样式;
- 点击文章跳转至详情;
1、获取已发布的素材
在之前一篇文章中介绍了如果通过接口获取公众号素材,传送门:开发一个微信小程序(1):获取文章列表
打开根目录下app.json
,先创建2个文件夹 wx_article
和 wx_article_detail
最开始我的想法是通过接口来实时拿到微信公众号的文章,但是经过一番操作发现行不通,原因是:微信不允许直接在小程序中调用微信公众号的接口(主要是会暴露一些敏感信息,例如AppID)
然后我把调用公众号接口相关的功能写到了服务端(用flask即可),本地部署好服务后,尝试在小程序中调用自己定义的接口,结果发现小程序不允许直接调用ip地址,需要配置域名
接着我修改本地host文件,把ip和域名做了一个映射,使用postman通过域名调用flask接口时,提示成功,然后尝试在小程序调用,发现依然不行,这次提示我的域名不安全,不是https
接着我又去阿里云购买了一个域名,同时申请了一个免费的ssl证书,把域名和我本地ip绑定,同时修改flask启动方式,这样就能用https访问接口了,经过postman试验调用成功,然后尝试在小程序调用,发现又失败了,这次提示我的域名没有进行备案?
心态快炸了,没想到卡在了这里,微信小程序的限制也太多了
最后我决定先跳过这里,把公众号文章的数据提取到一个js文件中,然后在小程序中,直接去读这个js文件来获取数据,这样我就不必卡在这里,可以继续进行后面的学习了~
1.1 创建一个js文件,存放文章数据
在根目录下创建一个文件夹 data
,然后在data
下创建一个文件wx_article_data.js
里面的数据,是我通过接口拿到的,都粘贴到了这个文件中
1.2 读取并处理数据
打开 /pages/wx_article/wx_article.js
,编辑如下代码
// pages/wx_article/wx_article.js
//引入本地数据
var wxArticleData = require("../../data/wx_article_data.js")
Page({
/**
* 页面的初始数据
*/
data: {
page: 1,
posts: [],
isloading: false, //定一个标识符,默认为false,表示当前没有发送请求
},
//提取本地存储的微信公众号数据
get_wx_article() {
//开始取数据时,将isloading置为true
this.setData({
isloading: true //为true时,表示正在发起请求
})
//展示loading效果
wx.showLoading({
title: '努力加载中...',
})
if (this.data.page === 1) {
this.setData({
posts: [...this.data.posts, ...wxArticleData.wxData.slice(0, 10)] //第一次取前10个
})
}
else {
this.setData({
//后续当page>1时,从下标开始取10个
posts: [...this.data.posts, ...wxArticleData.wxData.slice(this.data.page*10-10, this.data.page*10)]
})
}
//取完数后
wx.hideLoading() //隐藏loading效果
//取数后,将isloading置为false
this.setData({
isloading: false
})
},
//通过编程式导航跳转到非tabBar页面
gotodetail(e) {
// console.log(e);
const item = e.currentTarget.dataset['item'];
// console.log(item);
const article_url = item.url;
const jpg_url = item.jpg_url;
wx.navigateTo({
url: '/pages/wx_article_detail/wx_article_detail?article_url='+
encodeURIComponent(article_url)+'&jpg_url='+encodeURIComponent(jpg_url)
})
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
this.get_wx_article()
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
wx.setNavigationBarTitle({
title: '公众号文章', //把这个页面的标题自定义设置一下
})
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
//请求前,需要重置参数
this.setData({
page: 1,
posts: [],
})
this.get_wx_article() //下拉刷新调用这个函数,重新发起请求
wx.stopPullDownRefresh() //真机上,刷新完后,调用这个方法,关闭下拉刷新
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
if(this.data.isloading) return //如果isloading为true,则退出onReachBottom这个方法
this.setData({
page: this.data.page + 1 //上拉触底时,给页码加1,这样再发起请求时,就请求到了下一组的数据
})
this.get_wx_article() //调用获取随笔的方法
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
}
})
主要是 get_wx_article()
方法,它的作用是读取 wx_article_data.js
中的数据并进行处理
每次提取10个,上拉页面触底时,加载下一组数据
在data
中定义了一个参数page
,如果page=1
,则取前10个数据
if (this.data.page === 1) {
this.setData({
posts: [...this.data.posts, ...wxArticleData.wxData.slice(0, 10)] //第一次取前10个
})
}
如果page>1
, 则从下标开始往后取10个
else {
this.setData({
//后续当page>1时,从下标开始取10个
posts: [...this.data.posts, ...wxArticleData.wxData.slice(this.data.page*10-10, this.data.page*10)]
})
}
在上拉触底事件中,给page+1
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
if(this.data.isloading) return //如果isloading为true,则退出onReachBottom这个方法
this.setData({
page: this.data.page + 1 //上拉触底时,给页码加1,这样再发起请求时,就请求到了下一组的数据
})
this.get_wx_article() //调用提取本地存储的微信公众号数据的方法
},
2、将数据渲染到前端 & 调整列表样式
打开 /pages/wx_article/wx_article.wxml
<!--pages/wx_article/wx_article.wxml-->
<!-- <text>pages/wx_article/wx_article.wxml</text> -->
<!-- 文章列表 -->
<view class="box">
<view class="items" wx:for="{{posts}}" wx:key="media_id" bindtap="gotodetail" data-item="{{item}}">
<view class="father">
<view class="son1">
<text class="title">{{item.title}}</text>
<text class="digest">{{item.digest}}</text>
</view>
<view class="son2">
<image src="{{item.jpg_url}}" mode="aspectFill"></image>
</view>
</view>
<!-- <view class="bottom-element">
<text class="little-text">阅读:({{item.ViewCount}}) 评论:({{item.CommentCount}})</text>
<text class="post-date">{{tools.splitDate(item.PostDate)}}</text>
</view> -->
</view>
</view>
用for循环渲染数据,同时添加编程式导航,使得点击文章能够跳转至详情,使用bindtap
绑定事件gotodetail
同时传递一个参数item
,item
的值就是for循环的item对象
,写法data-item="{{item}}"
gotodetail()
方法如下
//通过编程式导航跳转到非tabBar页面
gotodetail(e) {
// console.log(e);
const item = e.currentTarget.dataset['item']; //接收页面传来的参数item
// console.log(item);
const article_url = item.url; //获取item中的url
const jpg_url = item.jpg_url; // 获取item中的jpg_url
wx.navigateTo({
url: '/pages/wx_article_detail/wx_article_detail?article_url='+
encodeURIComponent(article_url)+'&jpg_url='+encodeURIComponent(jpg_url)
//这里对文章url和图片url做了转码处理,因为url中包含很多特殊字符,直接传递会丢失
})
},
接下来再调整样式
主要是把标题放上面,概要放下面,图片放右侧
打开/pages/wx_article/wx_article.wxss
/* pages/wx_article/wx_article.wxss */
.items {
height: 150rpx;
border-bottom: 15rpx solid #efefef;
/* border-radius: 8rpx; */
line-height: 50rpx;
/* margin: 10rpx; */
position: relative;
padding-top: 20rpx;
background-color: rgb(255, 255, 255); /*设置每张小卡片的颜色*/
}
.father{
display: flex;
}
.son1{
width: 80%;
display: flex;
flex-direction: column; /*使元素纵向布局(默认为横向)*/
}
.son2{
width: 20%;
display: flex;
}
image{
height: 90%;
width: 100%;
margin-right: 20rpx;
margin-left: 10rpx;
}
.title{
font-size:32rpx;
margin-left: 20rpx;
margin-right: 20rpx;
display: -webkit-box; /*设置为弹性盒子*/
overflow:hidden; /*超出隐藏*/
text-overflow: ellipsis; /*显示省略号*/
-webkit-line-clamp: 1; /*多少行后显示省略号,这里设置为第一行超出后显示省略号*/
word-break:break-all; /*强制英文单词自动换行,可要可不要*/
-webkit-box-orient: vertical; /* 从上到下垂直排列子元素*/
}
.digest {
font-size: 27rpx;
color: gray;
margin-top: 30rpx;
margin-left: 20rpx;
display: -webkit-box; /*设置为弹性盒子*/
overflow:hidden; /*超出隐藏*/
text-overflow: ellipsis; /*显示省略号*/
-webkit-line-clamp: 1; /*多少行后显示省略号,这里设置为第一行超出后显示省略号*/
word-break:break-all; /*强制英文单词自动换行,可要可不要*/
-webkit-box-orient: vertical; /* 从上到下垂直排列子元素*/
}
3、文章详情
如果我们拿到公众号文章的url后,可以使用<web-view>
标签来展示详情
前提是要把公众号与小程序进行关联,打开微信公众平台,找到如下位置进行关联即可
对应代码如下
/pages/wx_article_detail/wx_article_detail.js
// pages/wx_article_detail/wx_article_detail.js
Page({
/**
* 页面的初始数据
*/
data: {
query: {} ,// 接收navigator传来的参数
article_url: "",
jpg_url: ""
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
this.setData({
query: options, //把navigator传来的参数赋给query
article_url: decodeURIComponent(options.article_url),
jpg_url: decodeURIComponent(options.jpg_url)
})
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
wx.setNavigationBarTitle({
title: '文章详情', //把这个页面的标题自定义设置一下
})
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
}
})
pages/wx_article_detail/wx_article_detail.wxml
<!--pages/wx_article_detail/wx_article_detail.wxml-->
<web-view src="{{article_url}}"></web-view>
<!-- <text>{{article_url}}</text> -->
OK,这样就完成了公众号文章列表功能页面