这是我参与「第四届青训营 」笔记创作活动的的第4天
github上的50projects50days看到不少人推荐,个人在跟着写,借此学习一下html,css,js相关知识,感觉还是学到了不少,这里将跟着案列学到的一些技术分享一下。github项目地址
1 Expanding Cards 拓展卡片
<div class="container">
<div class="panel active" style="background-image: url(https://picsum.photos/500);">
<h3>这是拓展卡片1</h3>
</div>
...
</div>
body还是比较简单的(这里分享一下picsum.photos 获取随机图片,还可设置各种要求,挺方便的),这个项目主要是看css,js方面利用forEach给panel添加了排他事件
const panels = document.querySelectorAll('.panel')
panels.forEach(panel => {
panel.addEventListener('click', () => {
removeClassACtive()
panel.classList.add('active')
})
})
function removeClassACtive() {
panels.forEach(panel => {
panel.classList.remove('active')
})
}
这里的classList之前没怎么接触过,现在写了不少案列,发现还是比较常用的,add(),remove(),toggle()...可以利用自带的api来实现对类名操作
mdn:classList
主要是css方面:
* {
box-sizing: border-box;
}
body {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
margin:0
}
.container {
width: 90vw;
display: flex;
justify-content: center;
align-items: center;
}
.panel {
flex: 0.5;
height: 80vh;
margin: 10px;
position: relative;
border-radius: 50px;
background-repeat: no-repeat;
background-size: cover;
background-position: center;
transition: all 500ms ease-in;
}
.panel.active{
flex:5;
}
.panel h3{
color: #fff;
position: absolute;
bottom: 20px;
left: 10px;
opacity: 0;
}
.panel.active h3{
opacity: 1;
}
首先是这条box-sizing: border-box;就是这些小项目都是vh,vw这种相对宽高,用这种变框盒子比较方便。box-sizing - CSS(层叠样式表) | MDN
body内用了flex布局,display: flex;justify-content: center这两条让内容居中;overflow: hidden让非可视区隐藏;margin:0这主要是和height:100vh配合让主体占据100%高,body的margin是有默认值的且非0,border-box是不包含margin,所以我们要手动清零。
flex 布局的基本概念 - CSS(层叠样式表) | MDN
利用flex: 0.5和.active下flex:5然后排他赋予点击的panel对象active实现拓展卡片的效果。
background-size,background-position规定背景怎么放置的,与之类似的有object-fit,object-position但两者还是有细微差别的。
此外opacity 属性指定了一个元素的不透明度,transition属性指定了元素的过渡效果transition - CSS(层叠样式表) | MDN
2 Progress Steps 步骤器
<div class="container">
<div class="progress-container">
<div class="progress" id="progress">
</div>
<div class="circle active">1</div>
<div class="circle">2</div>
<div class="circle">3</div>
<div class="circle">4</div>
<div class="circle">5</div>
</div>
<button class="btn" id="prev" disabled>上一个</button>
<button class="btn" id="next">下一个</button>
</div>
body内结构还是比较简单明了的
:root {
--line-border-fill: #3498db;
--line-border-empty: #e0e0e0;
}
...
.btn:active {
transform: scale(0.98);
}
.btn:focus {
outline: 0;
}
.btn:disabled {
background-color: var(--line-border-empty);
cursor: not-allowed;
}
css中:root在声明全局CSS变量时比较方便,便于后续对整体风格进行更改 mdn
对文本用到了text-align:center这个属性定义行内内容(例如文字)如何相对它的块父元素对齐,此外布局利用position进行了子绝父相,还有 top: 50%;transform: translateY(-50%);这样的组合来实现居中效果。
最有收获的应该是关于.btn的设置
.btn:active {transform: scale(0.98);}用scale()缩放实现按钮的点击变化效果
.btn:focus { outline: 0;}取消聚焦时轮廓(主要正对键盘tab键切换焦点时)
cursor: not-allowed;常见的按钮禁用效果时的指针样式
const progress = document.getElementById('progress')
const prev = document.getElementById('prev')
const next = document.getElementById('next')
const circles = document.querySelectorAll('.circle')
let currentIdx = 1
next.addEventListener('click', () => {
currentIdx++
if (currentIdx > circles.length) {
currentIdx = circles.length
}
update()
})
prev.addEventListener('click', () => {
currentIdx--
if (currentIdx < 1) {
currentIdx = 1
}
update()
})
function update() {
circles.forEach((circle, idx) => {
if (idx < currentIdx) {
circle.classList.add('active')
} else {
circle.classList.remove('active')
}
})
const actives = document.querySelectorAll('.active')
progress.style.width = (actives.length - 1) / (circles.length - 1) * 100 + '%'
if (currentIdx === 1) {
prev.disabled = true
} else if (currentIdx === circles.length) {
next.disabled = true
} else {
prev.disabled = false
next.disabled = false
}
}
用个标记currentIdx来存储位置序号,给按钮绑定点击事件来改变currentIdx,每次改变都调用更新函数,更新根据currentIdx遍历每个circles,判断是否应处于active,然后根据获取的.active的长度占比决定中间直线长度,最后处理按钮在到达边界时状态。这个项目就完成了。