效果图
博客教程:使用Vue.js实现投票排行榜页面(详细步骤)
在本篇博客教程中,我们将逐步带你实现一个投票排行榜页面,使用的是Vue.js框架。此项目适合前端开发新手,可以帮助你更好地理解Vue的基本功能和组件开发。
目录
项目介绍
我们将创建一个简单的投票排行榜页面。这个页面会展示艺人/团体的投票信息、投票截止时间、投票按钮等功能。我们还会增加倒计时功能,实时显示距离投票结束的时间。
你将学会如何:
- 创建排行榜并根据票数排序
- 实现简单的投票功能
- 实现倒计时功能
- 使用Vue.js的计算属性和生命周期方法
搭建项目基础结构
首先,我们需要定义HTML页面的基本结构和样式。创建一个基础的Vue.js应用,并编写简单的HTML和CSS来展示内容。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>投票排行榜 - Vue.js 实现</title>
<script src="https://cdn.staticfile.net/vue/2.7.0/vue.min.js"></script>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #fff;
color: #333;
text-align: center;
}
#app {
max-width: 500px;
margin: 0 auto;
padding: 20px;
background-color: #f2f2f2;
}
.title {
font-size: 24px;
font-weight: bold;
color: #fff;
padding: 10px;
background-color: #ff3b3b;
margin-bottom: 20px;
}
.leaderboard {
display: flex;
justify-content: space-around;
margin-bottom: 20px;
}
.leaderboard div {
width: 80px;
height: 80px;
background-color: #ddd;
border-radius: 50%;
margin-bottom: 5px;
}
.leaderboard p {
font-size: 16px;
font-weight: bold;
color: #ff3b3b;
}
.countdown {
margin: 20px 0;
font-size: 16px;
color: #555;
}
.ranking-list {
background-color: #fff;
border-radius: 10px;
padding: 10px;
margin-bottom: 20px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
.ranking-item {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
padding: 10px 5px;
border-bottom: 1px solid #eee;
}
.ranking-item:last-child {
border-bottom: none;
}
.ranking-item div {
display: flex;
align-items: center;
}
.ranking-item div .avatar {
width: 50px;
height: 50px;
background-color: #ddd;
border-radius: 50%;
margin-right: 10px;
}
.ranking-item div span {
font-size: 18px;
font-weight: bold;
color: #333;
}
.ranking-item button {
background-color: #ff3b3b;
border: none;
color: white;
padding: 5px 10px;
border-radius: 5px;
cursor: pointer;
transition: transform 0.2s ease;
}
.ranking-item button:hover {
background-color: #d73232;
}
.ranking-item button:active {
transform: scale(0.95);
}
.tabs {
display: flex;
justify-content: space-around;
margin-top: 20px;
}
.tabs button {
padding: 10px;
border: none;
background-color: #ff3b3b;
color: white;
border-radius: 5px;
cursor: pointer;
}
.tabs button:hover {
background-color: #d73232;
}
</style>
</head>
<body>
<div id="app">
<div class="title">投票排行榜</div>
实现榜单前3名展示
我们需要显示榜单前三名的艺人,并为他们提供简单的样式(如圆形头像)。在Vue的数据模型中定义艺人及其票数,并通过计算属性来排序和展示前三名艺人。
<div class="leaderboard">
<div v-for="(artist, index) in topThree" :key="index">
<p>{{ artist.name }}</p>
<p>{{ artist.votes }}票</p>
</div>
</div>
实现倒计时功能
我们将使用mounted
生命周期函数在组件加载时启动倒计时,并使用setInterval
每秒更新倒计时数据。
<div class="countdown">
距离投票结束还有: {{ daysLeft }} 天 {{ hoursLeft }} 小时 {{ minutesLeft }} 分钟
</div>
在Vue实例中,编写逻辑代码来计算并显示倒计时。
mounted() {
this.updateCountdown();
},
methods: {
updateCountdown() {
const endTime = new Date().getTime() + this.countdown;
this.timer = setInterval(() => {
const now = new Date().getTime();
const distance = endTime - now;
this.daysLeft = Math.floor(distance / (1000 * 60 * 60 * 24));
this.hoursLeft = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
this.minutesLeft = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
if (distance < 0) {
clearInterval(this.timer);
}
}, 1000);
}
}
实现投票功能
在每个艺人的信息下方添加一个“投票”按钮,并在点击时增加对应艺人的票数。
<div class="ranking-list">
<div v-for="(artist, index) in remainingArtists" :key="index" class="ranking-item">
<div>
<div class="avatar"></div>
<span>{{ artist.name }}</span>
</div>
<div>
<span>{{ artist.votes }}票</span>
<button @click="vote(index)">投票</button>
</div>
</div>
</div>
剩余艺人展示与排序
我们将通过计算属性remainingArtists
来筛选和展示剩余的艺人,并实现实时排序。
computed: {
topThree() {
return this.artists.slice(0, 3);
},
remainingArtists() {
return this.artists.slice(3);
}
},
methods: {
vote(index) {
this.artists[index + 3].votes += 1;
}
}
底部导航与样式优化
添加底部导航按钮,并且实现简单的页面切换效果。
<div class="tabs">
<button>活动投票</button>
<button>排名统计</button>
<button>活动说明</button>
</div>
总结与完整代码
通过这篇教程,我们学习了如何使用Vue.js实现一个投票排行榜页面。我们使用了Vue的计算属性、mounted
生命周期方法以及setInterval
函数实现了动态更新和实时投票的功能。
完整代码:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>投票排行榜 - Vue.js 实现</title>
<script src="https://cdn.staticfile.net/vue/2.7.0/vue.min.js"></script>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #fff;
color: #333;
text-align: center;
}
#app {
max-width: 500px;
margin: 0 auto;
padding: 20px;
background-color: #f2f2f2;
}
.title {
font-size: 24px;
font-weight: bold;
color: #fff;
padding: 10px;
background-color: #ff3b3b;
margin-bottom: 20px;
}
.leaderboard {
display: flex;
justify-content: space-around;
margin-bottom: 20px;
}
.leaderboard div {
width: 80px;
height: 80px;
background-color: #ddd;
border-radius: 50%;
margin-bottom: 5px;
}
.leaderboard p {
font-size: 16px;
font-weight: bold;
color: #ff3b3b;
}
.countdown {
margin: 20px 0;
font-size: 16px;
color: #555;
}
.ranking-list {
background-color: #fff;
border-radius: 10px;
padding: 10px;
margin-bottom: 20px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
.ranking-item {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
padding: 10px 5px;
border-bottom: 1px solid #eee;
}
.ranking-item:last-child {
border-bottom: none;
}
.ranking-item div {
display: flex;
align-items: center;
}
.ranking-item div .avatar {
width: 50px;
height: 50px;
background-color: #ddd;
border-radius: 50%;
margin-right: 10px;
}
.ranking-item div span {
font-size: 18px;
font-weight: bold;
color: #333;
}
.ranking-item button {
background-color: #ff3b3b;
border: none;
color: white;
padding: 5px 10px;
border-radius: 5px;
cursor: pointer;
transition: transform 0.2s ease;
}
.ranking-item button:hover {
background-color: #d73232;
}
.ranking-item button:active {
transform: scale(0.95);
}
.tabs {
display: flex;
justify-content: space-around;
margin-top: 20px;
}
.tabs button {
padding: 10px;
border: none;
background-color: #ff3b3b;
color: white;
border-radius: 5px;
cursor: pointer;
}
.tabs button:hover {
background-color: #d73232;
}
</style>
</head>
<body>
<div id="app">
<div class="title">投票排行榜</div>
<!-- 榜单前三展示 -->
<div class="leaderboard">
<div v-for="(artist, index) in topThree" :key="index">
<p>{{ artist.name }}</p>
<p>{{ artist.votes }}票</p>
</div>
</div>
<!-- 倒计时 -->
<div class="countdown">
距离投票结束还有: {{ daysLeft }} 天 {{ hoursLeft }} 小时 {{ minutesLeft }} 分钟
</div>
<!-- 排名列表 -->
<div class="ranking-list">
<div v-for="(artist, index) in remainingArtists" :key="index" class="ranking-item">
<div>
<div class="avatar"></div>
<span>{{ artist.name }}</span>
</div>
<div>
<span>{{ artist.votes }}票</span>
<button @click="vote(index)">投票</button>
</div>
</div>
</div>
<!-- 底部导航 -->
<div class="tabs">
<button>活动投票</button>
<button>排名统计</button>
<button>活动说明</button>
</div>
</div>
<script>
new Vue({
el: '#app',
data: {
countdown: 5 * 24 * 60 * 60 * 1000, // 5天的倒计时
artists: [
{ name: '黄飞燕', votes: 9690 },
{ name: '张彬彬', votes: 8690 },
{ name: '刘丹妮', votes: 8655 },
{ name: 'A12号 西建科', votes: 12350 },
{ name: 'A09号 孙萌萌', votes: 12089 },
{ name: 'A09号 司马学', votes: 12001 },
{ name: 'A06号 王珊珊', votes: 11984 },
{ name: 'A02号 何华康', votes: 11980 },
{ name: 'A08号 赵小菜', votes: 11978 }
],
timer: null,
daysLeft: 0,
hoursLeft: 0,
minutesLeft: 0
},
computed: {
topThree() {
return this.artists.slice(0, 3);
},
remainingArtists() {
return this.artists.slice(3);
}
},
methods: {
vote(index) {
this.artists[index + 3].votes += 1;
},
updateCountdown() {
const endTime = new Date().getTime() + this.countdown;
this.timer = setInterval(() => {
const now = new Date().getTime();
const distance = endTime - now;
this.daysLeft = Math.floor(distance / (1000 * 60 * 60 * 24));
this.hoursLeft = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
this.minutesLeft = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
if (distance < 0) {
clearInterval(this.timer);
}
}, 1000);
}
},
mounted() {
this.updateCountdown();
}
});
</script>
</body>
</html>
标签:ranking,Vue,color,border,js,60,排行榜,background,margin From: https://blog.csdn.net/qq_22182989/article/details/143175740