5个前端练手项目(html css js canvas)

01月10日 收藏 0 评论 1 前端开发

5个前端练手项目(html css js canvas)

转载声明:文章来源:https://blog.csdn.net/m0_51311990/article/details/125117079

一、跑马灯

1.1效果图:

1.2思路解析

在这个项目中,在html中创立20个span标签

每个span标签设置style为--i:数字的样式用于在css中动态分配圆圈分几份,transform: rotate(calc(18deg*var(--i)))

利用filter属性结合关键帧动态切换颜色。同时设置每一个span标签进行旋转

1.3源码

<style>
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
main{
display: flex;
background-color: #2c3a47;
/*用于设置图像居中 */
align-items: center;
justify-content: center;
width: 1920px;
height: 1000px;
animation: animate1 10s linear infinite;
}
/* 用于设置动画属性 其中filter用于做利镜其中的hue-rotate属性让图像运用色相旋转*/
@keyframes animate1 {
0% {
filter: hue-rotate(0deg);
}
100% {
filter: hue-rotate(360deg);
}
}
main .cube {
position: relative;
height: 120px;
width: 120px;
}
main .cube span {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
/* 用于设置一个圆圈被分成几份 */
transform: rotate(calc(18deg*var(--i)));
}
/* :before用于设置在给定的属性之前添加效果 */
main .cube span::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 15px;
height: 15px;
border-radius: 50%;
background-color: aqua;
box-shadow: 0 0 10px aqua ,0 0 20px aqua,0 0 40px aqua,0 0 80px aqua,0 0 100px aqua;
animation: animate 2s linear infinite;
animation-delay: calc(0.1s*var(--i));
}
@keyframes animate {
0% {
transform: scale(1);
}
80%,
100% {
transform: scale(0);
}
}
.loading{
color:#fff;
font-size: 20px;
position: relative;
top:100px;
right:100px;
}
@media (min-width:765px){

}

</style>
</head>
<body>
<main>
<div class="cube">
<span style="--i:1;"></span>
<span style="--i:2;"></span>
<span style="--i:3;"></span>
<span style="--i:4;"></span>
<span style="--i:5;"></span>
<span style="--i:6;"></span>
<span style="--i:7;"></span>
<span style="--i:8;"></span>
<span style="--i:9;"></span>
<span style="--i:10;"></span>
<span style="--i:11;"></span>
<span style="--i:12;"></span>
<span style="--i:13;"></span>
<span style="--i:14;"></span>
<span style="--i:15;"></span>
<span style="--i:16;"></span>
<span style="--i:17;"></span>
<span style="--i:18;"></span>
<span style="--i:19;"></span>
<span style="--i:20;"></span>
</div>
<div class="loading">
<p>loading</p>
</div>
</main>
</body>

二、彩虹爱心

2.1效果图

2.2思路解析

搭建基本的html结构,采用的svg技术

通过js动态改变颜色,以及动态实现切换图形

2.3源码

<svg id="hearts" viewBox="-600 -400 1200 800" preserveAspectRatio="xMidYMid slice">

<defs>

<symbol id="heart" viewBox="-69 -16 138 138">

<path d="M0,12
C 50,-30 110,50 0,120
C-110,50 -50,-30 0,12z"/>

</symbol>

</defs>

</svg>


const colors = ["#e03776","#8f3e98","#4687bf","#3bab6f","#f9c25e","#f47274"];
const SVG_NS = 'http://www.w3.org/2000/svg';
const SVG_XLINK = "http://www.w3.org/1999/xlink";

let heartsRy = []

function useTheHeart(n){
let use = document.createElementNS(SVG_NS, 'use');
use.n = n;
use.setAttributeNS(SVG_XLINK, 'xlink:href', '#heart');
use.setAttributeNS(null, 'transform', `scale(${use.n})`);
use.setAttributeNS(null, 'fill', colors[n%colors.length]);
use.setAttributeNS(null, 'x', -69);
use.setAttributeNS(null, 'y', -69);
use.setAttributeNS(null, 'width', 138);
use.setAttributeNS(null, 'height', 138);

heartsRy.push(use)
hearts.appendChild(use);
}

for(let n = 18; n >= 0; n--){useTheHeart(n)}

function Frame(){
window.requestAnimationFrame(Frame);
for(let i = 0; i < heartsRy.length; i++){
if(heartsRy[i].n < 18){heartsRy[i].n +=.01
}else{
heartsRy[i].n = 0;
hearts.appendChild(heartsRy[i])
}
heartsRy[i].setAttributeNS(null, 'transform', `scale(${heartsRy[i].n})`);
}
}

Frame()

三、闹钟 

3.1效果图

3.2思路解析

搭建基本的html结构,动态得到实时的时,分,秒

通过Date()函数获得。将得到的数字根据逻辑,绑定给各div结构,实行动态旋转。点击按钮,改变背景颜色

3.3源码

html:

<body>
<button class="toggle">Dark mode</button>
<div class="clock-container">
<div class="clock">
<div class="needle hour"></div>
<div class="needle minute"></div>
<div class="needle second"></div>
<div class="center-point"></div>
</div>
<div class="time"></div>
<div class="date"></div>
</div>
</body>

css:

@import url('https://fonts.googleapis.com/css?family=Heebo:300&display=swap');

* {
box-sizing: border-box;
}

:root {
--primary-color: #000;
--secondary-color: #fff;
}

html {
transition: all 0.5s ease-in;
}

html.dark {
--primary-color: #fff;
--secondary-color: #333;
}

html.dark {
background-color: #111;
color: var(--primary-color);
}

body {
font-family: 'Heebo', sans-serif;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
overflow: hidden;
margin: 0;
}

.toggle {
cursor: pointer;
background-color: var(--primary-color);
color: var(--secondary-color);
border: 0;
border-radius: 4px;
padding: 8px 12px;
position: absolute;
top: 100px;
}

.toggle:focus {
outline: none;
}

.clock-container {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
}

.clock {
position: relative;
width: 200px;
height: 200px;
}

.needle {
background-color: var(--primary-color);
position: absolute;
top: 50%;
left: 50%;
height: 65px;
width: 3px;
transform-origin: bottom center;
transition: all 0.5s ease-in;
}

.needle.hour {
transform: translate(-50%, -100%) rotate(0deg);
}

.needle.minute {
transform: translate(-50%, -100%) rotate(0deg);
height: 100px;
}

.needle.second {
transform: translate(-50%, -100%) rotate(0deg);
height: 100px;
background-color: #e74c3c;
}

.center-point {
background-color: #e74c3c;
width: 10px;
height: 10px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 50%;
}

.center-point::after {
content: '';
background-color: var(--primary-color);
width: 5px;
height: 5px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 50%;
}

.time {
font-size: 60px;
}

.date {
color: #aaa;
font-size: 14px;
letter-spacing: 0.3px;
text-transform: uppercase;
}

.date .circle {
background-color: var(--primary-color);
color: var(--secondary-color);
border-radius: 50%;
height: 18px;
width: 18px;
display: inline-flex;
align-items: center;
justify-content: center;
line-height: 18px;
transition: all 0.5s ease-in;
font-size: 12px;
}

js:

const hourEl = document.querySelector('.hour')
const minuteEl = document.querySelector('.minute')
const secondEl = document.querySelector('.second')
const timeEl = document.querySelector('.time')
const dateEl = document.querySelector('.date')
const toggle = document.querySelector('.toggle')

const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

toggle.addEventListener('click', (e) => {
const html = document.querySelector('html')
if (html.classList.contains('dark')) {
html.classList.remove('dark')
e.target.innerHTML = 'Dark mode'
} else {
html.classList.add('dark')
e.target.innerHTML = 'Light mode'
}
})

function setTime() {
const time = new Date();
const month = time.getMonth()
const day = time.getDay()
const date = time.getDate()
const hours = time.getHours()
const hoursForClock = hours >= 13 ? hours % 12 : hours;
const minutes = time.getMinutes()
const seconds = time.getSeconds()
const ampm = hours >= 12 ? 'PM' : 'AM'

hourEl.style.transform = `translate(-50%, -100%) rotate(${scale(hoursForClock, 0, 12, 0, 360)}deg)`
minuteEl.style.transform = `translate(-50%, -100%) rotate(${scale(minutes, 0, 60, 0, 360)}deg)`
secondEl.style.transform = `translate(-50%, -100%) rotate(${scale(seconds, 0, 60, 0, 360)}deg)`

timeEl.innerHTML = `${hoursForClock}:${minutes < 10 ? `0${minutes}` : minutes} ${ampm}`
dateEl.innerHTML = `${days[day]}, ${months[month]} <span class="circle">${date}</span>`
}

// StackOverflow https://stackoverflow.com/questions/10756313/javascript-jquery-map-a-range-of-numbers-to-another-range-of-numbers
const scale = (num, in_min, in_max, out_min, out_max) => {
return (num - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

setTime()

setInterval(setTime, 1000)

四、自制笔记本

4.1效果展示

4.2思路解析

通过js实现动态添加DOM结构,绑定创建出DOM结构的添加,删除按钮。实现监听事件。实现动态改变DOM结构其他的就是设置css的相关属性,

4.3源码

html:

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css" integrity="sha512-1PKOgIY59xJ8Co8+NE6FZ+LOAZKjy+KY8iq0G4B3CyeY6wYHN3yt9PW0XpSriVlkMXe40PTKnXrLnZ9+fkDaog==" crossorigin="anonymous" />
</head>
<body>
<button class="add" id="add">
<i class="fas fa-plus"></i> Add note
</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/1.2.2/marked.min.js"></script>

</body>

 css:

@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;400&display=swap');

* {
box-sizing: border-box;
outline: none;
}

body {
background-color: #7bdaf3;
font-family: 'Poppins', sans-serif;
display: flex;
flex-wrap: wrap;
margin: 0;
padding-top: 3rem;
}

.add {
position: fixed;
top: 1rem;
right: 1rem;
background-color: #9ec862;
color: #fff;
border: none;
border-radius: 3px;
padding: 0.5rem 1rem;
cursor: pointer;
}

.add:active {
transform: scale(0.98);
}

.note {
background-color: #fff;
box-shadow: 0 0 10px 4px rgba(0, 0, 0, 0.1);
margin: 30px 20px;
height: 400px;
width: 400px;
overflow-y: scroll;
}

.note .tools {
background-color: #9ec862;
display: flex;
justify-content: flex-end;
padding: 0.5rem;
}

.note .tools button {
background-color: transparent;
border: none;
color: #fff;
cursor: pointer;
font-size: 1rem;
margin-left: 0.5rem;
}

.note textarea {
outline: none;
font-family: inherit;
font-size: 1.2rem;
border: none;
height: 400px;
width: 100%;
padding: 20px;
}

.main {
padding: 20px;
}

.hidden {
display: none;
}

js:

const addBtn = document.getElementById('add')

const notes = JSON.parse(localStorage.getItem('notes'))

if(notes) {
notes.forEach(note => addNewNote(note))
}

addBtn.addEventListener('click', () => addNewNote())

function addNewNote(text = '') {
const note = document.createElement('div')
note.classList.add('note')

note.innerHTML = `
<div class="tools">
<button class="edit"><i class="fas fa-edit"></i></button>
<button class="delete"><i class="fas fa-trash-alt"></i></button>
</div>
<div class="main ${text ? "" : "hidden"}"></div>
<textarea class="${text ? "hidden" : ""}"></textarea>
`

const editBtn = note.querySelector('.edit')
const deleteBtn = note.querySelector('.delete')
const main = note.querySelector('.main')
const textArea = note.querySelector('textarea')

textArea.value = text
main.innerHTML = marked(text)

deleteBtn.addEventListener('click', () => {
note.remove()

updateLS()
})

editBtn.addEventListener('click', () => {
main.classList.toggle('hidden')
textArea.classList.toggle('hidden')
})

textArea.addEventListener('input', (e) => {
const { value } = e.target

main.innerHTML = marked(value)

updateLS()
})

document.body.appendChild(note)
}

function updateLS() {
const notesText = document.querySelectorAll('textarea')

const notes = []

notesText.forEach(note => notes.push(note.value))

localStorage.setItem('notes', JSON.stringify(notes))
}

五、自定义写字台(也可自定义字的样式)

5.1效果展示

5.2思路解析

搭建html结构,创建canvas标签

绑定设置的结构比如+,-,颜色改变

动态设置并获取他的值,然后将这些值动态的设置为canvas语法中设置渲染的宽度,以及设置颜色的属性

5.3源码

html:

<canvas id="canvas" width="800" height="700"></canvas>
<div class="toolbox">
<button id="decrease">-</button>
<span id="size">10</span>
<button id="increase">+</button>
<input type="color" id="color">
<button id="clear">X</button>
</div>

css:

@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');

* {
box-sizing: border-box;
}

body {
background-color: #f5f5f5;
font-family: 'Roboto', sans-serif;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
margin: 0;
}

canvas {
border: 2px solid steelblue;
}

.toolbox {
background-color: steelblue;
border: 1px solid slateblue;
display: flex;
width: 804px;
padding: 1rem;
}

.toolbox > * {
background-color: #fff;
border: none;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 2rem;
height: 50px;
width: 50px;
margin: 0.25rem;
padding: 0.25rem;
cursor: pointer;
}

.toolbox > *:last-child {
margin-left: auto;
}

js:

const canvas = document.getElementById('canvas');
const increaseBtn = document.getElementById('increase');
const decreaseBtn = document.getElementById('decrease');
const sizeEL = document.getElementById('size');
const colorEl = document.getElementById('color');
const clearEl = document.getElementById('clear');

const ctx = canvas.getContext('2d');

let size = 10
let isPressed = false
colorEl.value = 'black'
let color = colorEl.value
let x
let y

canvas.addEventListener('mousedown', (e) => {
isPressed = true

x = e.offsetX
y = e.offsetY
})

document.addEventListener('mouseup', (e) => {
isPressed = false

x = undefined
y = undefined
})

canvas.addEventListener('mousemove', (e) => {
if(isPressed) {
const x2 = e.offsetX
const y2 = e.offsetY

drawCircle(x2, y2)
drawLine(x, y, x2, y2)

x = x2
y = y2
}
})

function drawCircle(x, y) {
ctx.beginPath();
ctx.arc(x, y, size, 0, Math.PI * 2)
ctx.fillStyle = color
ctx.fill()
}

function drawLine(x1, y1, x2, y2) {
ctx.beginPath()
ctx.moveTo(x1, y1)
ctx.lineTo(x2, y2)
ctx.strokeStyle = color
ctx.lineWidth = size * 2
ctx.stroke()
}

function updateSizeOnScreen() {
sizeEL.innerText = size
}

increaseBtn.addEventListener('click', () => {
size += 5

if(size > 50) {
size = 50
}

updateSizeOnScreen()
})

decreaseBtn.addEventListener('click', () => {
size -= 5

if(size < 5) {
size = 5
}

updateSizeOnScreen()
})

colorEl.addEventListener('change', (e) => color = e.target.value)

clearEl.addEventListener('click', () => ctx.clearRect(0,0, canvas.width, canvas.height))
C 1条回复 评论
青梅煮酒

请问 一下,我本科就是软件工程(软件测试方向),以后也想成为软件测试工程师,目前大三即将结束,我之前是准备考研 ,也只是知道考研没有考虑具体什么方向之类的。因为软件测试是专业课 大三下才开课,我现在发现考研的学校 基本没有 软件测试方向的,都是比较热门的大数据、人工智能等研究方向。 所以 想成为软件测试工程师 是在大四时好好学习技术 然后本来毕业找工作?还是 应该考研究生(只是 我发现研究生没有研究软件测试的,也可能我没关注到) ?

发表于 2023-08-05 22:00:00
0 0