首页
统计
关于
Search
1
Sealos3.0离线部署K8s集群
1,314 阅读
2
类的加载
873 阅读
3
Spring Cloud OAuth2.0
861 阅读
4
SpringBoot自动装配原理
752 阅读
5
集合不安全问题
647 阅读
笔记
Java
多线程
注解和反射
JVM
JUC
设计模式
Mybatis
Spring
SpringMVC
SpringBoot
MyBatis-Plus
Elastic Search
微服务
Dubbo
Zookeeper
SpringCloud
Nacos
Sentinel
数据库
MySQL
Oracle
PostgreSQL
Redis
MongoDB
工作流
Activiti7
Camunda
消息队列
RabbitMQ
前端
HTML5
CSS
CSS3
JavaScript
jQuery
Vue2
Vue3
Canvas
React
Linux
容器
Docker
Containerd
Podman
Kubernetes
Python
FastApi
OpenCV
数据分析
牛牛生活
登录
Search
标签搜索
Java
CSS
mysql
RabbitMQ
JavaScript
Redis
OpenCV
JVM
Mybatis-Plus
Camunda
多线程
CSS3
Python
Canvas
Spring Cloud
注解和反射
Activiti
工作流
SpringBoot
ndarray
蘇阿細
累计撰写
459
篇文章
累计收到
4
条评论
首页
栏目
笔记
Java
多线程
注解和反射
JVM
JUC
设计模式
Mybatis
Spring
SpringMVC
SpringBoot
MyBatis-Plus
Elastic Search
微服务
Dubbo
Zookeeper
SpringCloud
Nacos
Sentinel
数据库
MySQL
Oracle
PostgreSQL
Redis
MongoDB
工作流
Activiti7
Camunda
消息队列
RabbitMQ
前端
HTML5
CSS
CSS3
JavaScript
jQuery
Vue2
Vue3
Canvas
React
Linux
容器
Docker
Containerd
Podman
Kubernetes
Python
FastApi
OpenCV
数据分析
牛牛生活
页面
统计
关于
搜索到
109
篇与
的结果
2025-08-13
滤镜
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>滤镜</title> </head> <body> <script> // 1.创建 canvas 画布 const canvas = document.createElement('canvas') // 设置宽高 canvas.width = 500 canvas.height = 500 document.body.append(canvas) // 2.获取 context 对象(画笔) const context = canvas.getContext('2d') // 滤镜 // context.filter = 'none' // 默认值 // context.filter = 'blur(5px)' // 模糊 // context.filter = 'brightness(70%)' // 亮度 // context.filter = 'contrast(25%)' // 对比度 // context.filter = 'grayscale(60%)' // 灰度 // context.filter = 'hue-rotate(100deg)' // 色彩旋转 // context.filter = 'invert(60%)' // 透明度 // context.filter = 'opacity(60%)' // 反相 // context.filter = 'saturate(300%)' // 饱和度 context.filter = 'sepia(300%)' // 褐度 const img = new Image() img.src = './images/test.jpg' img.onload = function() { context.drawImage(img, 100, 100) } </script> </body> </html>
2025年08月13日
32 阅读
0 评论
0 点赞
2025-08-12
文字
(1)绘制文字<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>绘制文字</title> </head> <body> <script> // 1.创建 canvas 画布 const canvas = document.createElement('canvas') // 设置宽高 canvas.width = 500 canvas.height = 500 document.body.append(canvas) // 2.获取 context 对象(画笔) const context = canvas.getContext('2d') // 文字属性 context.font = '200 16px Arial' // fillText(content, x, y, [maxWidth]) // 注:x, y为文字的左下角初始坐标 context.fillText('孙笑川', 100, 100) // maxWidth 属性一般不使用 context.fillText('孙笑川', 100, 200, 30) // strokeText(content, x, y, [maxWidth]) context.strokeText('孙笑川', 100, 300) </script> </body> </html>(2)绘制渐变的文字<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>绘制渐变的文字</title> </head> <body> <script> // 1.创建 canvas 画布 const canvas = document.createElement('canvas') // 设置宽高 canvas.width = 500 canvas.height = 500 document.body.append(canvas) // 2.获取 context 对象(画笔) const context = canvas.getContext('2d') // 文字属性 context.font = 'italic 40px Arial' // 渐变 let gradient = context.createLinearGradient(0, 0, 500, 0) gradient.addColorStop(0, 'yellow') gradient.addColorStop(0.25, 'orange') gradient.addColorStop(0.5, 'skyblue') gradient.addColorStop(0.75, 'purple') gradient.addColorStop(1, 'red') context.fillStyle = gradient // fillText(content, x, y, [maxWidth]) // 注:x, y为文字的左下角初始坐标 context.fillText('孙笑川', 100, 100) // maxWidth 属性一般不使用 context.fillText('孙笑川', 100, 200, 30) context.strokeStyle = gradient // strokeText(content, x, y, [maxWidth]) context.strokeText('孙笑川', 100, 300) </script> </body> </html>(3)文字的横向对齐方式<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>文字的横向对齐方式</title> </head> <body> <script> // 1.创建 canvas 画布 const canvas = document.createElement('canvas') // 设置宽高 canvas.width = 500 canvas.height = 500 document.body.append(canvas) // 2.获取 context 对象(画笔) const context = canvas.getContext('2d') // 辅助中线 context.strokeStyle = 'black' context.moveTo(250, 0) context.lineTo(250, 500) context.stroke() // 文字属性 context.font = 'italic 24px Arial' // 方向控制 direction context.direction = 'ltr' // 默认为从左到右 // 对齐方式 textAlign // context.textAlign = 'left' // context.textAlign = 'right' // context.textAlign = 'center' // fillText(content, x, y, [maxWidth]) // 注:x, y为文字的左下角初始坐标 context.fillText('孙笑川', 250, 100) context.direction = 'rtl' // 默认为从左到右 // strokeText(content, x, y, [maxWidth]) context.strokeText('孙笑川', 250, 300) </script> </body> </html>(4)文字的纵向对齐方式<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>文字的纵向对齐方式</title> </head> <body> <script> // 1.创建 canvas 画布 const canvas = document.createElement('canvas') // 设置宽高 canvas.width = 500 canvas.height = 500 document.body.append(canvas) // 2.获取 context 对象(画笔) const context = canvas.getContext('2d') const baselines = ['top', 'hanging', 'middle', 'alphabetic', 'ideographic'] context.font = '24px Arial' baselines.forEach((baseline, index) => { // 基线 context.textBaseline = baseline const y = 50 + index * 50 context.beginPath() context.moveTo(0, y + 0.5) context.lineTo(500, y + 0.5) context.stroke() context.fillText(`孙笑川(${baseline})`, 0, y) }) </script> </body> </html>
2025年08月12日
30 阅读
0 评论
0 点赞
2025-08-11
图片
1. 绘制图片<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>绘制图片</title> </head> <body> <script> // 1.创建 canvas 画布 const canvas = document.createElement('canvas') // 设置宽高 canvas.width = 500 canvas.height = 500 document.body.append(canvas) // 2.获取 context 对象(画笔) const context = canvas.getContext('2d') // 3.1 准备图片 let img = new Image() img.src = './images/test.jpg' // 图片加载时需要一定的时间(该加载过程不会阻塞js进程),需等待加载完成,才能绘制 img.onload = function () { // 3.2 使用 drawImage 方法 // 方法一:传入绘制的坐标,按图片原有的大小绘制 // context.drawImage(img, 100, 100) // 方法二:传入绘制的坐标和渲染的大小(宽、高) // context.drawImage(img, 20, img.height) // 方法三:传入要裁切的区域,渲染到页面上 context.drawImage(img, 10, 20, 15, 25, 100, 100, 100, 100) } </script> </body> </html>2. 动画使用的精灵图素材宽1260,高300,分为7份<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>动画</title> </head> <body> <script> // 1.创建 canvas 画布 const canvas = document.createElement('canvas') // 设置宽高 canvas.width = 500 canvas.height = 500 document.body.append(canvas) // 2.获取 context 对象(画笔) const context = canvas.getContext('2d') // 3.1 准备图片 let img = new Image() img.src = './images/sprite.png' // 图片加载时需要一定的时间(该加载过程不会阻塞js进程),需等待加载完成,才能绘制 img.onload = function () { let index = 0 setInterval(() => { context.clearRect(0, 0, canvas.width, canvas.height) context.drawImage(img, 180 * index, 0, 180, 300, 0, 0, 180, 300) index++ index %= 7 }, 100) } </script> </body> </html>
2025年08月11日
37 阅读
0 评论
0 点赞
2025-07-20
贝塞尔曲线
2. 贝塞尔曲线Canvas 提供了二阶和三阶的贝塞尔曲线方法:quadraticCurveTobezierCurveTo(1)二阶、三阶贝塞尔曲线<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>贝塞尔曲线</title> </head> <body> <script> // 1.创建 canvas 画布 const canvas = document.createElement('canvas') // 设置宽高 canvas.width = 500 canvas.height = 500 document.body.append(canvas) // 2.获取 context 对象(画笔) const context = canvas.getContext('2d') // // 二阶贝塞尔曲线(第一个点是控制点) // // 3.1 起始点 // context.moveTo(100, 100) // // 3.2 调用 quadraticCurveTo 绘制二阶路径 // context.quadraticCurveTo(180, 230, 350, 100) // context.stroke() // 三阶贝塞尔曲线(第一、二个点是控制点) // 4.1 起始点 context.moveTo(100, 100) // 4.2 调用bezierCurveTo绘制三阶路径 context.bezierCurveTo(180, 210, 50, 280, 410, 360) context.stroke() </script> </body> </html>(2)使用 arcTo 绘制圆弧<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>arcTo绘制圆弧</title> </head> <body> <script> // 1.创建 canvas 画布 const canvas = document.createElement('canvas') // 设置宽高 canvas.width = 500 canvas.height = 500 document.body.append(canvas) // 2.获取 context 对象(画笔) const context = canvas.getContext('2d') // arcTo 绘制圆弧 // 3.1 起始点 context.moveTo(100, 100) // 3.2 调用 arcTo 方法,第一、二个参数为控制点,第三个参数为圆弧半径 context.arcTo(180, 100, 180, 180, 50) context.stroke() </script> </body> </html>
2025年07月20日
73 阅读
0 评论
0 点赞
2025-07-09
标准圆弧曲线
Canvas中的曲线分为两种:标准圆弧曲线、贝塞尔曲线1. 标准圆弧曲线(1)弧线<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>弧线</title> </head> <body> <script> // 1. 创建 canvas 画布 const canvas = document.createElement('canvas') // 设置宽高 canvas.width = 500 canvas.height = 500 document.body.append(canvas) // 2. 获取 context 对象(画笔) const context = canvas.getContext('2d') // 画圆弧 /* 参数:圆心x, 圆心y, 弧度,圆弧起点,圆弧终点,是否逆时针(默认为false) */ context.arc(200, 200, 50, 90 * (Math.PI / 180), 180 * (Math.PI / 180), true) context.stroke() </script> </body> </html>(2)画一个笑脸<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>笑脸</title> </head> <body> <script> // 1. 创建 canvas 画布 const canvas = document.createElement('canvas') // 设置宽高 canvas.width = 500 canvas.height = 500 document.body.append(canvas) // 2. 获取 context 对象(画笔) const context = canvas.getContext('2d') // 3.画笑脸 // 3.1 外圈大圆 context.arc(200, 200, 100, 0, 360 * (Math.PI / 180)) context.stroke() // 3.2 左眼 // 重新生成新的路径(即在两个不相关的图形之间要加上开始路径,闭合路径,取消两个图形之间的连线) context.beginPath() context.arc(150, 150, 20, 0, 360 * (Math.PI / 180)) context.stroke() context.closePath() // 3.3 右眼 context.beginPath() context.arc(250, 150, 20, 0, 360 * (Math.PI / 180)) context.stroke() context.closePath() // 3.4 鼻子 context.beginPath() context.arc(200, 195, 8, 0, 360 * (Math.PI / 180)) context.stroke() context.closePath() // 3.5 嘴巴 context.beginPath() context.arc(200, 200, 80, 0, 180 * (Math.PI / 180)) context.stroke() context.closePath() </script> </body> </html>(3)椭圆<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>椭圆</title> </head> <body> <script> // 1. 创建 canvas 画布 const canvas = document.createElement('canvas') // 设置宽高 canvas.width = 500 canvas.height = 500 document.body.append(canvas) // 2. 获取 context 对象(画笔) const context = canvas.getContext('2d') // 画椭圆 /* 参数:圆心x,圆心y,x半径,y半径,椭圆旋转的角度(弧度),圆弧起点,圆弧终点,是否逆时针(默认为false) */ context.ellipse(300, 300, 200, 100, 0, 0, 360 * (Math.PI / 180)) context.stroke() </script> </body> </html>(4)使用fill填充图形<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>使用fill填充图形</title> </head> <body> <script> // 1. 创建 canvas 画布 const canvas = document.createElement('canvas') // 设置宽高 canvas.width = 500 canvas.height = 500 document.body.append(canvas) // 2. 获取 context 对象(画笔) const context = canvas.getContext('2d') // 3.填充 context.moveTo(100, 100) context.lineTo(90, 220) context.lineTo(220, 150) // 调用fill方法时,路径会自动连接起始位置 // context.lineTo(100, 100) // context.fill() // 填充指定颜色 // context.fillStyle = 'lightblue' // context.fill() // 使用线性渐变填充 // const gradient = context.createLinearGradient(0, 0, 500, 500) // gradient.addColorStop(0, 'lightblue') // gradient.addColorStop(1, 'red') // context.fillStyle = gradient // context.fill() // 使用径向渐变填充 const gradient = context.createRadialGradient(150, 150, 0, 150, 150, 100) gradient.addColorStop(0, 'lightblue') gradient.addColorStop(1, 'orange') context.fillStyle = gradient context.fill() </script> </body> </html>(5)五子棋(5)五子棋<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>五子棋</title> <style> canvas { background-color: green; display: block; margin: 0 auto; } #tip { text-align: center; padding: 20px; } </style> </head> <body> <div id="tip">游戏开始</div> <script> // 1.创建 canvas 画布 const canvas = document.createElement('canvas') // 设置宽高 canvas.width = 700 canvas.height = 700 document.body.append(canvas) // 2.获取 context 对象(画笔) const context = canvas.getContext('2d') const tip = document.getElementById('tip') // 3.棋盘 for (i = 0; i < 14; i++) { context.moveTo(50, 50 * i) context.lineTo(650, 50 * i) context.stroke() context.moveTo(50 * i, 50) context.lineTo(50 * i, 650) context.stroke() } // 5.棋子颜色判断标志位 let isBlackChess = true // 6.使用二维数组存储棋子 let circles = [] for(i = 0; i < 14; i ++) { circles[i] = [] } // 7.游戏结束判断标志位 let gameOver = false // 4.落子 canvas.addEventListener('click', e => { if (gameOver) { return } let { offsetX, offsetY } = e // 判断棋子不超出棋盘 if (offsetX < 25 || offsetY < 25 || offsetX > 675 || offsetY > 675) { return } // 6.1 格子位置 let gridX = Math.floor((offsetX + 25) / 50) let gridY = Math.floor((offsetY + 25) / 50) // 6.3 判断是否重复落子 if (circles[gridX][gridY]) { return } // 4.1 棋子位置 let x = gridX * 50 let y = gridY * 50 context.beginPath() context.arc(x, y, 20, 0, 2 * Math.PI) // 6.2 存储棋子 circles[gridX][gridY] = isBlackChess ? 'black' : 'white' // 5.1 设置棋子颜色 let chessGradientX = isBlackChess ? x - 10 : x + 10 let chessGradientY = isBlackChess ? y - 10 : y + 10 let gradient = context.createRadialGradient(chessGradientX, chessGradientY, 0, chessGradientX, chessGradientY, 30) gradient.addColorStop(0, isBlackChess ? 'gray' : '#666') gradient.addColorStop(1, isBlackChess ? 'black' : 'white') context.fillStyle = gradient // 5.2 设置棋子阴影 context.shadowColor = '#333' context.shadowOffsetX = 2.5 context.shadowOffsetY = 2 context.fill() context.closePath() // 7.判断当前是否有人获胜 gameOver = checkVertical(circles[gridX][gridY], gridX, gridY) || checkHorizontal(circles[gridX][gridY], gridX, gridY) || checkWn2Es(circles[gridX][gridY], gridX, gridY) || checkEn2Ws(circles[gridX][gridY], gridX, gridY) if (gameOver) { tip.innerText = `${isBlackChess ? '黑' : '白'}棋获胜,游戏结束!` //console.log(circles) return } tip.innerText = isBlackChess ? '请白棋落子' : '请黑棋落子' isBlackChess = !isBlackChess }) // 纵向查找是否有五个连续相同的棋子 function checkVertical(currentChess, row, col) { let count = 1 return checkUp(currentChess, row, col, count) + checkDown(currentChess, row, col, count) - 1 >= 5 } function checkUp(currentChess, row, col, count) { // 向上查找的次数 let up = 0 while (true) { // 向上查找 up++ // 角 // 左上角 if (row === 1 && col === 1) { return count } // 右上角 if (row + up === circles.length && col === 1) { return count } // 边 // 上 if (col === 1) { return count } // 右 pass // 下 pass // 左 pass // 超出边界 if (row - up < 0) { return count } if (circles[row][col - up] && circles[row][col - up] === currentChess) { count++ } // 棋子不连续 if (col === 1) { if (count >= 5 || (circles[row][col + up] !== currentChess)) { break } } else if (col + up >= circles.length) { if (count >= 5 || (circles[row][col - up] !== currentChess)) { break } } else { if (count >= 5 || (circles[row][col - up] !== currentChess && circles[row][col + up] !== currentChess)) { break } } } return count } function checkDown(currentChess, row, col, count) { // 向下查找的次数 let down = 0 while (true) { // 向下查找 down++ // 角 // 右下角 if (row + down === circles.length && col + down === circles.length) { return count } // 左下角 if (row === 1 && col + down === circles.length) { return count } // 边 // 上 pass // 右 pass // 下 if (col + down === circles.length) { return count } // 左 pass // 超出边界 if (row + down > circles.length) { return count } if (circles[row][col + down] && circles[row][col + down] === currentChess) { count++ } // 棋子不连续 if (col === 1) { if (count >= 5 || (circles[row][col - down] !== currentChess)) { break } } else if (col + down >= circles.length) { if (count >= 5 || (circles[row][col - down] !== currentChess)) { break } } else { if (count >= 5 || (circles[row][col - down] !== currentChess && circles[row][col + down] !== currentChess)) { break } } } return count } // 横向查找是否有五个连续相同的棋子 function checkHorizontal(currentChess, row, col) { let count = 1 return checkLeft(currentChess, row, col, count) + checkRight(currentChess, row, col, count) - 1 >= 5 } function checkLeft(currentChess, row, col, count) { // 向左查找的次数 let left = 0 while (true) { // 向左查找 left++ // 角 // 左上角 if (row === 1 && col === 1) { return count } // 左下角 if (row === 1 && col + left === circles.length) { return count } // 边 // 上 pass // 右 pass // 下 pass // 左 if (row === 1) { return count } // 超出边界 if (row - left < 0) { return count } if (circles[row - left][col] && circles[row - left][col] === currentChess) { count++ } // 棋子不连续 if (col === 1 && row + left < circles.length) { if (count >= 5 || (circles[row + left][col] !== currentChess)) { break } } else if (row + left >= circles.length) { if (count >= 5 || (circles[row - left][col] !== currentChess)) { break } } else { if (count >= 5 || (circles[row - left][col] !== currentChess && circles[row + left][col] !== currentChess)) { break } } } return count } function checkRight(currentChess, row, col, count) { // 向右查找的次数 let right = 0 while (true) { // 向右查找 right++ // 角 // 右上角 if (row + right === circles.length && col === 1) { return count } // 右下角 if (row + right === circles.length && col + right === circles.length) { return count } // 边 // 上 pass // 右 if (row + right === circles.length) { return count } // 下 pass // 左 pass if (circles[row + right][col] && circles[row + right][col] === currentChess) { count++ } // 超出边界 if (row + right > circles.length) { return count } // 同色棋子大于5 || 棋子不连续 if (col === 1 && row + right < circles.length) { if (count >= 5 || (circles[row + right][col] !== currentChess)) { break } } else if (row + right >= circles.length) { if (count >= 5 || (circles[row - right][col] !== currentChess)) { break } } else { if (count >= 5 || (circles[row - right][col] !== currentChess && circles[row + right][col] !== currentChess)) { break } } } return count } // 左上到右下查找是否有五个连续相同的棋子 function checkWn2Es(currentChess, row, col) { // 连续同色棋子的数量 let count = 1 return checkWn(currentChess, row, col, count) + checkEs(currentChess, row, col, count) - 1 >= 5 } function checkWn(currentChess, row, col, count) { // 左上查找的次数 let leftUp = 0 while (true) { // 向左上查找 leftUp++ // 角 // 左上角 if (row === 1 && col === 1) { return count } // 右上角 if (row + leftUp === circles.length && col === 1) { return count } // 左下角 if (row === 1 && col + leftUp === circles.length) { return count } // 边 // 上 if (col === 1) { return count } // 右 pass // 下 pass // 左 if (row === 1) { return count } // 超出边界 if (row - leftUp < 0 || col - leftUp < 0) { return count } if (circles[row - leftUp][col - leftUp] && circles[row - leftUp][col - leftUp] === currentChess) { count++ } // 同色棋子大于5 || 棋子不连续 if (row === 1 || col === 1) { if (count >= 5 || (circles[row + leftUp][col + leftUp] !== currentChess)) { break } } else if (row + leftUp >= circles.length || col + leftUp >= circles.length) { if (count >= 5 || circles[row - leftUp][col - leftUp] !== currentChess) { break } } else { if (count >= 5 || (circles[row - leftUp][col - leftUp] !== currentChess && circles[row + leftUp][col + leftUp] !== currentChess)) { break } } } return count } function checkEs(currentChess, row, col, count) { // 右下查找的次数 let rightDown = 0 while (true) { // 向右下查找 rightDown++ // 角 // 右上角 if (row + rightDown === circles.length && col === 1) { return count } // 右下角 if (row + rightDown === circles.length && col + rightDown === circles.length) { return count } // 左下角 if (row === 1 && col + rightDown === circles.length) { return count } // 边 // 上 pass // 右 if (row + rightDown === circles.length) { return count } // 下 if (col + rightDown === circles.length) { return count } // 左 pass // 超出边界 if (row + rightDown > circles.length || col + rightDown > circles.length) { return count } if (circles[row + rightDown][col + rightDown] && circles[row + rightDown][col + rightDown] === currentChess) { count++ } // 同色棋子大于5 || 棋子不连续 if (row === 1 || col === 1) { if (count >= 5 || (circles[row + rightDown][col + rightDown] !== currentChess)) { break } } else if (row + rightDown >= circles.length || col + rightDown >= circles.length) { if (count >= 5 || circles[row - rightDown][col - rightDown] !== currentChess) { break } } else { if (count >= 5 || row - rightDown < 0) { break } if (count >= 5 || (circles[row - rightDown][col - rightDown] !== currentChess && circles[row + rightDown][col + rightDown] !== currentChess)) { break } } } return count } // 右上到左下查找是否有五个连续相同的棋子 function checkEn2Ws(currentChess, row, col) { // 连续同色棋子的数量 let count = 1 return checkEn(currentChess, row, col, count) + checkWs(currentChess, row, col, count) - 1 >= 5 } function checkEn(currentChess, row, col, count) { // 右上查找的次数 let rightUp = 0 while (true) { // 向右上查找 rightUp++ // 角 // 左上角 if (row === 1 && col === 1) { return count } // 右上角 if (row + rightUp === circles.length && col === 1) { return count } // 右下角 if (row + rightUp === circles.length && col + rightUp === circles.length) { return count } // 边 // 上 if (col === 1) { return count } // 右 if (row + rightUp >= circles.length) { return count } // 下 pass // 左 pass // 超出边界 if (row + rightUp > circles.length || col - rightUp < 0) { return count } if (circles[row + rightUp][col - rightUp] && circles[row + rightUp][col - rightUp] === currentChess) { count++ } // 同色棋子大于5 || 棋子不连续 if (row === 1 || col + rightUp >= circles.length) { if (count >= 5 || (circles[row + rightUp][col - rightUp] !== currentChess)) { break } } else if (row + rightUp >= circles.length || col === 1) { if (count >= 5 || (circles[row - rightUp][col + rightUp] !== currentChess)) { break } } else { if (count >= 5 || row - rightUp < 0) { break } if (count >= 5 || (circles[row + rightUp][col - rightUp] !== currentChess && circles[row - rightUp][col + rightUp] !== currentChess)) { break } } } return count } function checkWs(currentChess, row, col, count) { // 左下查找的次数 let leftDown = 0 while (true) { // 向左下查找 leftDown++ // 角 // 左上角 if (row === 1 && col === 1) { return count } // 左下角 if (row === 1 && col + leftDown === circles.length) { return count } // 右下角 if (row + leftDown === circles.length && col + leftDown === circles.length) { return count } // 边 // 上 pass // 右 pass // 下 if (col === col + leftDown === circles.length) { return count } // 左 if (row === 1) { return count } // 超出边界 if (row - leftDown < 0 || col + leftDown > circles.length) { return count } if (circles[row - leftDown][col + leftDown] && circles[row - leftDown][col + leftDown] === currentChess) { count++ } // 同色棋子大于5 || 棋子不连续 if (row + leftDown >= circles.length || col === 1) { if (count >= 5 || circles[row - leftDown][col + leftDown] !== currentChess) { break } } else if (row === 1 || col + leftDown >= circles.length) { if (count >= 5 || (circles[row + leftDown][col - leftDown] !== currentChess)) { break } } else { if (count >= 5 || (circles[row - leftDown][col + leftDown] !== currentChess && circles[row + leftDown][col - leftDown] !== currentChess)) { break } } } return count } </script> </body> </html>(6)阴影<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>阴影</title> </head> <body> <script> // 1.创建 canvas 画布 const canvas = document.createElement('canvas') // 设置宽高 canvas.width = 500 canvas.height = 500 document.body.append(canvas) // 2.获取 context 对象(画笔) const context = canvas.getContext('2d') context.strokeStyle = 'green' context.lineWidth = 6 // 设置图像的阴影 context.shadowColor = 'gray' context.shadowOffsetX = 6 context.shadowOffsetY = 3 context.shadowBlur = 5 context.moveTo(100, 100) context.lineTo(260, 260) context.stroke() </script> </body> </html>
2025年07月09日
148 阅读
0 评论
0 点赞
2025-07-07
线条绘制
(1)直线步骤:使用 moveTO 方法把画笔移动到直线起点使用 lineTo 方法把画笔移动到直线终点使用 stroke 方法让画笔绘制线条<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>直线</title> </head> <body> <script> // 1. 创建 canvas 画布 const canvas = document.createElement('canvas') // 设置宽高 canvas.width = 500 canvas.height = 500 document.body.append(canvas) // 2. 获取 context 对象(画笔) const context = canvas.getContext('2d') // 3. 绘制直线 // 3.1 起点 context.moveTo(100, 100) // 3.2 终点 context.lineTo(200, 220) // 3.3 调用画线的方法 context.stroke() </script> </body> </html>(2)折线<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>折线</title> </head> <body> <script> // 1. 创建 canvas 画布 const canvas = document.createElement('canvas') // 设置宽高 canvas.width = 500 canvas.height = 500 document.body.append(canvas) // 2. 获取 context 对象(画笔) const context = canvas.getContext('2d') // 3. 绘制折线 // 3.1 起点 context.moveTo(100, 100) // 3.2 使用 lineTo 依次经过转折点 context.lineTo(200, 220) context.lineTo(300, 100) context.lineTo(400, 210) context.lineTo(500, 250) // 3.3 调用画线的方法 context.stroke() </script> </body> </html>(3)lineWidth 设置线条的宽度<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>lineWidth设置线条的宽度</title> </head> <body> <script> // 1. 创建 canvas 画布 const canvas = document.createElement('canvas') // 设置宽高 canvas.width = 500 canvas.height = 500 document.body.append(canvas) // 2. 获取 context 对象(画笔) const context = canvas.getContext('2d') // 3. 画线 context.moveTo(100, 100) context.lineTo(200, 220) // 4.设置线条的宽度(粗细) context.lineWidth = 3 // 5.画线 context.stroke() context.lineTo(300, 100) // 注意:画完线之后如果有新的路径,要调用 stroke 方法才会绘制新的路径 context.stroke() </script> </body> </html>(4)strokeStyle 修改线条的颜色<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>strokeStyle修改线条的颜色</title> </head> <body> <script> // 1. 创建 canvas 画布 const canvas = document.createElement('canvas') // 设置宽高 canvas.width = 500 canvas.height = 500 document.body.append(canvas) // 2. 获取 context 对象(画笔) const context = canvas.getContext('2d') // 3. 画线 context.moveTo(100, 100) context.lineTo(200, 220) context.lineWidth = 3 // 4.修改线条的颜色 context.strokeStyle = '#add8e6' // 5.画线 context.stroke() context.lineTo(300, 100) // 注意:画完线之后如果有新的路径,要调用 stroke 方法才会绘制新的路径 context.stroke() </script> </body> </html>(5)线性渐变<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>线性渐变</title> </head> <body> <script> // 1. 创建 canvas 画布 const canvas = document.createElement('canvas') // 设置宽高 canvas.width = 500 canvas.height = 500 document.body.append(canvas) // 2. 获取 context 对象(画笔) const context = canvas.getContext('2d') // 3. 线性渐变 // 创建 const gradient = context.createLinearGradient(0, 0, 500, 500) // 从什么颜色开始渐变 gradient.addColorStop(0, 'pink') // 中间 gradient.addColorStop(0.35, 'yellow') // 到什么颜色结束 gradient.addColorStop(1, 'green') // 画线 context.lineTo(0, 0) context.lineTo(300, 300) context.lineWidth = 3 // 将渐变作为线条的颜色 context.strokeStyle = gradient context.stroke() </script> </body> </html>(6)径向渐变<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>径向渐变</title> </head> <body> <script> // 1. 创建 canvas 画布 const canvas = document.createElement('canvas') // 设置宽高 canvas.width = 500 canvas.height = 500 document.body.append(canvas) // 2. 获取 context 对象(画笔) const context = canvas.getContext('2d') // 3. 生成渐变对象 const gradient = context.createRadialGradient(100, 100, 0, 100, 100, 100) // 添加渐变的颜色 gradient.addColorStop(0, 'yellow') gradient.addColorStop(1, 'green') // 把渐变赋给画笔 context.fillStyle = gradient context.fillRect(0, 0, 200, 200) </script> </body> </html>(7)锥形渐变<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>锥形渐变</title> </head> <body> <script> // 1. 创建 canvas 画布 const canvas = document.createElement('canvas') // 设置宽高 canvas.width = 500 canvas.height = 500 document.body.append(canvas) // 2. 获取 context 对象(画笔) const context = canvas.getContext('2d') // 3. 生成渐变对象 /* 参数一:弧度 参数二:渐变中心的 x 轴坐标 参数三:渐变中心的 y 轴坐标 */ const gradient = context.createConicGradient(45 * (Math.PI / 180), 100, 100) // 添加渐变的颜色 gradient.addColorStop(0, 'pink') gradient.addColorStop(1, 'lightgreen') // 把渐变赋给画笔 context.fillStyle = gradient context.fillRect(0, 0, 200, 200) </script> </body> </html>(8)重复元图像<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>重复元图像</title> </head> <body> <script> // 1. 创建 canvas 画布 const canvas = document.createElement('canvas') // 设置宽高 canvas.width = 500 canvas.height = 500 document.body.append(canvas) // 2. 获取 context 对象(画笔) const context = canvas.getContext('2d') // 3. 生成渐变对象 let img = new Image() img.src = './images/test.jpg' img.onload = function() { // 创建重复元图像对象 let p = context.createPattern(img, 'repeat') context.fillStyle = p context.fillRect(0, 0, 200, 200) } </script> </body> </html>(9)渐变的折线<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>渐变的折线</title> </head> <body> <script> // 1. 创建 canvas 画布 const canvas = document.createElement('canvas') // 设置宽高 canvas.width = 500 canvas.height = 500 document.body.append(canvas) // 2. 获取 context 对象(画笔) const context = canvas.getContext('2d') // 3. 绘制折线 context.lineWidth = 3 // 渐变 let gradient = context.createLinearGradient(100, 100, 500, 100) gradient.addColorStop(0, 'lightblue') gradient.addColorStop(0.25, 'lightgreen') gradient.addColorStop(0.5, 'hotpink') gradient.addColorStop(1, 'red') // 将渐变赋值给 context context.strokeStyle = gradient // 3.1 起点 context.moveTo(100, 100) // 3.2 使用 lineTo 依次经过转折点 context.lineTo(200, 220) context.lineTo(300, 100) context.lineTo(400, 210) context.lineTo(500, 100) // 3.3 调用画线的方法 context.stroke() </script> </body> </html>(10)线段转折点的样式<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>线段转折点的样式</title> </head> <body> <script> // 1. 创建 canvas 画布 const canvas = document.createElement('canvas') // 设置宽高 canvas.width = 500 canvas.height = 500 document.body.append(canvas) // 2. 获取 context 对象(画笔) const context = canvas.getContext('2d') // 3. 绘制折线 context.lineWidth = 8 // 渐变 let gradient = context.createLinearGradient(100, 100, 500, 100) gradient.addColorStop(0, 'lightblue') gradient.addColorStop(0.25, 'lightgreen') gradient.addColorStop(0.5, 'hotpink') gradient.addColorStop(1, 'red') // 将渐变赋值给 context context.strokeStyle = gradient // 修改线段起点、终点的样式 /* butt 默认值,线条末端呈正方形 round 圆角 square 线条末端呈方形 */ context.lineCap = 'round' // 修改线段转折点的样式 /* miter 默认值,通过延伸相连部分的外边缘,使其相交于一点,形成一个额外的菱形区域 round 圆角 bevel 在相连部分的末端填充一个额外的以三角形为底的区域,每个部分都有各自独立的矩形拐角 */ context.lineJoin = 'round' // 3.1 起点 context.moveTo(100, 100) // 3.2 使用 lineTo 依次经过转折点 context.lineTo(200, 220) context.lineTo(300, 100) context.lineTo(400, 210) context.lineTo(500, 100) // 3.3 调用画线的方法 context.stroke() </script> </body> </html>
2025年07月07日
69 阅读
0 评论
0 点赞
2025-07-07
基础使用
参考 b站 叩丁狼 Canvas 课程(1)通过 html 标签创建<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>通过html标签创建</title> </head> <body> <canvas id="canvas" width="500" height="500"></canvas> <script> // 1. 获取 canvas 画布 const canvas = document.getElementById('canvas') // 2. 获取 context 对象(画笔) const context = canvas.getContext('2d') // 3. 画一个正方形 // fillRect(x, y, width, height) context.fillRect(50, 40, 200, 200) </script> </body> </html>(2)通过 js 创建<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>通过js创建</title> </head> <body> <script> // 1. 创建 canvas 画布 const canvas = document.createElement('canvas') // 设置宽高 canvas.width = 500 canvas.height = 500 document.body.append(canvas) // 2. 获取 context 对象(画笔) const context = canvas.getContext('2d') // 3. (同第一节)画一个正方形 context.fillRect(60, 60, 200, 200) </script> </body> </html>(3)canvas 宽高的设置<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>canvas宽高的设置</title> <!-- <style> canvas { width: 500px; height: 500px } </style> --> </head> <body> <script> // 注意:不建议使用 CSS 样式表设置 canvas 的宽高,样式会出问题 // 1. 创建 canvas 画布 const canvas = document.createElement('canvas') // 设置宽高 canvas.width = 500 canvas.height = 500 document.body.append(canvas) // 2. 获取 context 对象(画笔) const context = canvas.getContext('2d') // 3. (同第一节)画一个正方形 context.fillRect(60, 60, 200, 200) </script> </body> </html>
2025年07月07日
30 阅读
0 评论
0 点赞
2025-01-12
十、DOM
1. document对象<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>document对象</title> </head> <body> <script> /* document对象: - 表示的是整个网页 - 原型链: HTMLDocument -> Document -> Node -> EventTarget -> Object.prototype -> null - 部分属性: - document.documentElement html根元素 - document.head head元素 - document.title title元素 - document.body body元素 - document.links 页面中的所有超链接 ...... - mdn文档:https://developer.mozilla.org/en-US/docs/Web/API/Document */ </script> </body> </html> 2. 元素节点<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>元素节点</title> </head> <body> <script> /* 元素节点: - 在网页中,每一个标签都是一个元素节点 - 如何获取元素节点对象? 1. 通过document对象获取 2. 通过document对象创建 - 通过document来获取已有的元素节点: - document.getElementById(): - 根据id获取一个 - document.getElementsByClassName(): - 根据元素的class属性值获取一组元素节点对象 - 返回的是一个类数组对象,不是数组 - 返回结果是实时更新的(即当网页中添加了新的元素,返回结果也会同步实时更新) - document.getElementsByTagName(): - 根据标签名获取一组元素节点对象 - 同理getElementsByClassName()方法 - document.getElementsByTagName("*") 获取网页中的所有元素节点对象 - document.getElementsByName(): - 根据name属性获取一组元素节点对象 - 同理getElementsByClassName()方法 - 常用于获取 form 表单中的元素节点对象 - document.querySelectorAll(): - 根据选择器获取元素节点对象 - 返回结果是一个类数组对象(不会实时更新) - document.querySelector(): - 根据选择器获取网页中第一个符合条件的元素节点对象 - 创建元素节点对象: - document.createElement(): - 根据标签名创建元素节点对象 - const div = document.createElement('div') */ </script> </body> </html> 3. 元素的属性和方法<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>元素的属性和方法</title> </head> <body> <script> /* 通过元素节点对象获取其他节点的方法: - element.childNodes 获取当前元素的子节点(包含空白的子节点,文本,换行符等等) - element.children 获取当前元素的子元素 - element.firstElementChild 获取当前元素的第一个子元素 - element.lastElementChild 获取当前元素的最后一个子元素 - element.nextElementSibling 获取当前元素的下一个兄弟元素 - element.previousElementSibling 获取当前元素的前一个兄弟元素 - element.parentNode 获取当前元素的父节点 - element.tagName 获取当前元素的标签名 */ </script> </body> </html> 4. 文本节点<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>文本节点</title> </head> <body> <script> /* 网页中的所有文本内容都是文本节点对象 - element.textContent 获取或修改元素的文本内容 - 获取的是标签中的原始内容,不考虑css样式 - element.innerText 获取或修改元素的文本内容 - 当修改的内容中包含html元素时,会自动进行转义 - 获取内容时,会考虑css的样式(展示什么获取的就是什么) - 读取css样式时,会触发网页的重排(计算css样式) - element.innerHtml 获取或修改元素中的html代码 - 插入内容时,有xss注入风险 */ </script> </body> </html> 5. 属性节点<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>属性节点</title> </head> <body> <input id="aaaa" class="aaa" type="text" name="username" value="admin"/> <script> /* 属性节点(Attr): - 如何操作属性节点: 方式一: - 读取:元素.属性名(注:class属性需要使用calssName来读取) - 修改:元素.属性名 = 属性值 方式二: - 读取:元素.getAttribute(属性名) - 修改:元素.setAttribute(属性名, 属性值) - 删除:元素.removeAttribute(属性名) */ const input = document.querySelector("[name=username]") console.log('input.type:', input.type) console.log('input.id:', input.id) console.log('input.class:', input.className) console.log('input.name:', input.name) console.log('input.value:', input.value) //input.value = '孙笑川' console.log('---------------------------------------'); console.log('input.getAttribute(\'type\'):', input.getAttribute('type')) console.log('input.getAttribute(\'id\'):', input.getAttribute('id')) console.log('input.getAttribute(\'class\'):', input.getAttribute('class')) console.log('input.getAttribute(\'name\'):', input.getAttribute('name')) console.log('input.getAttribute(\'value\'):', input.getAttribute('value')) input.setAttribute('value', '药水哥') input.setAttribute('disabled', true) input.removeAttribute('disabled') </script> </body> </html> 6. 事件<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>事件</title> </head> <body> <!-- <button id="btn" onclick="alert('直接在元素的属性中设置')">点一下</button> --> <button id="btn">点一下</button> <script> /* 事件(Event): - 用户与网页之间发生的交互行为 - 可以通过为事件绑定响应函数,来完成与用户之间的交互 - 绑定方式: 1. 直接在元素的属性中设置 2. 为元素的指定属性设置回调函数来绑定(一个事件只能绑定一个响应函数,后来者居上) 3. 通过元素的 addEventListener() 方法来绑定(可以重复绑定,先绑定的谁,谁先执行) */ const btn = document.getElementById('btn') //btn.onclick = function() { // alert('为元素的指定属性设置回调函数来绑定') //} btn.addEventListener("click", function() { alert('通过元素的 addEventListener() 方法来绑定') }) </script> </body> </html> 7. 文档的加载<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>文档的加载</title> <script> // 方式二 //window.onload = function() { // const btn = document.getElementById('btn') // console.log(btn) //} //window.addEventListener('load', function() { // const btn = document.getElementById('btn') // console.log(btn) //}) // 方式三 //document.addEventListener('DOMContentLoaded', function() { // const btn = document.getElementById('btn') // console.log(btn) //}) </script> <script defer src="./script/index.js"></script> </head> <body> <button id="btn">点一下</button> <script> /* 网页是自上而下加载的,如果将js代码编写到网页的上边(之前),js代码在执行时,网页还没有加载完毕,这时会出现无法获取DOM的情况 解决方案: 1. 将 script 标签放到 body 之后 - 所有方式中优先级最高 2. 将js代码写到 window.onload 的回调函数中 - 网页中所有的文档加载完后才执行 3. 将js代码写到 document 对象的 DOMContentLoaded 的回调函数中 - 当前文档加载完毕之后触发(相比方式二执行时机更早) 4. 将代码编写到外部的js文件中,然后以defer的形式引入 - 相比方式三执行时机更早 */ // 方式一 //const btn = document.getElementById('btn') //console.log(btn) </script> </body> </html> index.jsconst btn = document.getElementById('btn') console.log(btn)8. DOM的修改<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>DOM的修改</title> </head> <body> <button id="btn1">添加元素</button> <button id="btn2">删除元素</button> <button id="btn3">替换元素</button> <ul id="list"> <li id="sxc">孙笑川</li> <li id="ysg">药水哥</li> </ul> <script> const list = document.getElementById('list') const btn1 = document.getElementById('btn1') btn1.onclick = function() { // 创建新的li const li = document.createElement('li') li.innerText = 'Giao哥' li.id = 'gg' // appendChild() 给节点添加子节点 //list.appendChild(li) /* insertAdjacentElement(): - 像元素的指定位置添加元素 - 参数: 1. 要添加的位置: - beforeend 标签的最后 - afterbegin 标签的开始 - beforebegin 在当前元素的前边插入(即插入兄弟元素) - afterend 在当前元素的后边插入(即插入兄弟元素) 2. 要添加的元素 */ //list.insertAdjacentElement('beforeend', li) // 同理 insertAdjacentElement() 方法 list.insertAdjacentHTML('beforeend', '<li id="gg">Giao哥</>') } const btn2 = document.getElementById('btn2') btn2.onclick = function() { const sxc = document.getElementById('sxc') sxc.remove() } const btn3 = document.getElementById('btn3') btn3.onclick = function() { const sxc = document.getElementById('sxc') const li = document.createElement('li') li.innerText = 'Giao哥' li.id = 'gg' sxc.replaceWith(li) } </script> </body> </html> 9. XSS注入问题<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>XSS注入问题</title> </head> <body> <script> /* 在涉及到需要将用户输入的内容插入到网页中时, 尽量使用 元素.innerText 或 元素.textContent 方法代替 元素.innerHTML 方法 前两种方法在赋值时会进行转义 */ </script> </body> </html> 10. 节点的复制<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>节点的复制</title> </head> <body> <button id="btn">复制节点</button> <ul id="list1"> <li id="l1">孙笑川</li> <li id="l2">药水哥</li> <li id="l3">Giao哥</li> </ul> <ul id="list2"> <li>刘波</li> </ul> <script> // 点击按钮后,复制list1的节点到list2 const list1 = document.getElementById('list1') const list2 = document.getElementById('list2') const l1 = document.getElementById('l1') const btn = document.getElementById('btn') btn.onclick = function() { /* cloneNode() 方法: - 参数: - false(默认值) 复制节点的所有属性,但不包括子节点 - true 复制所有信息,包括子节点 */ const newL1 = l1.cloneNode(true) newL1.id = 'newL1' list2.appendChild(newL1) } </script> </body> </html>11. 修改css样式<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>修改css样式</title> <style> .box1 { width: 200px; height: 200px; background-color: lightblue; } .box2 { width: 300px; height: 300px; border: 1px black solid; background-color: lightgreen; } </style> </head> <body> <button id="btn">修改样式</button> <hr/> <div class="box1"></div> <script> // 点击按钮后修改box1的样式 const box1 = document.getElementsByClassName('box1')[0] const btn = document.getElementById('btn') // 直接修改样式(不建议直接使用) // btn.onclick = function() { // // 修改宽度 // // 元素.style.样式名(小驼峰) = 样式值 // box1.style.width = '300px' // box1.style.backgroundColor = 'lightgreen' // } // 通过class属性间接修改样式 btn.onclick = function() { // 不建议这么操作 // box1.className += ' box2' /* 元素.classList: - 是一个对象,提供了对当前元素的 class 的各种操作方法 - 常用方法: - add(): 向元素中添加一个或多个 class - remove(): 移除指定 class - toggle(): 切换元素的class(一次只能操作一个) - replace(): 替换 class - contains(): 检查是否包含指定 class */ // box1.classList.add('box2', 'box3') // box1.classList.remove('box2') // box1.classList.toggle('box2') // box1.classList.replace('box1', 'box2') console.log(box1.classList.contains('box1')) } </script> </body> </html>12. 读取css样式<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>读取css样式</title> <style> .box1 { width: 200px; height: 200px; background-color: lightblue; } .box1::before { color: blueviolet; content: '测试'; } </style> </head> <body> <button id="btn">读取样式</button> <hr/> <div class="box1"></div> <script> // 点击按钮后读取css样式 const box1 = document.getElementsByClassName('box1')[0] const btn = document.getElementById('btn') btn.onclick = function() { /* getComputedStyle(): - 读取指定元素所有生效的样式,以对象的形式返回 - 参数: 1. 要获取样式的对象 2. 要获取的伪元素 - 注:样式对象中返回的值不一定能直接拿来计算, 有可能是 auto 等等 */ const styleObj = getComputedStyle(box1) console.log(styleObj) const box1Before = getComputedStyle(box1, '::before') console.log(box1Before.content) } </script> </body> </html>13. 通过属性读取样式<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>通过属性读取样式</title> <style> .box1 { width: 200px; height: 200px; background-color: lightblue; margin: 50px; padding: 50px; border: 2px black solid; overflow: auto; } .box2 { width: 100px; height: 500px; background-color: lightcoral; } </style> </head> <body> <button id="btn">读取样式</button> <hr/> <div id="box1" class="box1"> <div id="box2" class="box2"></div> </div> <script> const btn = document.getElementById('btn') const box1 = document.getElementById('box1') btn.onclick = function() { /* 获取元素内部的高度和宽度(包括内容区和内边距): 元素.clientWidth 元素.clientHeight 获取元素的可见框的大小(包括内容区,内/外边距): 元素.offsetHeight 元素.offsetWidthyuan 获取元素滚动区域的大小: 元素.scrollHeight 元素.scrollWidth 获取元素的定位父元素: 元素.offsetParent 注:定位父元素:离当前元素最近的开启了定位的祖先元素,如果都没有开启,则返回body 获取元素相对于其定位父元素的偏移量: 元素.offsetTop 元素.offsetLeft 获取元素滚动条的偏移量: 元素.scrollTop 元素.scrollLeft */ console.log(box1.scrollTop) console.log(box1.scrollLeft) } </script> </body> </html>14. 事件<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>事件</title> <style> .box1 { width: 300px; height: 300px; background-color: lightblue; border: 1px black solid; } </style> </head> <body> <div id="box1" class="box1"></div> <script> /* 事件(Event): - 浏览器在事件触发时所创建的对象 - 如:鼠标的坐标、键盘的按键等等 - 浏览器在创建事件对象后,会将其作为响应函数的参数传递 可以在事件的回调函数中定义一个形参来接收事件对象 */ const box1 = document.getElementById('box1') // box1.onmousemove = function(event) { // console.log(event) // } // box1.onmousemove = event => { // console.log(event) // } // box1.addEventListener('mousemove', function() { // console.log(event) // }) box1.addEventListener('mousemove', event => { console.log(event) }) </script> </body> </html> 15.事件对象<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>事件对象</title> <style> .box1 { width: 300px; height: 300px; background-color: lightblue; border: 1px black solid; } .box2 { width: 150px; height: 150px; background-color: lightcoral; border: 1px black solid; } .box3 { width: 75px; height: 75px; background-color: lightseagreen; border: 1px black solid; } </style> </head> <body> <div id="box1" class="box1"> <div id="box2" class="box2"> <div id="box3" class="box3"></div> </div> </div> <a id="test" href="https://www.bing.com" target="_blank">点击跳转</a> <script> /* DOM中有多种不同类型的事件对象: - 共同祖先 Event: - event.target 表示触发事件的对象 - event.currentTarget 绑定事件的对象(与this同理) - event.stopPropagation() 停止事件的传递 - event.preventDefault() 取消事件的默认行为(推荐使用) - 事件的冒泡(bubble): - 指事件的向上传递 - 当元素上的某个事件被触发后,其祖先元素上的相同的事件也被同时触发 */ const box1 = document.getElementById('box1') box1.onclick = event => { console.log('box1', event.target) alert('box1') } const box2 = document.getElementById('box2') box2.onclick = event => { console.log('box2', event.target) alert('box2') } const box3 = document.getElementById('box3') box3.onclick = event => { console.log('box3', event.target) // 停止冒泡事件 event.stopPropagation() alert('box2') } const test = document.getElementById('test') test.addEventListener('click', event => { // 取消事件的默认行为 event.preventDefault() alert('点击后不进行超链接跳转') }) </script> </body> </html> 16. 事件的冒泡<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>事件的冒泡</title> <style> .box1 { width: 75px; height: 75px; background-color: lightblue; border-radius: 50%; position: absolute; } .box2 { width: 300px; height: 300px; background-color: lightcoral; } .box3 { width: 200px; height: 200px; background-color: lightgreen; } .box4 { width: 150px; height: 150px; background-color: lightgray; position: absolute; bottom: 0; } </style> </head> <body> <div id="box1" class="box1"></div> <div id="box2" class="box2"></div> <div id="box3" class="box3" onclick="alert('box3')"> <div id="box4" class="box4" onclick="alert('box4')"></div> </div> <script> // 使box1跟随鼠标移动 document.addEventListener("mousemove", (event) => { box1.style.left = event.x + "px" box1.style.top = event.y + "px" }) const box2 = document.getElementById("box2") box2.addEventListener("mousemove", (event) => { event.stopPropagation() }) // 点击box4依然会触发事件冒泡,弹出box3,即事件的冒泡与元素的样式无关,只与结构有关 </script> </body> </html> 17. 事件委派<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>事件委派</title> </head> <body> <button id="btn">添加</button> <ul id="list"> <li><a href="javascript:;">链接一</a></li> <li><a href="javascript:;">链接二</a></li> <li><a href="javascript:;">链接三</a></li> <li><a href="javascript:;">链接四</a></li> </ul> <script> const links = document.getElementsByTagName("a") // for (let i = 0; i < links.length; i++) { // links[i].addEventListener('click', event => { // alert(links[i].textContent) // }) // } const list = document.getElementById("list") const btn = document.getElementById("btn") btn.addEventListener("click", () => { list.insertAdjacentHTML("beforeend", `<li><a href="javascript:;">链接${Math.ceil(Math.random() * 10)}</a></li>`) }) //需求:只进行一次事件绑定,即可让所有的超链接(不管是原有的还是新添加的)都具有指定的事件 document.addEventListener("click", (event) => { if ([...links].includes(event.target)) { alert(event.target.textContent) } }) /* 事件委派: - 将原本绑定给多个元素的事件,统一绑定给document(此处以绑定给document为例,绑定的对象随业务场景的不同而不同) - 降低代码的复杂度 */ </script> </body> </html> 18. 事件的捕获<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>事件的捕获</title> <style> .box1 { width: 300px; height: 300px; background-color: lightblue; } .box2 { width: 200px; height: 200px; background-color: lightcoral; } .box3 { width: 100px; height: 100px; background-color: lightgrey; } </style> </head> <body> <div id="box1" class="box1"> <div id="box2" class="box2"> <div id="box3" class="box3"></div> </div> </div> <script> /* 事件的传播机制: - 在DOM中,分为三个阶段: 1. 捕获阶段(由祖先元素向目标元素进行事件的捕获) 2. 目标阶段(触发事件的对象) 3. 冒泡阶段(由目标元素向祖先元素进行事件的冒泡) - 默认情况下是在冒泡阶段触发事件 - 事件的捕获: - 指事件从外向内的传导 - document -> html -> body -> 具体元素 - 默认情况下,事件不会再捕获阶段触发 - 可以通过设置 元素.addEventListener() 方法的第三个参数为true来在捕获阶段触发事件(一般不这么使用) */ const box1 = document.getElementById('box1') const box2 = document.getElementById('box2') const box3 = document.getElementById('box3') // 通过设置第三个参数为true,在捕获阶段触发点击事件 // 此时 alert 的顺序为:box1 -> box2 -> box3 // 一般情况下不会这么使用 box1.addEventListener('click', event => { alert('box1 - ' + event.eventPhase) // event.eventPhase 事件触发的阶段 // 1:捕获阶段 2:目标阶段 3:冒泡阶段 }, true) box2.addEventListener('click', event => { alert('box2 - ' + event.eventPhase) }, true) box3.addEventListener('click', event => { alert('box3 - ' + event.eventPhase) }, true) </script> </body> </html> 19. BOM对象<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>BOM对象</title> </head> <body> <script> /* BOM: - 浏览器对象模型 - 通过BOM对象,可以完成对浏览器的各种操作 - 五个BOM对象: - Window:浏览器窗口(全局对象) - Navigator:浏览器的对象 - Location:浏览器的地址栏信息 - History:浏览器的历史记录(控制浏览器的前进后退) - Screen:屏幕信息 */ </script> </body> </html> 20. Navigator<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Navigator</title> </head> <body> <script> /* Navigator(浏览器的对象): - mdn文档:https://developer.mozilla.org/en-US/docs/Web/API/Navigator */ console.log(navigator.userAgent) </script> </body> </html> 21. Location<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Location</title> </head> <body> <button id="btn">点一下</button> <script> /* Location(浏览器的地址栏信息): - mdn文档:https://developer.mozilla.org/en-US/docs/Web/API/Location */ const btn = document.getElementById('btn') btn.addEventListener('click', () => { // 可以直接给location赋值,表示跳转到指定地址 // location = 'https://www.bing.com' // 等价于直接赋值 //location.assign('https://www.bing.com') // 执行替换之后不能通过历史记录回退 //location.replace('https://www.bing.com') // 刷新页面 // location.reload() // 强制清缓存刷新 Ctrl + F5 location.reload(true) }) </script> </body> </html> 22. History<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>History</title> </head> <body> <button id="btn">点一下</button> <script> /* History(浏览器的历史记录): - mdn文档:https://developer.mozilla.org/en-US/docs/Web/API/History */ const btn = document.getElementById('btn') btn.addEventListener('click', () => { // 后退 // history.back() // 前进 // history.forward() // 1:前进1,-1:后退1 history.go(1) }) console.log('历史记录的数量:', history.length) </script> </body> </html> 23. 定时器<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>定时器</title> </head> <body> <div id="num"></div> <script> /* 定时器: - 让代码在指定时间后执行 - 设置方式: 1. setTimeout(): - 参数: 1. 回调函数 2. 延迟的时间(单位毫秒) - 关闭定时器: - clearTimeout() 2. setInterval(): - 每间隔一段时间,代码就执行一次 - 参数: 1. 回调函数 2. 延迟的时间(单位毫秒) - 关闭定时器: - clearInterval() */ const timer = setTimeout(() => { alert('延迟1.5s再执行') }, 1500) // 关闭定时器 clearTimeout(timer) const timer1 = setInterval(() => { alert('延迟2s再执行') }, 2000) clearInterval(timer1) // const num = document.getElementById('num') // let index = 0 // setInterval(() => { // index ++ // num.textContent = index // }, 2000) /* 定时器的本质,即在指定时间后将函数添加到消息队列中 注:函数实际的执行时间要看调用栈的情况 */ // console.time() // setTimeout(() => { // console.timeEnd() // console.log('setTimeout()定时器执行了...') // // 打印结果为: // // default: 5003.26904296875 ms // // 定时器执行了... // }, 3000) // const begin = Date.now() // while (Date.now() - begin < 5000) {} /* setInterval()方法每隔一段时间就将函数添加到消息队列中, 但函数执行的间隔时间受函数自身执行速度的影响,所以每次的间隔时间不一定是定时器中指定的间隔时间 */ // console.time() // setInterval(() => { // console.timeEnd() // console.log('setInterval()定时器执行了...') // alert('setInterval()') // console.time() // }, 3000) // 需求:确保函数每一次执行的间隔时间都相同 // console.time() // setTimeout(function test() { // console.timeEnd() // console.log('确保函数每一次执行的间隔时间都相同') // console.time() // setTimeout(test, 3000) // }, 3000) // 打印结果为 222 \n 111 // console.log(222)在主调用栈中,优先级最高 // console.log(111)是在定时器等待0ms后将函数投递到消息队列中 setTimeout(() => { console.log(111) }, 0) console.log(222) </script> </body> </html>24. 事件循环<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>事件循环</title> </head> <body> <button id="btn">点一下</button> <button id="btn1">消息队列测试</button> <script> /* 事件循环(Event Loop): - 函数在每次执行时,都会产生一个执行环境 - 执行环境负责存储函数执行时产生的一切数据 调用栈(Call Stack): - 后进先出(后来者居上) - 负责存储函数的执行环境 - 当一个函数被调用时,它的执行环境会作为一个栈帧, 插入到调用栈的栈顶,执行完之后改栈帧会自动弹出 消息队列: - 先进先出 - 负责存储将要执行的函数 - 当触发一个事件时,其执行函数并不是直接添加到调用栈中 即:事件触发后,js引擎将事件响应函数插入到消息队列中排队 */ function test() { console.log('执行test函数') function test1() { console.log('执行test1函数') } console.log('test执行完毕') } // test() const btn = document.getElementById('btn') btn.addEventListener('click', () => { alert('btn按钮') const begin = Date.now() while (Date.now() - begin < 3000) {} }) const btn1 = document.getElementById('btn1') btn1.addEventListener('click', () => { alert('btn1按钮') }) </script> </body> </html>
2025年01月12日
49 阅读
0 评论
0 点赞
1
2
3
...
14