这个是全部的代码,我贴出来,供大家学习参考。
项目截图
uniapp代码
api detail detail.js
import request from '@/api/request.js'
export const getDetail = (data) => {
return request({
url:'/news/detail.php',
method:'GET',
data: data
})
}
api index index.js
import request from '@/api/request.js'
export const getNavList = () => {
return request({
url:'/news/navlist.php',
method: 'GET'
})
}
export const getNewsList = (data)=>{
return request({
url:'/news/newslist.php',
method:'GET',
data:data
})
}
api request.js
let baseUrl = 'https://ku.qingnian8.com/dataApi';
let instance = (config) => {
return new Promise((resolve,rejected)=>{
uni.showLoading({
title:'正在获取数据...',
mask:true
});
uni.request({
url: baseUrl + config.url,
timeout: 5000,
data:config.data,
method: config.method,
success(res){
//成功
if(res.statusCode == 200){
resolve(res);
}else{
//请求失败,提示错误
uni.showToast({
title:res.errMsg,
icon:'error',
mask:true,
duration:2000
});
}
},
complete(res) {
//关闭提示
uni.hideLoading({
complete:()=>{
//成功
// if(res.statusCode != 200){
// //请求失败,提示错误
// uni.showToast({
// title:res.errMsg,
// icon:'error',
// mask:true,
// duration:2000
// });
// }
}
});
}
})
})
}
export default instance;
components newsbox newsbox.vue
<template>
<view class="newsbox">
<view class="pic">
<image :src="item.picurl" mode="aspectFill" class="image"></image>
</view>
<view class="text">
<view class="title">
{{item.title}}
</view>
<view class="info" v-if="!item.lookTime">
<text class="txt">{{item.author}}</text>
<text class="txt">{{item.hits}}浏览</text>
</view>
<view class="info" v-else>
<text class="txt">浏览时间:{{item.lookTime}}</text>
</view>
</view>
</view>
</template>
<script>
export default {
name:"newsbox",
data() {
return {
};
},
props:{
item:{
type:Object,
default(){
return {
title:'组件内默认的标题',
author:'张三',
hits: 998,
picurl:'../../static/logo.png',
lookTime:'2023-01-01 10:10:20'
}
}
}
}
}
</script>
<style lang="scss" scoped>
.newsbox{
display: flex;
justify-content: center;
.pic{
width: 230rpx;
height: 160rpx;
.image{
width: 100%;
height: 100%;
}
}
.text{
flex: 1;
padding-left: 20rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
.title{
font-size: 36rpx;
color: #333;
//
text-overflow: -o-ellipsis-lastline;
overflow: hidden; //溢出内容隐藏
text-overflow: ellipsis; //文本溢出部分用省略号
display: -webkit-box; //特别显示模式
-webkit-line-clamp: 2; //行数
line-clamp: 2;
-webkit-box-orient: vertical; //盒子中内容垂直排列
}
.info{
font-size: 26rpx;
color: #999;
.txt{
padding-right: 30rpx;
}
}
}
}
</style>
pages detail detail.vue
<template>
<view class="detail">
<view class="title">
<text
<!-- #ifndef MP-WEIXIN -->
:selectable="true"
<!-- #endif -->
:user-select="true">
{{detailData.title}}
</text>
</view>
<view class="info">
<view class="author">
作者:{{detailData.author}}
</view>
<view class="time">
发布日期:{{detailData.posttime}}
</view>
</view>
<view class="content">
<rich-text :nodes="detailData.content"></rich-text>
</view>
<view class="desc">
<text
<!-- #ifndef MP-WEIXIN -->
:selectable="true"
<!-- #endif -->
:user-select="true">
声明:本站的内容均采集自腾讯新闻,如有侵权请联系管理员(51389435760qq.com)进行整改删除,本站进行了内容采集不代表本站及作者观点,若有侵犯请及时联系管理员,谢谢您的支持。
</text>|
</view>
</view>
</template>
<script>
import {getDetail} from '@/api/detail/detail.js'
import { parseTime } from '@/utils/tool.js'
export default {
data() {
return {
id:null,
cid:null,
detailData:[]
};
},
onLoad(options) {
console.log("id",options.id)
console.log("cid",options.cid)
this.id = options.id;
this.cid = options.cid;
//
this.getData();
},
methods:{
//把保存浏览历史
saveHistory(){
//先从本地存储,获取是否存在
let historyData = uni.getStorageSync("b-history") || [];
//转换,只取主要的内容
let news = {
id: this.detailData.id,
classid: this.detailData.classid,
picurl: this.detailData.picurl,
title: this.detailData.title,
lookTime: parseTime(Date.now())
}
//先判断,缓存中是否已存在相同记录
let index = historyData.findIndex(ele=>{
return ele.id == news.id
})
//说明有重复的,删除
if(index >= 0){
historyData.splice(index,1);
}
//塞入数组
historyData.unshift(news);
//避免缓存中存放太多数据,仅保留10条最新记录
historyData = historyData.slice(0,10);
//存回本地
uni.setStorageSync("b-history",historyData);
},
//
getData(){
getDetail({
cid: this.cid,
id: this.id
}).then(res=>{
console.log(res)
//时间戳转换时间字符串格式
res.data.posttime = parseTime(res.data.posttime);
//修改小程序中图片超过屏幕右侧的bug
res.data.content = res.data.content.replace(/<img/gi,'<img style="max-width:100%"');
this.detailData = res.data;
//顶部栏修改标题
// uni.setNavigationBarTitle({
// title: this.detailData.title
// })
this.saveHistory();
})
}
}
}
</script>
<style lang="scss" scoped>
.detail{
padding: 30rpx;
.title{
font-size: 46rpx;
color: #333;
}
.info{
background-color: #f6f6f6;
padding: 20rpx;
font-size: 25rpx;
color: #666;
display: flex;
justify-content: space-between;
margin: 40rpx 0;
}
.content{
padding-bottom: 50rpx;
/* #ifdef H5 */
/deep/ img{
max-width: 100%;
}
/* #endif */
}
.desc{
background-color: #fef0f0;
font-size: 24rpx;
padding: 20rpx;
color: #f89898;
line-height: 1.8em;
}
}
</style>
pages index index.vue
<template>
<view class="home">
<scroll-view scroll-x class="nav-scorll">
<view
class="item"
:class="navIndex == index ? 'active': ''"
v-for="(item,index) in navData"
:key="item.id"
@tap="clickNav(index,item.id)">
{{item.classname}}
</view>
</scroll-view>
<view class="content">
<view class="row" v-for="(item,index) in newsData" :key="item.id">
<newsbox :item="item" @tap.native="goDetail(item)"></newsbox>
</view>
</view>
<view class="nodata" v-if="!newsData.length">
<text>此分类下,暂无数据!!!</text>
</view>
<view class="loading" v-if="newsData.length">
<view v-if="loading === 1">数据加载中...</view>
<view v-if="loading === 2">没有更多了~</view>
</view>
</view>
</template>
<script>
import {getNavList,getNewsList} from '@/api/index/index.js'
export default {
data() {
return {
loading:0, //0默认,1 加载中 ,2没有更多了
//当前页
currentPage:1,
//每页条数
pagesize:6,
//分类索引id
id:0,
//导航栏索引
navIndex:0,
//分类索引数据
navData:[],
//新闻数据
newsData:[]
}
},
onLoad() {
//获取索引
this.getNavData();
//获取新闻
this.getNewsData();
},
//触底加载
onReachBottom() {
//如果已经触底,就不再多余发送请求
if(this.loading == 2){
return;
}
//
this.currentPage++;
//
this.loading = 1;
//
this.getNewsData();
},
methods: {
//获取新闻数据,默认50
getNewsData(id=50){
//通过id,在请求对应的新闻数据
getNewsList({
cid: id,
num: this.pagesize,
page: this.currentPage
}).then(res=>{
console.log(res);
this.newsData.push(...res.data);
if(res.data.length <= 0){
console.log('没有了')
//底部提示
this.loading = 2;
//弹窗提示
uni.showToast({
title:'没有更多新闻了!',
icon:'none',
mask:true,
duration:2500
})
}
})
},
//获取分类索引数据
getNavData(){
getNavList().then(res=>{
//console.log(res);
this.navData = res.data;
})
},
//前往新闻详情页
goDetail(obj){
uni.navigateTo({
url:`/pages/detail/detail?cid=${obj.classid}&id=${obj.id}`
});
},
//点击导航滑动分类栏
clickNav(index,id){
//点击时保存当前索引值
this.navIndex = index;
//切换时,先重置数据
this.newsData = [];
this.currentPage = 1;
this.loading = 0;
//
this.getNewsData(id);
}
}
}
</script>
<style lang="scss" scoped>
.home{
.nav-scorll{
height: 100rpx;
background-color: #f7f8fa;
white-space: nowrap;
position: fixed;
top: var(--window-top);
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{
font-size: 40rpx;
line-height: 100rpx;
display: inline-block;
padding: 0 55rpx;
color: #333;
&.active{
color: #31c27c;
}
}
}
.content{
margin-top: 100rpx;
padding: 30rpx;
.row{
border-bottom: 1px dotted #efefef;
padding: 20rpx 0;
}
}
.nodata{
width: 100%;
padding: 50rpx;
color: #999;
text-align: center;
}
.loading{
text-align: center;
font-size: 26rpx;
color: #888;
line-height: 2em;
}
}
</style>
pages user user.vue
<template>
<view class="user">
<view class="top">
<icon type="waiting" size="65" class="image"/>
<text>浏览历史</text>
</view>
<view class="content" v-if="newsData.length">
<view class="row" v-for="(item,index) in newsData" :key="index">
<newsbox :item="item" @tap.native="goDetail(item)"></newsbox>
</view>
</view>
<view class="no-history" v-if="!newsData.length">
<view class="text">暂无浏览记录</view>
</view>
<button type="default" @tap="onClear">清除历史记录</button>
</view>
</template>
<script>
export default {
data() {
return {
//新闻数据
newsData:[]
};
},
methods:{
//清除历史记录
onClear(){
uni.showModal({
title:'删除提示',
content:'您确定要删除全部记录吗?',
confirmColor:'red',
confirmText:'删除',
success(res){
if(res.confirm){
uni.showToast({
title:'删除成功!',
icon:'success'
});
uni.clearStorageSync();
setTimeout(()=>{
// #ifdef H5
window.location.reload();
// #endif
// #ifdef MP-WEIXIN || APP
uni.reLaunch({
url:'/pages/user/user'
});
// #endif
},1500);
}else{
uni.showToast({
title:'已取消删除!',
icon:'none'
});
}
}
})
},
//获取数据
getData(){
let historyData = uni.getStorageSync("b-history") || [];
this.newsData = historyData;
},
//前往新闻详情页
goDetail(obj){
uni.navigateTo({
url:`/pages/detail/detail?cid=${obj.classid}&id=${obj.id}`
});
}
},
onLoad() {
//load只执行一次
//this.getData();
},
onShow() {
this.getData();
}
}
</script>
<style lang="scss" scoped>
.user{
.top{
padding: 35rpx 0;
background-color: #f8f8f8;
color: #666;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.image{
}
text{
font-size: 30rpx;
padding-top: 20rpx;
}
}
.content{
padding: 30rpx;
.row{
border-bottom: 1px dotted #efefef;
padding: 20rpx 0;
}
}
.no-history{
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100rpx;
.text{
font-size: 26rpx;
color: #888;
padding: 20rpx 0;
}
}
}
</style>
utils
//时间间隔函数
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
}
app.vue
<script>
export default {
onLaunch: function() {
console.log('App Launch')
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
}
}
</script>
<style>
/*每个页面公共css */
*{
padding: 0;
margin: 0;
box-sizing: border-box;
}
</style>
pages.json
{
"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "首页"
}
},
{
"path" : "pages/user/user",
"style" :
{
"navigationBarTitleText" : "个人中心",
"enablePullDownRefresh" : false
}
},
{
"path" : "pages/detail/detail",
"style" :
{
"navigationBarTitleText" : "新闻详情",
"enablePullDownRefresh" : false
}
}
],
"globalStyle": {
"navigationBarTextStyle": "white",
"navigationBarTitleText": "青年新闻",
"navigationBarBackgroundColor": "#2CAF73",
"backgroundColor": "#F8F8F8"
},
"uniIdRouter": {},
"tabBar": {
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "static/tabbar/home.png",
"selectedIconPath": "static/tabbar/home-s.png"
},
{
"pagePath": "pages/user/user",
"text": "个人中心",
"iconPath": "static/tabbar/mine.png",
"selectedIconPath": "static/tabbar/mine-s.png"
}
]
}
}
manifest.json
/* 小程序特有相关 */
"mp-weixin" : {
"appid" : "wx86209e8eccbc4307",
"setting" : {
"urlCheck" : false,
"es6" : true,
"postcss" : true,
"minified" : true
},
"lazyCodeLoading" : "requiredComponents"
},
测试
首页
详情页
个人中心页
清除历史
以上就是全部代码,希望对各位有所帮助。
另外本项目是学习自青年帮新闻项目而来,在此感谢咸虾米老师,无私的讲解项目的视频教程,让我对学习uniapp受益良多,感谢感谢。