(新手友好)前端实践:JavaScript在项目中的应用
JavaScript在前端开发里主要起到的作用就是用来实现一些用户与网页的交互效果。
在这篇文章里,笔者将通过一个完整的项目实例expanding cards来展示JavaScript在这里面起到的交互作用。
(PS:这个项目是笔者在github 找到的,感兴趣的可以点进去看看)
0.项目介绍
这个项目是非常适合新手入门的,它的技术栈完全就是三剑客组合(HTML+CSS+JavaScript),也没有用到前端框架等等其他的东西,非常容易掌握。
首先先来看一下这个项目的效果(笔者做了一些小改动):
我们用户通过点击每张卡片,每张卡片就会伸长开来,并且动态显示文字。
笔者先放一下它的源代码,ps笔者已经在这个代码里做了一些中文注释,方便新手食用。
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="p2.css" />
<title>Expanding Cards</title>
</head>
<body>
<div class="container">
<div class="panel active" style="background-image: url('https://images.unsplash.com/photo-1558979158-65a1eaa08691?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80')">
<h3>Explore The World</h3>
</div>
<div class="panel" style="background-image: url('https://images.unsplash.com/photo-1572276596237-5db2c3e16c5d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80')">
<h3>Wild Forest</h3>
</div>
<div class="panel" style="background-image: url('https://images.unsplash.com/photo-1507525428034-b723cf961d3e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1353&q=80')">
<h3>Sunny Beach</h3>
</div>
<div class="panel" style="background-image: url('https://images.unsplash.com/photo-1551009175-8a68da93d5f9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1351&q=80')">
<h3>City on Winter</h3>
</div>
<div class="panel" style="background-image: url('https://images.unsplash.com/photo-1549880338-65ddcdfd017b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80')">
<h3>Mountains - Clouds</h3>
</div>
<!-- 这个是笔者自己加的-->
<!-- <div class="panel" style="background-image: url('img.jpg')">-->
<!-- <h3>Sunlight</h3>-->
<!-- </div>-->
</div>
<script src="p2.js"></script>
</body>
</html>
/* 引入了一个google字体库的字体Muli,让网页可以使用这个字体,也不用看用户自己有没有安装这个字体*/
@import url('https://fonts.googleapis.com/css?family=Muli&display=swap');/*display=swap 这意味着如果字体文件下载失败,浏览器会使用一个默认的字体来替代,以保证网页的可读性*/
*{
box-sizing: border-box;
}
body {
font-family: 'Muli', sans-serif;
display: flex;
align-items: center;
justify-content: center;
height: 100vh; /*整个网页的高度将被设置为浏览器窗口高度的 100%*/
overflow:hidden;
margin: 0;
}
.container{
display:flex; /*让盒子可以呈横向排布*/
width:90vw; /*表示元素的宽度将占据整个视口宽度的90%。*/
}
.panel{
background-size:cover;/*让背景图整个呈现在容器里,也就是对图片进行缩放*/
backgroud-position:center;
background-repeat: no-repeat;
height: 80vh;
border-radius: 50px;
color:lightpink;
cursor:pointer; /*鼠标滑过panel时变成手型*/
/*这在创建具有响应式和交互式设计的网页时非常有用*/
flex:0.5;
/*设置弹性容器中项目的伸缩性.flex:0.5 表示每个.panel 元素的宽度将占据容器宽度的 50%*/
margin:10px; /*设置元素的外边距为10像素*/
position:relative;
-webkit-transition: flex 0.7s ease-in; /*设置过渡效果:体现为图片移动花的时间。*/
}
/* ease-in:CSS的一种过渡时间函数。CSS 还提供了其他几种过渡时间函数,如 ease-out、ease-in-out、linear 等。*/
.panel h3{
font-size:24px;
position:absolute;
bottom: 10px;
left: 20px;
margin: 0;
opacity: 0;
/*设置元素的不透明度为0,就是字体完全透明。opacity默认值为1,也就是完全不透明*/
}
.panel.active{
flex:5;
}
.panel.active h3{
opacity: 1;
/*设置过渡效果:0.3s表示过渡持续时间,0.4s表示过渡延迟时间,也就是元素收到改变0.4s后开始展示过渡效果。而延迟时间默认值为0*/
/*体现为字体“蹦出来”花的时间,和什么时候蹦出来*/
/*过渡开始时速度较慢,然后逐渐加快*/
transition:opacity 0.3s ease-in 0.4s;
/*ease-out:过渡开始时速度较快,然后逐渐减慢*/
/*transition: opacity 0.3s ease-out;*/
/*ease-in-out:过渡开始和结束时速度较快,中间速度较慢*/
/*transition: opacity 0.3s ease-in-out;*/
/*linear:过渡速度均匀*/
/*transition: opacity 0.3s linear;*/
/*step-start:tep-start 和 step-end:过渡以离散的步骤进行。也就是过渡在每个时间点都有一个固定的速度*/
/*transition: opacity 0.3s step-start;*/
}
@media (max-width: 480px) {
.container {
width: 100vw;
}
.panel:nth-of-type(4),
.panel:nth-of-type(5) {
display: none;
}
}
/*响应式设计
允许网页根据不同的设备屏幕尺寸调整布局和样式*/
const panels = document.querySelectorAll('.panel')
panels.forEach(panel => {
panel.addEventListener('click', () => {
removeActiveClasses()//移除其他的panel元素的active类
panel.classList.add('active') //给选中的panel添加active类
// 这样子操作就可以导致只有一个panel元素处于active状态,其他元素就不会。
})
})
function removeActiveClasses() {
panels.forEach(panel => {
panel.classList.remove('active')
})
// 这个函数通常用于在用户点击某个 panel 元素时,将之前被激活的 panel 元素的 active 类移除,以确保只有当前点击的 panel 元素处于激活状态。
}
1.JavaScript在这个项目里起到的作用
这个项目的交互功能主要体现在:用户点击使得卡片伸展和收缩,并且显示文字或者文字消失。
在CSS里,我们分别构建图片在没被用户点到的时候(不是active状态)的效果(.panel选择器)、图片被点击时(active状态)的效果(.panel.active选择器)、没被点击时文字的效果(.panel h3选择器)、被点击时文字的效果(.panel.active h3选择器)。
而JavaScript在这个项目里要做的事情就是:通过函数去调用不同状态下的选择器,让图片和文字产生不一样的渲染效果。
2.对JS代码的分析
根据上面放出来的JS部分代码,我们可以看到这个JS代码的编写逻辑是:
- 首先是定义了一个
panels变量,它是一个包含所有.panel元素的NodeList对象。 - 然后使用
forEach方法遍历panels,为每个.panel元素添加一个点击事件监听器:也就是,每一张图片都会被绑定一个点击类型的事件监听器,每一张图片都可以在被点击时和没被点击时作出相应的响应。 - 自定义一个
removeActiveClasses函数,用于移除所有.panel元素的active类:这个函数的作用主要是在用户点击某张图片时,让其他没有被点击的图片们移除它们的active状态,呈现出缩小的视觉样式,文字消失。而只有当前点击的.panel元素(图片)处于激活状态,呈现出伸展的视觉样式,并且相应的文字会出现。
比如说,在这个代码块里:
panels.forEach(panel => {
panel.addEventListener('click', () => {
removeActiveClasses()//移除其他的panel元素的active类
panel.classList.add('active') //给选中的panel添加active类
// 这样子操作就可以导致只有一个panel元素处于active状态,其他元素就不会。
})
})
如果笔者注释掉removeActiveClasses(),就会发现,虽然所有的图片都可以被点击处于激活状态,但是它们的激活状态在无法移除,图片无法被收缩,文字也无法消失。最后呈现这样的状态:
如果笔者注释掉panel.classList.add('active'),就会发现,除了图片们都无法被激活(就是无法被点击了),最后呈现这样的状态:
function removeActiveClasses() {
panels.forEach(panel => {
panel.classList.remove('active')
})
}
而在这个代码块里,我们自定义了一个removeActiveClasses函数,并且对每一个panel元素都进行遍历,这样子做的目的是为了可以让所有的panel元素都能够移除它们的active类。
3.JavaScript的编写原则
根据青训营上课的内容,JavaScript的编写应该遵循这下面三个原则:
- 各司其职--结构表现行为分离:也就是遵循HTML负责结构,CSS负责表现,JavaScript负责行为。比如在这个项目里,我们分别设立了3个文件(HTML+CSS+JS)去管理这个项目。
- 高内聚低耦合--组件封装:组件可以有函数组件和类组件。比如,我们使用了函数组件去实现这个项目。在这个函数组件里,我们分别定义了一个
panels变量,一个removeActiveClasses函数,一个forEach方法。 - 过程抽象:也就是使用一些函数去实现过程。比如,在这个项目里,我们使用了
forEach方法去遍历每一个panel元素,并且为每一个panel元素添加了一个点击事件监听器。
4.总结
总的来说,JavaScript负责的都是一些交互效果,这个例子里面的JavaScript比较基础,它定义的函数也比较少。而在一些交互行为比较多的项目里,JS的编写会更加复杂。这个项目真的非常适合新手尝试。