一、实验准备
课程主页:课程主页(gitee.com)
实验文档:lab5文档
海大官网:海大官网
初始资料:项目初始文件夹压缩包
参考资料:参考资料
二、实验目标
1、综合所学知识创建完整的前端新闻小程序项目;
2、能够在开发过程中熟练掌握真机预览、调试等操作。
3、按照海大首页三个新闻重新整理:“中国海大志愿者完成第五届跨国公司领导人青岛峰会志愿服务”,“贵州省人大干部综合能力提升培训班在中国海洋大学举办”,“中国海洋大学开展2024级本科生集中入学教育”。
三、实验步骤
1、项目创建和页面配置
基本流程见前两个lab,在此不再赘述。
本项目一共需要 3 个页面,即首页、新闻页和个人中心页,其中首页和个人中心页需 要以 tabBar 的形式展示,可以点击 tab 图标互相切换。
1.1 首页功能需求
(1)首页需要包含幻灯片播放效果和新闻列表;
(2)幻灯片至少要有3幅图片自动播放;
(3)点击新闻列表可以打开新闻全文。
1.2 新闻页功能需求
(1)阅读新闻全文的页面需要显示新闻标题、图片、正文和日期;
(2)允许点击按钮将当前阅读的新闻添加到本地收藏夹中;
(3)已经收藏过的新闻也可以点击按钮取消收藏。
1.3 个人中心页功能需求
(1)未登录状态下显示登录按钮,用户点击以后可以显示微信头像和昵称。
(2)登录后读取当前用户的收藏夹,展示收藏的新闻列表。
(3)收藏夹中的新闻可以直接点击查看内容。
(4)未登录状态下收藏夹显示为空。
2、全局设计
2.1 导航栏设计
编写App.json:
{
"pages":[
"pages/index/index",
"pages/detail/detail",
"pages/my/my"
],
"window":{
"backgroundTextStyle":"light",
"navigationBarBackgroundColor": "#24A0ED",
"navigationBarTitleText": "实验五:高校新闻网",
"navigationBarTextStyle":"white"
},
"tabBar": {
"color": "#000",
"selectedColor": "#24A0ED",
"list": [
{
"pagePath": "pages/index/index",
"iconPath": "images/index.png",
"selectedIconPath": "images/index_blue.png",
"text": "首页"
},
{
"pagePath": "pages/my/my",
"iconPath": "images/my.png",
"selectedIconPath": "images/my_blue.png",
"text": "我的"
}
]
},
"style": "v2",
"sitemapLocation": "sitemap.json"
}
2.2 全局数据设计
编写common.js:
//模拟新闻数据
const news = [
{id: '264698',
title: '中国海大志愿者完成第五届跨国公司领导人青岛峰会志愿服务',
poster: 'https://news.ouc.edu.cn/_upload/article/images/dd/19/ede76a4a4ebdb1d3ab278a12fdd8/9bb154f8-e33b-421a-b453-82c758a32405.jpg',
content: `中国海大志愿者完成第五届跨国公司领导人青岛峰会志愿服务的新闻详情内容`,
add_date: '2024-08-31'},
{id: '304083',
title: '贵州省人大干部综合能力提升培训班在中国海洋大学举办',
poster: 'https://news.ouc.edu.cn/_upload/article/images/3a/4d/73b22a9b404f93e907238f2a2325/55606b28-53b8-412f-9420-74c7a30657b6.jpg',
content: `贵州省人大干部综合能力提升培训班在中国海洋大学举办的新闻详情内容`,
add_date: '2024-08-30'},
{id: '305670',
title: '中国海洋大学开展2024级本科生集中入学教育',
poster: 'https://news.ouc.edu.cn/_upload/article/images/94/9e/509119874e5287e8c56ef708865b/11604054-e936-468b-a50e-a4233e475a53.jpg',
content: `中国海洋大学开展2024级本科生集中入学教育的新闻详情内容`,
add_date: '2024-08-29'}
];
//获取新闻列表
function getNewsList() {
let list = [];
for (var i = 0; i < news.length; i++) {
let obj = {};
obj.id = news[i].id;
obj.poster = news[i].poster;
obj.add_date = news[i].add_date;
obj.title = news[i].title;
list.push(obj);
}
return list; //返回新闻列表
}
//获取新闻内容
function getNewsDetail(newsID) {
let msg = {
code: '404', //没有对应的新闻
news: {}
};
for (var i = 0; i < news.length; i++) {
if (newsID == news[i].id) { //匹配新闻id编号
msg.code = '200'; //成功
msg.news = news[i]; //更新当前新闻内容
break;
}
}
return msg; //返回查找结果
}
// 对外暴露接口
module.exports = {
getNewsList: getNewsList,
getNewsDetail: getNewsDetail
}
3、视图与逻辑设计
3.1 首页设计
首页主要包含两部分内容,即幻灯片滚动和新闻列表。
首页主要有两个功能:一是展示新闻列表,二是点击新闻标题可以跳转对应的内容页面进行浏览。
编写index.wxml:
<!--pages/index/index.wxml-->
<!--幻灯片滚动-->
<swiper indicator-dots="true" autoplay="true" interval="5000" duration="500" style="height: {{swiperHeight}}px;" circular="true">
<block wx:for="{{swiperImg}}" wx:key='index'>
<swiper-item class="swiper-item">
<image src="{{item.src}}" class="swiper-image" mode="aspectFit" bindload="imageLoad"></image>
</swiper-item>
</block>
</swiper>
<!--新闻列表-->
<view id='news-list'>
<view class='list-item' wx:for="{{newsList}}" wx:for-item="news" wx:key="id">
<image src='{{news.poster}}'></image>
<text bindtap='goToDetail' data-id='{{news.id}}'>◇{{news.title}}——{{news.add_date}}</text>
</view>
</view>
编写index.wxss
/* pages/index/index.wxss */
/*2-1新闻列表容器*/
#news-list {
min-height: 600rpx;
padding: 15rpx;
}
/*2-2列表项目*/
.list-item{
display: flex;
flex-direction: row;
border-bottom: 1rpx solid gray;
}
/*2-3新闻图片*/
.list-item image{
width:230rpx;
height: 150rpx;
/* width:100%;
height: auto; */
margin: 10rpx;
}
/*2-4新闻标题*/
.list-item text{
width: 100%;
line-height: 60rpx;
font-size: 10pt;
}
/* 轮播图容器 */
.swiper-item {
display: flex;
justify-content: center;
align-items: center;
}
/* 轮播图图片 */
.swiper-image {
max-width: 100%;
max-height: 100%;
}
编写index.js:
// pages/index/index.js
var common = require('../../utils/common.js') //引用公共JS文件
Page({
data: {
//幻灯片素材
swiperImg: [{
src: 'https://news.ouc.edu.cn/_upload/article/images/dd/19/ede76a4a4ebdb1d3ab278a12fdd8/9bb154f8-e33b-421a-b453-82c758a32405.jpg'
},
{
src: 'https://news.ouc.edu.cn/_upload/article/images/3a/4d/73b22a9b404f93e907238f2a2325/55606b28-53b8-412f-9420-74c7a30657b6.jpg'
},
{
src: 'https://news.ouc.edu.cn/_upload/article/images/94/9e/509119874e5287e8c56ef708865b/11604054-e936-468b-a50e-a4233e475a53.jpg'
}
],
},
imageLoad: function(e) {
const { width, height } = e.detail;
wx.getSystemInfoAsync({
success: (res) => {
const windowWidth = res.windowWidth;
const swiperHeight = (windowWidth * height) / width;
this.setData({
swiperHeight
});
}
});
},
goToDetail: function (e) {
//获取携带的data-id数据
let id = e.currentTarget.dataset.id;
//携带新闻id进行页面跳转
var islogin = wx.getStorageSync('islogin')
if (islogin) {
wx.navigateTo({
url: '../detail/detail?id=' + id
})
} else {
wx.showModal({
title: '提示',
content: '你还没有登陆,将跳转至登录界面',
success: (res) => {
if (res.confirm) { //这里是点击了确定以后
wx.switchTab({
url: '../my/my',
})
} else { //这里是点击了取消以后
console.log('用户点击取消')
}
}
})
}
},
onLoad: function (options) {
//获取新闻列表
let list = common.getNewsList()
//更新列表数据
this.setData({
newsList: list,
})
},
})
3.2 个人中心页设计
个人中心页主要包含两个板块,即登录面板和“我的收藏”,登录面板用于显示用户的微信头像和昵称,“我的收藏”用于显示收藏在本地的新闻列表。
个人中心页主要有三个功能:一是获取微信用户信息;二是获取收藏列表;三是浏览收藏的新闻。
编写my.wxml:
<!--pages/my/my.wxml-->
<view class="myLogin">
<block wx:if="{{isLogin}}">
<image class="myIcon" src="{{src}}"></image>
<text class="nickName">{{nickName}}</text>
</block>
<button wx:else open-type="chooseAvatar" bindchooseavatar="onChooseAvatar">
未登录,点击选择头像
</button>
<input wx:if="{{isLogin}}" type="nickname" placeholder="请输入昵称" bindblur="onNicknameBlur" value="{{inputValue}}" />
<button wx:if="{{isLogin}}" bindtap="goLogout">退出登录</button>
</view>
<view class="myFavorites" wx:if="{{isLogin}}">
<view class="shoucang">我的收藏--{{num}}</view>
<view class="news-list">
<view class="list-item" wx:for="{{newsList}}" wx:for-item="news" wx:key="id">
<image src="{{news.poster}}"></image>
<text bindtap="goToDetail" data-id='{{news.id}}'>
{{news.title}}--{{news.add_date}}
</text>
<!-- 添加取消收藏按钮 -->
<button bindtap="onUnfavorite" data-id="{{news.id}}" class="unfavorite-btn" size="mini">取消收藏</button>
</view>
</view>
</view>
编写my.wxss
/* pages/my/my.wxss */
.myLogin {
background-color: #24A0ED;
height: 500rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
}
.myIcon {
width: 200rpx;
height: 200rpx;
border-radius: 50%;
}
.nickName {
color: white;
}
.myFavorites {
padding: 20rpx;
}
.myFavorites .shoucang {
width: 100%;
text-align: center;
color: black;
font-size: large;
}
.news-list {
min-height: 600rpx;
padding: 15rpx;
}
.list-item {
display: flex;
flex-direction: row;
border-bottom: 1rpx solid gray;
position: relative;
}
.list-item image {
width: 230rpx;
height: 150rpx;
margin: 10rpx;
}
.text-container {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
}
.list-item text {
width: 100%;
line-height: 60rpx;
font-size: 10pt;
}
.unfavorite-btn {
flex: 1;
position: absolute;
right: 10rpx;
bottom: 10rpx;
height: 50rpx;
width: 100rpx;
font-size: 10rpx;
background-color: #ff4d4f;
color: white;
border: none;
border-radius: 5rpx;
padding: 5rpx 10rpx;
}
编写my.js:
// pages/my/my.js
Page({
data: {
num: 0,
isLogin: false,
src: '',
nickName: '',
inputValue: ''
},
onChooseAvatar: function (e) {
const { avatarUrl } = e.detail;
this.setData({
src: avatarUrl,
isLogin: true
});
wx.setStorageSync('islogin', true);
this.getMyFavorites();
},
onNicknameBlur: function (e) {
const { value } = e.detail;
this.setData({
nickName: value,
inputValue: '' // 清空输入框
});
},
goLogout() {
wx.showModal({
title: '提示',
content: '您确定要退出登录吗',
success: (res) => {
if (res.confirm) {
console.log('用户点击确定')
wx.setStorageSync('islogin', false)
this.setData({
src: '',
nickName: '',
isLogin: false
})
} else {
console.log('用户点击取消')
}
}
})
},
getMyFavorites: function () {
let info = wx.getStorageInfoSync();
let keys = info.keys;
let num = keys.length - 1;
let myList = [];
for (var i = 0; i < num; i++) {
let obj = wx.getStorageSync(keys[i]);
myList.push(obj);
}
this.setData({
newsList: myList,
num: num
});
},
goToDetail: function (e) {
let id = e.currentTarget.dataset.id;
wx.navigateTo({
url: '../detail/detail?id=' + id,
})
},
onLoad(options) {
},
onShow: function () {
if (this.data.isLogin) {
this.getMyFavorites()
}
},
})
3.3 新闻详情页设计
新闻页是用于给用户浏览新闻全文的,需要用户点击首页的新闻列表,然后在新窗口中打开该页面。新闻页包括新闻标题、新闻图片、新闻正文和新闻日期。
新闻页有两个功能:一是显示对应新闻,二是可以添加/取消新闻收藏。
编写detail.wxml:
<!--pages/detail/detail.wxml-->
<view class="container">
<view class="title">
{{article.title}}
</view>
<view class="poster">
<image src="{{article.poster}}" mode="widthFix"></image>
</view>
<view class="content">
{{article.content}}
</view>
<view class="add_date">
时间:{{article.add_date}}
</view>
<button wx:if="{{isAdd}}" plain bindtap="cancelFavorites">♥已收藏</button>
<button wx:else plain bindtap='addFavorites'>♥点击收藏</button>
</view>
编写detail.wxss
/* pages/detail/detail.wxss */
.container {
padding: 15rpx;
text-align: center;
}
.title {
font-weight: 800;
font-size: 14pt;
line-height: 80rpx;
}
.poster image {
width: 700rpx;
}
.content {
text-align: left;
font-size: 12pt;
line-height: 60rpx;
white-space: pre-wrap; /* 保留换行和缩进 */
}
.add_date {
font-size: 12pt;
text-align: right;
line-height: 30rpx;
margin-right: 25rpx;
margin-top: 20rpx;
margin-bottom: 20rpx;
}
button {
width: 250rpx;
height: 100rpx;
margin: 20rpx auto;
}
编写detail.js:
// pages/detail/detail.js
var common = require('../../utils/common')
Page({
data: {},
onLoad: function (options) {
let id = options.id;
// 检查当前新闻是否在收藏夹中
var article = wx.getStorageSync(id);
if (article != '') {
this.setData({
article: article,
isAdd: true
});
} else {
let result = common.getNewsDetail(id);
if (result.code == '200') {
this.setData({
article: result.news
});
}
}
},
addFavorites: function () {
let article = this.data.article;
wx.setStorageSync(article.id, article);
this.setData({
isAdd: true
});
},
cancelFavorites: function () {
let article = this.data.article;
wx.showModal({
title: '提示',
content: '你确定要取消收藏吗?',
success: (res) => {
if (res.confirm) {
wx.removeStorageSync(article.id);
this.setData({
isAdd: false
});
}
}
});
}
});
四、程序运行结果
(1)首页
(2)首页轮播图效果。
(3)未登录状态下点击任意新闻,弹出提示,点击”确定“跳转我的页面进行登录
(4)点击登录
(5)点击输入框输入昵称
(6)点击新闻跳转至新闻详情页。
(7)新闻详情页下滑至底部,点击按钮进行收藏,收藏的新闻会保留在我的中心页面
(8)再次点击按钮,弹出提示,点击确定可以取消收藏,取消收藏的新闻会在我的中心页面删除
(9)在我的中心页面点击红色按钮,可以直接取消收藏
五、问题总结与体会
- 新增登出功能:
- 添加了一个登出功能,用户点击“退出登录”按钮时,会弹出提示窗确认操作。确认后,用户登出,并将
Storage
中的islogin
设置为false
。
<!--pages/my/my.wxml-->
......
<input wx:if="{{isLogin}}" type="nickname" placeholder="请输入昵称" bindblur="onNicknameBlur" value="{{inputValue}}" />
<button wx:if="{{isLogin}}" bindtap="goLogout">退出登录</button>
// pages/my/my.js
......
goLogout() {
wx.showModal({
title: '提示',
content: '您确定要退出登录吗',
success: (res) => {
if (res.confirm) { //这里是点击了确定以后
console.log('用户点击确定')
wx.setStorageSync('islogin', false)
this.setData({
src: '',
nickName: '',
isLogin: false
})
} else { //这里是点击了取消以后
console.log('用户点击取消')
}
}
})
}
- 修改未登录显示个人收藏:
- 只有在用户登录后,才能查看个人收藏及收藏新闻列表。对“收藏–”的样式进行了修改。
<!--pages/my/my.wxml-->
......
<view class="myFavorites" wx:if="{{isLogin}}">
<view class="shoucang">我的收藏--{{num}}</view>
<view class="news-list">
新闻收藏列表
</view>
</view>
- 限制新闻浏览需登录:
- 新闻详情页面和收藏功能需要用户登录才能使用。如果未登录,跳转至详情界面时会提示用户登录,并提供跳转至登录界面的选项。
// pages/index/index.js
......
goToDetail: function (e) {
//获取携带的data-id数据
let id = e.currentTarget.dataset.id;
//携带新闻id进行页面跳转
var islogin = wx.getStorageSync('islogin')
if (islogin) {
wx.navigateTo({
url: '../detail/detail?id=' + id
})
} else {
wx.showModal({
title: '提示',
content: '你还没有登陆,将跳转至登录界面',
success: (res) => {
if (res.confirm) { //这里是点击了确定以后
wx.switchTab({
url: '../my/my',
})
} else { //这里是点击了取消以后
console.log('用户点击取消')
}
}
})
}
}
- 优化取消收藏功能
- 在我的中心页面可以点击”取消收藏“红色按钮直接取消收藏。
<!--pages/my/my.wxml-->
......
<view class="list-item" wx:for="{{newsList}}" wx:for-item="news" wx:key="id">
<image src="{{news.poster}}"></image>
<text bindtap="goToDetail" data-id='{{news.id}}'>
{{news.title}}--{{news.add_date}}
</text>
<!-- 添加取消收藏按钮 -->
<button bindtap="onUnfavorite" data-id="{{news.id}}" class="unfavorite-btn" size="mini">取消收藏</button>
</view>
- 新增cancelFavorites函数,不管在新闻详情页还是我的中心页,取消收藏的时候都弹出提示,更符合用户使用逻辑。
// pages/my/my.js
......
cancelFavorites: function () {
let article = this.data.article;
wx.showModal({
title: '提示',
content: '你确定要取消收藏吗?',
success: (res) => {
if (res.confirm) {
wx.removeStorageSync(article.id);
this.setData({
isAdd: false
});
}
}
});
}
- 使轮播图自适应图片大小并居中
- 在轮播图中,通过style="height: {{swiperHeight}}px;"适应图片高度大小, 通过circular="true"循环播放轮播图,使用mode="aspectFit"保持图片完整。
<!--pages/index/index.wxml-->
......
<swiper indicator-dots="true" autoplay="true" interval="5000" duration="500" style="height: {{swiperHeight}}px;" circular="true">
<block wx:for="{{swiperImg}}" wx:key='index'>
<swiper-item class="swiper-item">
<image src="{{item.src}}" class="swiper-image" mode="aspectFit" bindload="imageLoad"></image>
</swiper-item>
</block>
</swiper>
- 使新闻文本能够多段显示
- 通过white-space: pre-wrap; 保留原文本的换行和缩进。
/* pages/detail/detail.wxss */
......
.content {
text-align: left;
font-size: 12pt;
line-height: 60rpx;
white-space: pre-wrap; /* 保留换行和缩进 */
}
收获与体会:
- 通过这个项目,我不仅巩固了前端开发的基础知识,还学会了如何在实际项目中应用这些知识。此外,我还掌握了真机预览和调试的技巧,能够更好地发现和解决问题。这次项目让我对小程序开发有了更深的理解和信心。