1、新建uniapp项目
2、新建界面(新闻界面、个人中心界面)
3、配置tabBar![9659b275d9e54ccd91b97cddc47409f7.png](https://i-blog.csdnimg.cn/blog_migrate/6b4af3f02336b1806132a8f0a96b8436.png)
显示界面如下:
在图标素材网站找首页和个人的矢量图
步骤:
(1)选择喜欢的图标后,点击下载,然后同样的图标下载两个,一个是选中前的图片,一个是选中后的图片
(2)将下载的几张图片放在一个文件夹中,再将文件夹放至项目的static里面
(3)运用下载的图标设置后页面显示如下:
(4)设置导航栏背景颜色,导航栏标题颜色,设置导航栏标题文本
4、scroll-view实现横向滚动条样式
<template>
<view class="home">
<view class="scrollNav">
<scroll-view scroll-x class="navscroll">
<view class="item">国内</view>
<view class="item">国内</view>
<view class="item">国内</view>
<view class="item">国内</view>
<view class="item">国内</view>
<view class="item">国内</view>
<view class="item">国内</view>
<view class="item">国内</view>
<view class="item">国内</view>
<view class="item">国内</view>
<view class="item">国内</view>
<view class="item">国内</view>
<view class="item">国内</view>
</scroll-view>
</view>
<view class="content">
<view class="row">
每一行新闻显示的内容
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
title: 'Hello'
}
},
onLoad() {
},
methods: {
}
}
</script>
<style scoped lang="scss">
.navscroll {
display: flex;
height: 100rpx;
background-color: #F1F3F5;
// nowarp:使用了该属性后,文本将会在不换行的情况下一直显示,直到文本结束或者遇到换行符为止。
white-space: nowrap;
// 去掉国内字下拉条
/deep/ ::-webkit-scrollbar {
width: 4px !important;
height: 1px !important;
overflow: auto !important;
background: transparent !important;
-webkit-appearance: auto !important;
display: block;
}
.item {
display: inline-block;
line-height: 100rpx;
padding: 0 28rpx;
font-size: 38rpx;
}
}
</style>
5、定义components组件(里面设置每一条新闻显示的样式)
<template>
<view class="newbox">
<view class="pic">
<image src="../../static/qingnianbang/壁纸2.jpg" mode="aspectFit"></image>
</view>
<view class="text">
<view class="title">
默认新闻标题默认新闻标题默认新闻标题默认新闻标题默认新闻标题默认新闻标题默认新闻标题
</view>
<view class="info">
<text>作者名称</text>
<text>998浏览</text>
</view>
</view>
</view>
</template>
<script>
export default {
name: "newsbox",
data() {
return {
};
}
}
</script>
<style lang="scss">
.newbox {
display: flex;
image {
width: 240rpx;
height: 200rpx;
}
.text {
flex: 1;
padding: 5rpx 20rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
.title {
font-size: 38rpx;
color: #333;
// 设置溢出部分隐藏;
overflow: hidden;
// 设置文本溢出时以省略号显示;
text-overflow: ellipsis;
// 设置显示为块级元素;
display: -webkit-box;
// 设置最多显示2行文本
-webkit-line-clamp: 2;
// 设置文本溢出时以省略号显示最后一行
text-overflow: -o-ellipsis-lastline;
// 设置文本排列方式为垂直
-webkit-box-orient: vertical;
}
.info {
font-size: 26rpx;
color: #999;
text {
padding-right: 30rpx;
}
}
}
}
</style>
6、布局个人中心页面定义组件默认值
个人中心页面样式
<template>
<view class="user">
<view class="top">
<image src="../../static/qingnianbang/历史记录.png" mode=""></image>
<text>浏览历史</text>
</view>
<view class="content">
<view class="row" v-for="item in 10">
<newsbox></newsbox>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
}
},
methods: {
}
}
</script>
<style scoped lang="scss">
.top{
display: flex;
flex-direction: column;
background-color: #F7F7F7;
image{
margin: 50rpx auto 30rpx auto;
height: 150rpx;
width: 150rpx;
}
text{
// padding: 50rpx;
text-align: center;
font-size: 38rpx;
padding-bottom: 50rpx;
}
}
.content{
margin-top: 40rpx;
}
</style>
组件默认值
<template>
<view class="newbox">
<view class="pic">
<image :src="item.picurl" mode="aspectFit"></image>
</view>
<view class="text">
<view class="title">
{{ item.title }}
</view>
<view class="info">
<text>{{ item.author }}</text>
<text class="a">{{ item.hits }}浏览</text>
</view>
</view>
</view>
</template>
<script>
export default {
name: "newsbox",
props: {
item: {
type: Object,
default () {
return {
title: "组件内的默认标题",
author: "张三",
hits: "668",
picurl: '../../static/qingnianbang/壁纸2.jpg'
}
}
}
},
data() {
return {
};
}
}
</script>
<style lang="scss">
.newbox {
display: flex;
image {
width: 240rpx;
height: 200rpx;
}
.text {
flex: 1;
padding: 5rpx 20rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
.title {
font-size: 38rpx;
color: #333;
// 设置溢出部分隐藏;
overflow: hidden;
// 设置文本溢出时以省略号显示;
text-overflow: ellipsis;
// 设置显示为块级元素;
display: -webkit-box;
// 设置最多显示2行文本
-webkit-line-clamp: 2;
// 设置文本溢出时以省略号显示最后一行
text-overflow: -o-ellipsis-lastline;
// 设置文本排列方式为垂直
-webkit-box-orient: vertical;
}
.info {
font-size: 26rpx;
color: #999;
text {
padding-right: 30rpx;
}
.a {
padding: 30rpx;
}
}
}
}
</style>
实现组件化的差异
在newsbox组件中,新增一个名为info的类盒子。实现逻辑是判断传递给组件的值中是否包含item.lootime的值。如果不包含,就显示首页盒子的内容;如果包含,就只显示浏览时间的盒子。通过这种方式,可以根据传递的值来实现组件的显示样式差异化。
7、uniapp内置css变量window-top的吸顶效果
//使用CSS变量(–window-top)来指定元素的顶部位置
top: var(--window-top);
// 将导航栏国内那一行固定在上方
//(将元素的定位方式设置为固定定位。元素的位置相对于视窗固定,不会随页面滚动而改变)
position: fixed;
left: 0;
z-index: 10;
8、导航栏点击高亮
通过设置一个变量navindex
为0,可以在导航栏的选项设置点击事件,并将点击的下标传递给navindex
变量。然后,可以创建一个名为active
的CSS类,用于设置选中项的颜色。通过使用三元运算符判断,如果下标等于navindex
变量的值,则应用active
颜色类,就可以实现点击高亮的效果。
<template>
<view class="home">
<view class="scrollNav">
<scroll-view scroll-x class="navscroll">
<view class="item" v-for="(item,index) in 10" @click="clickNav(index)"
:class="index=== navindex?'ative':''" :key="item.id">国内</view>
</scroll-view>
</view>
<view class="content">
<view class="row" v-for="item in 10">
<newsbox></newsbox>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
title: 'Hello',
navindex: 0
}
},
onLoad() {
},
methods: {
clickNav(index) {
this.navindex = index
}
}
}
</script>
<style scoped lang="scss">
.navscroll {
display: flex;
height: 100rpx;
background-color: #F1F3F5;
// nowarp:使用了该属性后,文本将会在不换行的情况下一直显示,直到文本结束或者遇到换行符为止。
white-space: nowrap;
top: var(--window-top);
// 将导航栏国内那一行固定在上方
position: fixed;
left: 0;
z-index: 10;
//自定义滚动条,使滑动的时候滚动条不会显示在页面
/deep/ ::-webkit-scrollbar {
width: 4px !important;
height: 1px !important;
overflow: auto !important;
background: transparent !important;
-webkit-appearance: auto !important;
display: block;
}
.item {
display: inline-block;
line-height: 100rpx;
padding: 0 28rpx;
font-size: 38rpx;
}
}
.content {
margin-top: 120rpx;
.row {
border-bottom: 1px dashed #efefef;
}
}
.ative {
color: #3DD680;
}
</style>
9、页面跳转与详情页布局
设置单击事件跳转到详情页(设置详情页地址)在index和user里面都要设置
创建详情页面,页面样式
<template> <view class="detail"> <view class="title"> 文章标题 </view> <view class="info"> <view class="author"> 编辑:张三 </view> <view class="time"> 发布时间:2022-12-12 15:30:00 </view> </view> <view class="content"> 内容部分 </view> <view class="description"> 声明:本站的内容均采集与腾讯新闻,如果侵权请联系管理(51389257@qq.com)进行删除,本站进行了内容采集不代表本站及作者观点,若有侵权请及时联系管理员,谢谢您的支持 <view> </view> </template> <script> export default { data() { return { }; }, } </script> <style lang="scss" scoped> .detail { .title { margin: 40rpx 20rpx; font-size: 50rpx; } .info { background-color: #F6F6F6; display: flex; justify-content: space-between; margin: 20rpx 25rpx 40rpx 25rpx; padding: 25rpx; color: #8E898A; } .content { margin: 0 20rpx; padding-bottom: 50rpx; } .description { background: #FEF0F0; font-size: 26rpx; padding: 20rpx; color: #F89898; line-height: 1.8em; } } </style>
10、uni.request获取网络请求渲染到页面中
三个接口地址:
获取新闻详情
url: "https://ku.qingnian8.com/dataApi/news/detail.php",
获取新闻列表
url: "https://ku.qingnian8.com/dataApi/news/newslist.php",
获取新闻栏目
url: "https://ku.qingnian8.com/dataApi/news/navlist.php",
拿到新闻栏目数据
可以看到区分新闻栏目是根据id进行划分的,并且数据类型是数组
创建一个名为navArr的数组,并将获取到的数据赋值给navArr。然后,需要将页面中的栏目遍历的数量10改为使用navArr中的数据进行渲染,实现页面内容的动态更新。
获取新闻列表(渲染步骤与前面一致)
将遍历后的数据传给组件
这里的 :item
是子组件定义的 prop(属性),用于接收从父组件传递过来的数据。而 "item" 是父组件中要传递的具体数据。
到这里实现了综合页面的渲染,这个接口需要根据cid=id(id是导航栏目里面的id)传值进行判断,才可以实现新闻栏目分类的效果,cid
是一个关键的参数,用于从后端 API 获取特定分类的新闻数据。当点击导航栏中的某个新闻分类时,cid
会被传递给后端接口,以获取该分类下的新闻列表。也就是cid=50则显示国内的新闻,cid=51则显示国际新闻...
参数名 | 介绍 | 是否必填 |
cid | 栏目id | 必填 |
num | 获取的条数 | 非必填 |
page | 页码 | 非必填 |
返回值
参数名 | 介绍 |
id | id唯一标识 |
title | 标题 |
11、点击导航跳转不同的新闻页面
因为接口需要id所以我们需要先拿到id,以便于赋值给cid
在新闻栏目点击事件里面的方法再次调用网络请求的方法,将拿到的新闻栏目的id将id通过网络请求发送给获取网络请求数据的方法,在被调用的方法中接收被点的id,然后在默认的情况下方法中的id=50是指id的默认值为50,50对应的就是国内的新闻id,也就是默认显示国内新闻。如果点击之后进行调用之后就是将id赋值给cid,就显示传入id对应的新闻界面,以达到切换新闻栏目的分类效果。
如果当前栏目没有数据,就应该显示没有数据的image
12、onReachBottom触底加载更多翻页效果(onReachBottom页面滚动到底部的事件(不是scroll-view滚到底),常用于下一页数据。)
在我们拿到新闻列表的接口中,page是根据页码来显示展示的数据
在网络请求中增加一个名为"page"的参数,展示当前的页面数。设置一个全局变量"currentPage",将初始值设为自己想要的页面,比如1。当触发底事件时,通过改变的值来更新"page"的值,即"currentPae++”。再onReachBottom()方法里在调用一次网络请求,获取新一组的数据。这样就可以实现翻功能,获取到新的数据展示。但是这样的话就不能翻回翻页前的数据,所以我们需要加载更多,将原有的数据拼接到新的数据。
但是以上操作可能导致点击新的新闻栏目分组时候page还是显示的加载后的page页面的内容,所以我们需要再点击新闻栏目分组时,重新将page的值赋值为1。赋值为1后会将新点击的栏目数据从新追加到数据里面,所以我们还需要将原有数组里面的内容清空。
13、优化细节增加loading加载样式
设置全局变量loading默认值赋值为0(不显示内容),1=加载中,2=没有更多内容了
判断什么时候需要显示什么
在触底的时候我们获取网络请求的时候需要添加数据加载中,所以在触底事件中,页面++后,将loading的状态设置为1,也就是数据加载中,同时,再切换导航的时候我们需要将loading重新赋值为默认值0。再获取网络请求的方法中做判断,如果我们获取的数据的长度为0,就将loading的值改为2,也就是没有更多内容了。
如果loading状态已经变成2了,就不用再去翻页和请求了,所以在这里做一个判断。然后页面没有数据也会显示没有更多内容了 我们直接在loading这个盒子做一个判断,如果newarr数组有数据才显示就可以了。
14、获取参数跳转到不同的详情页
获取新闻详情需要的参数
参数名 | 介绍 | 是否必填 |
cid | 栏目id | 必填 |
id | 当前新闻id | 必填 |
返回值
参数名 | 介绍 |
id | id唯一标识符 |
title | 标题 |
picurl | 缩略图地址 |
posttime | 发布时间 |
classid | 栏目id |
author | 作者 |
hits | 浏览量 |
页面跳转的时候将item传过去,item这个对象里面就包含了需要的参数
在方法中接收
console.log打印item就可以在浏览器控制台看到打开详情页后,可以看到item的数据已经传递过去
这个接口需要接收两个参数:cid和id。可以通过uni.navigateTo方法中的url将这两个参数传递给目标页面。在接收参数的页面,使用onLoad生命周期函数来接收参数,并将其渲染到页面上
cid=栏目id 所以在控制台的数据中可以看到我们需要传递的数据名为classid,id=当前新闻的id。
创建一个全局变量,将onload函数里接收到的数据赋值给创建的全局变量。
在获取新闻详情网络请求中,将onload获取到的参数放在data里面,就可以拿到新闻详情的数据,在全局变量中创建一个对象,将新闻详情的数据赋值给这个定义的对象,就通过调用对象里面的数据在页面进行渲染。
使用rich-text解析富文本 (rich-text标签是小程序(微信小程序和支付宝小程序)中的一个组件,它的作用是用于渲染富文本内容。富文本内容指的是带有多种样式(如字体、颜色、大小等)和标签(如链接、图片等)的文本内容。)
<rich-text :nodes="detail.content"></rich-text>
这段代码的作用是在小程序中使用rich-text
组件来渲染富文本内容。具体来说,detail.content
是一个存储富文本内容的数据字段,它可以是一个字符串,也可以是一个包含富文本标签和样式的数组。这个数据字段可以通过绑定语法(:nodes="detail.content"
)传递给rich-text
组件的nodes
属性。nodes
属性接受一个数组作为参数,数组中的每个元素表示一个富文本节点。富文本节点可以是一个文本节点(纯文本内容),也可以是一个节点对象,其中包含了富文本标签和样式。组件会根据传入的nodes
数组解析并渲染出对应的富文本内容。
15、解决小程序图片宽度超出页面显示范围
将字符串中的所有"<img"替换为’<img style=“max-width:100%”‘。这个替换操作是通过使用正则表达式来匹配字符串中的"<img",并用新的字符串’<img style=“max-width:100%”'来替换它们。这样做的目的是给所有的图片元素添加一个样式,使其最大宽度限制为100%。就可以解决图片宽度超出页面显示范围。
16、转换时间戳
新建目录utils,创建js文件。
将以下内容赋值在工具类中
//时间间隔函数
export function timeInterval(timesData) {
//如果时间格式是正确的,那下面这一步转化时间格式就可以不用了
var dateBegin = timesData;//将-转化为/,使用new Date
var dateEnd = new Date();//获取当前时间
var dateDiff = Math.abs( dateEnd.getTime() - dateBegin ); //时间差的毫秒数
var yearDiff = Math.floor(dateDiff / (24 * 3600 * 1000*365));
var dayDiff = Math.floor(dateDiff / (24 * 3600 * 1000)); //计算出相差天数
var leave1 = dateDiff % (24 * 3600 * 1000) //计算天数后剩余的毫秒数
var hours = Math.floor(leave1 / (3600 * 1000))//计算出小时数
//计算相差分钟数
var leave2 = leave1 % (3600 * 1000) //计算小时数后剩余的毫秒数
var minutes = Math.floor(leave2 / (60 * 1000))//计算相差分钟数
//计算相差秒数
var leave3 = leave2 % (60 * 1000) //计算分钟数后剩余的毫秒数
var seconds = Math.round(leave3 / 1000);
var timesString = '';
if (yearDiff!=0){
timesString = yearDiff + '年前';
} else if (yearDiff == 0 && dayDiff != 0) {
timesString = dayDiff + '天前';
} else if (dayDiff == 0 && hours != 0) {
timesString = hours + '小时前';
} else if (hours == 0 && minutes != 0) {
timesString = minutes + '分钟前';
} else if (minutes == 0 && seconds<60){
timesString = '刚刚';
}
return timesString
}
// 日期格式化
export function parseTime(time, pattern) {
if (arguments.length === 0 || !time) {
return null
}
const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}'
let date
if (typeof time === 'object') {
date = time
} else {
if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
time = parseInt(time)
} else if (typeof time === 'string') {
time = time.replace(new RegExp(/-/gm), '/').replace('T', ' ').replace(new RegExp(/\.[\d]{3}/gm), '');
}
if ((typeof time === 'number') && (time.toString().length === 10)) {
time = time * 1000
}
date = new Date(time)
}
const formatObj = {
y: date.getFullYear(),
m: date.getMonth() + 1,
d: date.getDate(),
h: date.getHours(),
i: date.getMinutes(),
s: date.getSeconds(),
a: date.getDay()
}
const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
let value = formatObj[key]
// Note: getDay() returns 0 on Sunday
if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] }
if (result.length > 0 && value < 10) {
value = '0' + value
}
return value || 0
})
return time_str
}
引入
在网络请求中使用,将posttime值通过转换函数转换后重新赋值给posttime,就可以完成时间戳的转换。
设置当前页面的动态标题(uni.setNavigationBarTitle(object)函数)
17、StorageSync读写缓存渲染浏览记录页面
网络请求里获取获取到数据之后,调用savaHistory函数,在savaHistory函数定义缓存数据方法。(通过uni.getStorageSync函数从本地存储中同步获取名为"historyArr"的值,将其赋给变量historyArr。如果本地存储中没有"historyArr"的值,那么将historyArr赋值为空数组。)在savaHistory函数里定义变量let,将我们需要的参数放在里面,再通过uni.setStorageSync方法将该对象保存到名为historyArr的本地存储中。
查看本地储存
在详情页里接收传递过来的参数
重复点击会将重复添加历史记录
历史记录去重
无历史记录优化细节