5 front-end practice projects (html css js canvas)
Foreword:
First of all, I wish everyone a happy Dragon Boat Festival. There are 5 exercises in this article
For those of you who just finished learning the front-end Three Musketeers. should be a good practice
Table of contents
?.Custom writing desk (you can also customize the style of the word)
1. Marquee
1.1 renderings:
1.2 Analysis of ideas
In this project, inhtml中创立20个span标签
per span tag settingstyle为–i:The style of the numbers is used for
Dynamically allocate several parts of the circle in css, transform: rotate(calc(18deg*var(–i)))
usefilter property combined with keyframesDynamically switch colors. Set each span tag at the same time
to rotate
1.3 Source code
<style>
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
main{
display: flex;
background-color: #2c3a47;
/* used to set the center of the image */
align-items: center;
justify-content: center;
width: 1920px;
height: 1000px;
animation: animate1 10s linear infinite;
}
/* Used to set the animation properties where the filter is used to make a sharp mirror and the hue-rotate property allows the image to use hue rotation*/
@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%;
/* Used to set a circle to be divided into several parts */
transform: rotate(calc(18deg*var(--i)));
}
/* :before is used to set the effect before the given property */
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. Rainbow Love
2.1 Rendering
2.2 Analysis of ideas
Build the basic html structure, usingsvg技术,
Dynamically via jschange color, and the dynamic implementation of switching graphics
2.3 Source code
<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. Alarm clock
3.1 Rendering
3.2 Analysis of ideas
Build the basic html structure,动态得到实时的时,分,秒
Obtained by the Date() function. will get the numbers according to the logic,绑定
给各div结构, perform dynamic rotation. Click the button to change背景颜色
3.3 Source code
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. Homemade Notebook
4.1 Effect display
4.2 Analysis of ideas
Implemented by js动态添加DOM结构, the bindings that create the DOM structure
Add, remove buttons.Implement listener events. Implement dynamic changes to the DOM structure
The other is to set the relevant properties of css,
4.3 Source code
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. Customize the writing desk (you can also customize the style of the word)
5.1 Effect display
5.2 Analysis of ideas
build html structure,创建canvas标签,
The structure of binding settings such as +, -, color change
动态设置and get his values, then put these values dynamically
Set to canvas syntaxrenderwidth, and set
properties of color
5.3 Source code
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))
✍At the end, if you think the blogger’s writing is okay, look forward to like it, comment, favorite