在现代的前端开发中,组件封装成为了一项重要而强大的技术。无论是在大型应用程序还是小型项目中,良好的组件封装都能够为我们带来诸多好处。让我们一起探讨一下组件封装的优势及案例实现。
一、组件封装优势
组件封装可以大大提高代码的复用性。通过将具有相似功能或模式的代码抽象出来并封装成组件,我们可以在不同的地方重复使用它们,而无需重复编写相同的代码。这不仅减少了开发时间,还减少了出错的机会。例如,一个通用的按钮组件可以在应用的各个地方使用,而不需要每次都重新创建一个新的按钮。
组件封装可以提升代码的可维护性。通过将功能模块化并隐藏实现细节,我们可以降低代码的耦合度,使其更易于理解和维护。当我们需要对某个功能进行修改或修复时,只需关注特定的组件,而不需要担心对其他部分产生意外的影响。这种模块化的设计使得团队合作更加高效,每个人都可以专注于自己负责的组件。
二、案例实现
以下是相关的组件案例实现:
1.分页器
<template>
<div class="pagination">
<!-- 当当前页为1时,禁用按钮 -->
<button :disabled="pageNo == 1" @click="$emit('getPage',pageNo-1)" >上一页</button>
<!-- 当连续页的开始大于1时,显示按钮 -->
<button v-if="startAndEnd.start > 1" @click="$emit('getPage',1)" :class="{'active':pageNo==1}">1</button>
<button v-if="startAndEnd.start > 2">···</button>
<!-- 遍历页数(数字),中间显示的数字页数号 -->
<template v-for="(page,index) in startAndEnd.end" >
<button v-if="page >= startAndEnd.start" :key="index" @click="$emit('getPage',page)" :class="{'active':pageNo==page}">{{page}}</button>
</template>
<button v-if="startAndEnd.end < totalPage - 2">···</button>
<!-- 当连续页的结尾小于总页数时,显示按钮 -->
<button v-if="startAndEnd.end < totalPage" @click="$emit('getPage',totalPage)" :class="{'active':pageNo==totalPage}">{{totalPage}}</button>
<!-- 当当前页为总页数时,禁用按钮 -->
<button :disabled="pageNo == totalPage" @click="$emit('getPage',pageNo+1)">下一页</button>
<button style="margin-left: 30px">共 {{total}} 条</button>
</div>
</template>
<script>
export default {
name: "Pagination",
props:['pageNo','total','continues','pageSize'],
computed:{
//总页数
totalPage(){
return Math.ceil(this.total/this.pageSize)
},
//连续页数中的起始页和终止页
startAndEnd(){
let start = 0 ,end = 0
let {pageNo,continues,totalPage} = this
if(continues > this.totalPage){
start = 1
end = totalPage
}else{
start = pageNo - parseInt(continues/2)
end = pageNo + parseInt(continues/2)
}
//得出的起始页和结束页在进行判断
if(start < 1){
start = 1
end = continues
}else if(end > totalPage){
end = totalPage
start = pageNo - continues + 1
}
return {start,end}
}
}
}
</script>
<style lang="less" scoped>
.pagination {
text-align: center;
button {
margin: 0 5px;
background-color: #f4f4f5;
color: #606266;
outline: none;
border-radius: 2px;
padding: 0 4px;
vertical-align: top;
display: inline-block;
font-size: 13px;
min-width: 35.5px;
height: 28px;
line-height: 28px;
cursor: pointer;
box-sizing: border-box;
text-align: center;
border: 0;
&[disabled] {
color: #c0c4cc;
cursor: not-allowed;
}
&.active {
cursor: not-allowed;
background-color: #409eff;
color: #fff;
}
}
}
</style>
效果演示:
2.弹框
<template>
<div>
<button @click="openModal">Open Modal</button>
<!-- 通过showModel来控制弹框是否显示 -->
<div v-if="showModal" class="modal">
<div class="modal-content">
<span class="close" @click="closeModal">×</span>
<h2>{{ title }}</h2>
<p>{{ message }}</p>
<button @click="cancer">取消</button>
<button @click="save">完成</button>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
showModal: false,
title: "弹框标题",
message: "弹框内容"
};
},
methods: {
openModal() {
this.showModal = true;
},
closeModal() {
this.showModal = false;
},
cancer(){
this.showModal = false;
},
save(){
//实现完成后的逻辑功能,例如:跳转页面等
}
}
};
</script>
<style>
/* 遮罩层样式 */
.modal {
display: flex;
justify-content: center;
align-items: center;
position: fixed;
z-index: 9999;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
}
.modal-content {
background-color: #fff;
padding: 20px;
border-radius: 5px;
max-width: 400px;
width: 90%;
text-align: center;
}
.close {
float: right;
font-size: 20px;
font-weight: bold;
cursor: pointer;
}
button {
margin: 10px;
padding: 10px 20px;
background-color: #409eff;
color: #fff;
border: none;
border-radius: 5px;
cursor: pointer;
}
</style>
效果演示:
3.日历
<template>
<div>
<div class="header">
<!-- 点击按钮:年份减一 -->
<button @click="prevYear"><<</button>
<!-- 点击按钮:月份减一 -->
<button @click="prevMonth" :disabled="isDisabled"><</button>
<h2>{{ currentMonth }}</h2>
<button @click="nextMonth">></button>
<button @click="nextYear">>></button>
</div>
<table>
<thead>
<!-- 星期* -->
<tr>
<th v-for="day in daysOfWeek" :key="day">{{ day }}</th>
</tr>
</thead>
<tbody>
<!-- 日期* -->
<tr v-for="(week,index) in calendar" :key="index">
<!-- 'current-day': isCurrentDay(day), 再开始页面的当前时间高亮 -->
<td v-for="day in week" :key="day.date" :class="{ 'selected-day': isSelectedDay(day) }" @click="selectDay(day)">
{{ day.date }}
</td>
</tr>
</tbody>
</table>
<div>当前时间为:{{showDate}}</div>
</div>
</template>
<script>
export default {
data() {
return {
currentDate: new Date(),
daysOfWeek: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
calendar: [],
showDate:'',
isDisabled:false
};
},
computed: {
//将当前日历转换格式
currentMonth() {
return this.currentDate.toLocaleString('default', { month: 'long', year: 'numeric' });
}
},
mounted() {
this.renderCalendar();
},
methods: {
//获取当月的日历表
renderCalendar() {
const firstDayOfMonth = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth(), 1);
const lastDayOfMonth = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth() + 1, 0);
const weeks = [];
let currentWeek = [];
let currentDate = new Date(firstDayOfMonth);
while (currentDate <= lastDayOfMonth) {
currentWeek.push({
date: currentDate.getDate(),
month: currentDate.getMonth(),
year: currentDate.getFullYear()
});
//若当前日期为星期六,则将数组添加进新数组中
if (currentDate.getDay() === 6) {
weeks.push(currentWeek);
currentWeek = [];
}
currentDate.setDate(currentDate.getDate() + 1);
}
if (currentWeek.length > 0) {
weeks.push(currentWeek);
}
this.calendar = weeks;
},
prevMonth() {
if(this.currentDate.getMonth() < 1){
this.isDisabled == true
}else{
this.currentDate = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth() - 1, 1);
this.renderCalendar();
}
},
prevYear(){
console.log(11);
this.currentDate = new Date(this.currentDate.getFullYear() - 1, this.currentDate.getMonth(), 1);
this.renderCalendar();
},
nextMonth() {
if(this.currentDate.getMonth() > 12){
this.disabled == true
}else{
this.currentDate = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth() + 1, 1);
this.renderCalendar();
}
},
nextYear(){
this.currentDate = new Date(this.currentDate.getFullYear() + 1, this.currentDate.getMonth(), 1);
this.renderCalendar();
},
//是当天日期高亮(获得样式)
isCurrentDay(day) {
const today = new Date();
return day.date === today.getDate() && day.month === today.getMonth() && day.year === today.getFullYear();
},
isSelectedDay(day) {
return false;
},
//显示当前点击日期
selectDay(day) {
this.showDate = day.year + '年' + day.month +'月' + day.date + '日';
}
}
};
</script>
<style>
table {
width: 100%;
border-collapse: collapse;
}
th,
td {
padding: 10px;
text-align: center;
}
th {
background-color: #f2f2f2;
}
td {
border: 1px solid #ccc;
}
td:hover {
background-color: #f2f2f2;
cursor: pointer;
}
.current-day {
background-color: #e6e6e6;
}
.selected-day {
background-color: #409eff;
color: #fff;
}
.header {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 10px;
}
.header button {
background-color: transparent;
border: none;
cursor: pointer;
color: palevioletred;
font-size: 22px;
padding: 5px 10px;
}
</style>
效果演示:
三、总结
综上所述,组件封装是现代前端开发中不可或缺的一环。它通过提高代码复用性、维护性和可测试性,为我们带来了诸多好处。无论是在个人项目中还是大型团队开发中,合理地封装组件都能够提高开发效率和代码质量。让我们拥抱组件封装,打造更优秀的前端应用!