基于50projects50days的复习(一)| 青训营笔记

330 阅读3分钟

这是我参与「第四届青训营 」笔记创作活动的的第4天

github上的50projects50days看到不少人推荐,个人在跟着写,借此学习一下html,css,js相关知识,感觉还是学到了不少,这里将跟着案列学到的一些技术分享一下。github项目地址

1 Expanding Cards 拓展卡片

127.0.0.1_5501_50_1%E6%8B%93%E5%B1%95%E5%8D%A1%E7%89%87_index.html.png

    <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 步骤器

127.0.0.1_5501_50_2%E6%AD%A5%E9%AA%A4%E5%99%A8_index.html.png

    <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的长度占比决定中间直线长度,最后处理按钮在到达边界时状态。这个项目就完成了。