找到
18
篇与
Feng
相关的结果
-
什么是感光度?摄影入门必懂的知识分享! 图片 什么是感光度 在摄影中,感光度是控制照片亮度的核心参数之一,也是影响画质的关键因素。对于新手来说,理解并合理使用感光度,能让你在不同光线环境下拍出更理想的照片。这是第三期的内容,感觉这种文章好像没啥人看的,写完这篇可能就暂时不会更新这个系列了$[阿鲁表情]::(无所谓) 一、感光度的基本概念 感光度在相机中通常以“ISO”为标识,数值常见的有100、200、400、800、1600等。它的作用可以简单理解为:相机传感器对光线的敏感程度。 数值越高(如ISO 800、1600),传感器对光线越敏感,照片会更亮,就像在相机里“开了一盏更亮的灯”; 数值越低(如ISO 100、200),传感器对光线越不敏感,照片会偏暗,相当于“灯光调暗”。 比如在昏暗的环境中,调高ISO能让照片变亮;而在强光下,调低ISO可避免画面过曝。 二、感光度的“双刃剑”特性 感光度虽然能调节亮度,但也会影响画质,这也是它被称为“双刃剑”的原因: 图片 低ISO(100-400):画质细腻、干净,几乎没有噪点(画面中杂乱的斑点),适合光线充足的场景; 高ISO(800以上):画面会出现明显噪点,质感下降,尤其在中低端相机上更明显。 举个例子,手机在夜晚拍照时,往往会自动调高ISO,导致照片看起来“灰蒙蒙”“满是颗粒”,就是噪点过多的表现。 三、感光度的实用调节原则 使用感光度的核心是:在保证画面亮度合适的前提下,尽量用低ISO,减少噪点。具体可根据环境光线选择: 光线充足时(如晴天、强光室内):用最低ISO(通常是100),既能保证画面清晰,又能避免过曝; 光线一般时(如阴天、弱光室内):ISO 200-320为宜,平衡亮度和画质; 光线较暗时(如清晨、傍晚、夜景):ISO 800以内较合适,超过这个数值容易出现明显噪点(中低端相机尤其注意)。 四、特殊场景的灵活处理 虽然建议优先用低ISO,但遇到以下情况时,可适当提高ISO: “拍到”比“拍好”更重要:比如抓拍突发场景(如舞台瞬间、新闻事件),即使噪点增多,也要先保证画面清晰可见; 无法补光的暗环境:若没有闪光灯、三脚架等工具,适当提高ISO能避免画面过暗或模糊。 但需注意:非必要时,不要盲目调高ISO,以免画质太差。 五、总结 感光度是控制照片亮度的重要工具,数值越高画面越亮,但噪点也越多;数值越低画质越佳,但画面偏暗。使用时需根据光线环境灵活调节,优先选择低ISO,特殊场景下再适当提高,平衡亮度与画质。掌握这一点,你就能在不同场景下拍出更专业的照片啦!$[阿鲁表情]::(赞一个)
-
换个信息源,生活可能大不同 图片 换个信息源,生活可能大不同 每天刷社交媒体时,我们接收到的信息其实在悄悄塑造自己——心智水平、审美偏好、说话方式、逻辑能力,甚至人生方向,都可能被这些内容牵着走。 别看我们都在用同款APP,人和人的差距往往就藏在“看什么”里。同一平台上,不同创作者的内容质量天差地别;就算内容类型相似,短文和长文、短视频和长视频带来的影响也完全不同。有的内容只能博人一笑,有的能引发深度思考,有的不过是日常碎碎念。 当然,如果只是想上网打发时间,图个乐子,那怎么舒服怎么来就行。但要是觉得日子总在原地打转,想做出点改变,或许可以从调整信息源开始。 说句实在话,我刷短视频时,哪怕当时觉得再精彩、再有用,过段时间回想起来,脑子里常常一片空白,只记得“刚才挺开心”,像凭空浪费了一段时光。但那些认真看过的长文、长视频、访谈、电影、书籍和纪录片,带来的冲击和感触能留很久,真真切切地改变了我对某个领域、人际关系甚至自己生活的看法。 这不是说要彻底断网,或者非得捧着纸质书啃,更没必要一刀切卸载软件。关键是对信息要有筛选意识。好内容一定是创作者花了时间精力、认真思考打磨出来的,而我们要记住它、受它影响,也需要投入相应的阅读和观看时间——时间长度本身就是一道筛选门槛。 我的方法可能有点简单:首先是不看任何短视频。我知道肯定有好的,但算法推送太随机,往往看10个才能碰到1个有价值的,这种沙里淘金太浪费时间。其次,像微博、小红书这类平台,只看自己提前筛选过的、符合标准的创作者;偶尔想找新信息,再去主动搜索。 但这些只是补充,更多时间我会留给经典书籍、论文和电影。它们需要更多耐心去读、去看,但完整度、专业性和知识密度都高得多。有好几次,看完这些再刷社交媒体,才发现很多博主其实是“搬运工”,那些高赞观点不过是某本书里的一个片段,甚至还有些是一知半解的解读。 其实,社交媒体更该像一把钥匙,帮我们打开信息的大门。前段时间我看了狂阿弥采访蔡国强的那期视频,特别喜欢,就顺着这个线索去看了很多蔡国强的纪录片,还有和烟花相关的影片。之后又花了一个月,集中看了张艺谋、李安、陈凯歌的采访,回头再看他们以前的电影,突然有了新的理解。这种慢慢深入、不断学习的感觉,既满足又有成就感。 说到底,就是要意识到信息对人的影响有多大,主动给信息设置筛选门槛。生命就这么长,时间就这么多,把注意力放在值得的地方,才不算辜负自己。
-
什么是快门速度?摄影入门必懂的知识分享! 图片 什么是快门速度 在摄影中,快门速度是决定照片效果的核心参数之一。它不仅控制着画面的亮度,还能改变物体动态的呈现方式。今天,我们就来系统了解快门速度的奥秘。(这个系列的第二期,今天来讲讲什么是快门速度,这个东东有啥用,为什么有的时候拍出来会很糊,看完你就会啦~$[阿鲁表情]::(赞一个)) 一、快门速度的本质:光线的“开关” 快门是相机机身内控制光线进入的装置,它的工作原理类似窗户的开合: 打开时,光线进入相机感光元件; 关闭时,光线被阻断。 我们听到的“咔嚓”声,正是快门开合的机械声音。而快门速度,就是快门从打开到关闭的时间间隔。 二、快门速度的表示方法 快门速度以“时间”为单位,常见形式有两种: 分数秒:如1/1000秒、1/250秒,数值越小表示速度越快(1/2000秒比1/1000秒更快); 整数秒:如3秒、10秒、30秒,数值越大表示速度越慢。 关键规律:快门速度越快,进光量越少,画面偏暗;快门速度越慢,进光量越多,画面偏亮。 图片 三、快门速度如何影响画面动态? 快门速度的核心作用之一是控制物体动态的呈现状态: 高速快门(如1/1000秒以上):能定格高速运动的瞬间,比如飞鸟、水滴、运动中的车辆,让快速移动的物体清晰凝固; 低速快门(如1秒以上):会记录物体的运动轨迹,比如水流雾化、车轨拉丝、雨丝线条,让动态物体呈现模糊的动感。 原理:当快门速度快于物体运动速度时,物体被定格;当快门速度慢于物体运动速度时,物体运动轨迹被记录。 四、实用技巧:安全快门与常用参数 1. 安全快门:避免手持拍摄模糊 手持相机时,为保证画面清晰,需使用“安全快门”——快门速度不慢于镜头焦距的倒数。 例如: 85mm焦距镜头,安全快门为1/85秒; 200mm焦距镜头,安全快门为1/200秒。 2. 不同场景的常用快门速度 图片 作者:ymyphoto 日常静态场景(人文、静物):1/125秒,兼顾进光量与清晰度; 图片 作者:Imad Clicks 中速运动(跑动的小孩、行人):1/500秒,足以定格中等速度物体; 图片 作者:Vincent van Zalinge 高速运动(飞鸟、飞溅水花):1/1000秒,清晰捕捉快速动态; 图片 作者:Dane Deaner 超高速瞬间(爆破、子弹):1/2000秒以上,定格肉眼难见的瞬间; 图片 作者:Levi Trimmer 创意动态(雨丝、追焦):1/15-1/60秒,记录轨迹同时保持部分清晰; 图片 作者:云 陌 长曝光效果(瀑布雾化、车轨):5-10秒,需配合三脚架使用。 五、进阶技巧:低速快门的创意玩法 水流雾化:用5-10秒快门拍摄瀑布或溪流,让水流呈现丝绸般的质感; 车轨拉丝:夜晚用5-10秒快门拍摄车流,记录车灯形成的光轨(需三脚架); 追焦摇拍:用1/15-1/60秒快门,跟随运动物体(如行驶的汽车)移动相机,让主体清晰、背景模糊,突出速度感; 烟花拍摄:用5-10秒快门记录烟花绽放的完整轨迹,避免过长时间导致画面杂乱。 六、实用功能:快门优先模式 相机的“快门优先模式”(标记为S档或TV档)可帮你专注控制快门速度: 手动设置快门数值,相机自动匹配其他参数(光圈、ISO),适合快速抓拍运动场景或风光拍摄。 总结 快门速度是摄影中“控制时间”的魔法工具。无论是定格瞬间的锐利,还是记录轨迹的动感,理解并灵活运用快门速度,能让你的照片从“记录”升级为“表达”。下次拍摄时,不妨尝试不同的快门速度,探索属于你的独特视角吧!
-
什么是光圈?摄影入门必懂的光圈知识分享! 图片 什么是光圈?摄影入门必懂的光圈知识 在摄影的世界里,光圈是影响画面效果的核心要素之一。无论是控制光线、营造虚化还是突出主体,光圈都扮演着关键角色。本文将用通俗易懂的语言,今天的这篇文章带你全面了解光圈的本质、作用及实战技巧。(这个系列的第一篇,不知道会不会有续篇,文章也参考了部分资料与自己的想法,有不对的地方和建议可以在底部评论区发表哦~)$[经典表情]::(顶呱呱) 一、首先光圈是什么?—— 藏在镜头里的“光控阀门” 光圈是镜头内部由多片金属叶片组成的可调节装置,它像一扇可以缩放的“窗户”:叶片收缩时,中间的通光孔变小;叶片张开时,通光孔变大。这个通光孔的大小,就是我们常说的“光圈大小”。 由于无法直接观察镜头内部的叶片状态,相机用“f值”来表示光圈大小,比如f/1.4、f/2.8、f/5.6、f/11等。这里有个容易混淆的点:f值越小,代表光圈越大(通光孔越宽);f值越大,代表光圈越小(通光孔越窄)。 图片 二、光圈的核心作用:控制进光量 拍照的本质是“捕捉光线”,而光圈是控制光线进入相机的第一道“闸门”: 大光圈(f值小,如f/1.8):通光孔宽,进入相机的光线多,画面更亮; 小光圈(f值大,如f/16):通光孔窄,进入相机的光线少,画面较暗。 这一特性让光圈成为“曝光三要素”(光圈、快门、感光度)的核心成员,直接影响照片的明暗。比如在昏暗环境中,开大光圈可让画面更明亮;在强光下,缩小光圈能避免画面过曝。 图片 三、光圈的“隐藏技能”:控制背景虚化(景深) 除了调节光线,光圈最迷人的作用是改变画面的“景深”——简单说,就是画面中清晰区域的范围。这直接决定了背景的虚化效果: 大光圈(如f/1.4 - f/2.8):景深浅,主体清晰,背景模糊(虚化效果强),适合突出人像、花卉等主体; 中等光圈(如f/4 - f/5.6):景深适中,主体和背景都有一定清晰度,适合保留环境细节的人文纪实; 小光圈(如f/8 - f/16):景深大,画面从近到远都清晰,适合拍摄风光、建筑等需要全局清晰的场景。 省钱小技巧:如果你的镜头最大光圈不够大(如f/4),想拍出强虚化效果,可以让主体离背景远一些(比如拍花时,让花与后方的树叶拉开距离),同样能增强虚化。 四、实战!不同场景的光圈选择指南 光圈的使用没有固定公式,但根据题材选对光圈,能让照片瞬间“出彩”: 图片 作者:Roshan Kamath来自国外的一位打鸟的摄影师 突出主体(人像、静物、花卉) 目标:让主体清晰、背景虚化,聚焦视线。 推荐光圈:f/1.8 - f/2.8(大光圈)。 注意:使用f/1.4以下超大光圈时,建议缩小一档(如f/1.4→f/1.8),避免对焦不准(跑焦)。 图片 作者:𝗛&𝗖𝗢来自中国台湾-台北的摄影师 保留环境层次(人文、生活记录) 目标:主体清晰,背景不模糊到“消失”,体现场景氛围。 推荐光圈:f/4 - f/5.6(中等光圈)。 图片 作者:DASHIZI来自中国的摄影师 全局清晰(风光、建筑、产品) 目标:从前景到远景都清晰,展现细节。 推荐光圈:f/8 - f/16(小光圈)。 五、进阶技巧:找到镜头的“最佳画质光圈” 每支镜头都有一个“最佳画质光圈”——在这个光圈下,画面锐度、细节表现最好。通常它藏在“最大光圈缩小2-3档”的位置: 例如:最大光圈f/2.8的镜头,最佳画质光圈约为f/8; 最大光圈f/1.8的镜头,最佳画质光圈约为f/5.6。 拍摄商业广告、产品等对画质要求高的题材时,试试这个光圈,能让画面质感显著提升。 图片 六、懒人操作:光圈优先模式(A/AV档) 如果你想专注控制光圈,又不想手动调节其他参数,可以用相机的“光圈优先模式”(A档或AV档):手动设定光圈值,相机会自动匹配快门速度,保证曝光正常。尤其适合拍小孩、宠物等动态场景,避免错过瞬间。 总结 光圈是摄影的“魔法之手”:它能控制光线明暗,能制造虚实对比,还能决定画面的叙事重心。记住“f值越小光圈越大,虚化越强;f值越大光圈越小,画面越清晰”,再结合不同题材灵活调整,你就能快速掌握光圈的精髓。 教程永远是教程,其实更多的时候不要被死板的公式给局限,可以多拍拍自己想拍的,打破固有思维,或许会有不一样的收获哦~ 写完一点半了,不早了早点睡...$[阿鲁表情]::(内伤) 对了对了还有一点,如果下次还是不知道如何选择大光圈、小光圈,不妨先问自己:“我想突出主体,还是展现环境?” 答案会告诉你该用多大的光圈。$[经典表情]::(干杯)
-
Zabc.net 永久免费二级域名 支持各种记录类型设置! 图片 Zabc.net简介 ZABC.NET提供免费的二级域名服务,支持多种记录类型设置,包括A、AAAA、CNAME、MX、TXT和NS等。通过邀请链接注册,新手可获得10积分奖励,填写简单信息可额外获得20积分。用户可以用积分兑换不同长度的域名,四位及以上域名免费。此外,还享有强大的DNS管理功能和Cloudflare企业级保护管理面板。 图片 邀请链接 https://zoneabc.net/register?invite=4a391c31035f46ec802e7d3f8c32a1b3 通过邀请链接注册,可以比普通注册多获得:10积分新手奖励!再简单填写信息可得20积分,就可以用30积分换一个4位域名,五位域名20积分,6位域名10积分,七位或以上的免费。通过上面邀请链接注册~ 你可以获得: ✨ 10积分新手奖励 🌐 免费子域名注册 🚀 强大的DNS管理功能 🛡️ Cloudflare企业级保护 图片 管理面板 可以设置A、AAAA、CNAME、MX、TXT、NS等记录类型。 图片
-
免费领阿里云ESA Entrance CDN套餐 图片 前段时间腾讯云 EdgeOne CDN一直在做免费活动,阿里云现在也做了跟进,推出了国际和国内版的免费CDN。 各版本可领取时间:(跟阿里云官方确认的) 国际版:注册帐号就可以直接领,长期免费不限量不限速。 国际版Pro:每周发帖一次领取一个月。 国内版:每周发帖一次领取一个月。 总体来说相比腾讯云的国内版差别有点大,有需要的可以领取下。 领取方式 国际版领取 国际版是基础的Entrance版,注册就可以领取。 ESA Entrance 版套餐长期免费,不限量不限速、无需兑换码、无需做任务,直接注册国际站账号即可使用。您可以随时直接前往ESA控制台添加您的站点并选择免费的Entrance版套餐接入(默认不包含中国内地加速)。 图片 国际版Pro领取 按要求发帖即可每周都领取1个月Pro版的等值代金券(代金券还可抵扣超量流量费用),高阅读量的推文更有机会获得Premium版。 在任一社交平台或论坛博客(Linux.do、V2EX.com、X.com、LowEndTalk.com、您的个人博客、哔哩哔哩、即刻App、小红书、facebook.com、youtube.com)上发布一篇推荐阿里云ESA的帖子,并包含以下内容: 带有一张包含ESA元素的图片(控制台截图、速度测试图、产品宣传图等) 带有免费领取链接:http://s.tb.cn/e6.0Fu67m 发帖后,您可提供帖子链接和您的阿里云账号ID,加入群聊领取1个月Pro版。 若您的帖子停留1周,可再次发帖领取1个月 Pro 版的等值代金券,以此类推,每周都可发帖并领取一次。团队还将挑选部分阅读量超1万的推文送出1个月 Premium 版的等值代金券! 国内版领取 所有用户均可参加发帖送ESA的活动,您只需按要求发帖即可每周都领取1个月基础版的等值代金券(代金券还可抵扣超量流量费用),高阅读量的推文更有机会获得高级版。 在任一社交平台或论坛博客(Linux.do、V2EX.com、X.com、LowEndTalk.com、您的个人博客、哔哩哔哩、即刻App、小红书、facebook.com、youtube.com)上发布一篇推荐阿里云ESA的帖子,并包含以下内容: 带有一张包含ESA元素的图片(控制台截图、速度测试图、产品宣传图等) 带有免费领取链接:http://s.tb.cn/e6.0Fu67m 发帖后,您可提供帖子链接和您的阿里云账号ID,加入群聊私信奖励发放助手领取(或添加小助手拉您进群)领取1个月基础版。(点击上面的链接查看详情)
-
站点维护界面html分享 图片 《站点维护页面分享-非原创》 {iframe src="https://code.juejin.cn/pen/7530664819783893027" height="60vh"/} 在网站开发与维护过程中,常常会遇到需要对网站进行迁移升级的情况。为了给用户一个良好的提示,告知他们网站正在进行迁移维护,同时提供一些必要的信息,我们可以创建一个美观且功能丰富的网站迁移维护页面。下面就来介绍一个这样的项目示例。 一、项目概述 这个项目是一个用于展示网站迁移维护状态的单页面应用,采用 HTML、CSS 和 JavaScript 构建。页面设计简洁大方,同时运用了动画效果,让用户在等待的过程中也能有较好的视觉体验。 二、页面设计 1. 整体布局 页面主要分为几个部分:粒子背景、中心内容区域和页脚。粒子背景营造出一种动态的视觉效果,中心内容区域包含网站标志、提示信息、域名展示、进度条和社交图标,页脚则显示备案号。 2. 样式设计 背景效果:使用了渐变背景,并通过 CSS 动画实现了背景的动态变化,给人一种科技感和时尚感。 body { background: linear-gradient(-45deg, #1a2a6c, #b21f1f, #2d388a, #4a00e0); background-size: 400% 400%; animation: gradientBG 15s ease infinite; } 卡片样式:中心的提示信息区域采用了卡片式设计,具有模糊效果和阴影,增加了层次感。 .card { background: rgba(255, 255, 255, 0.1); backdrop-filter: blur(10px); border-radius: 20px; padding: 40px; box-shadow: 0 15px 35px rgba(0, 0, 0, 0.2); } 动画效果:页面中运用了多种动画效果,如标志的脉冲动画、卡片的淡入动画、进度条的动态变化等,增强了页面的交互性和趣味性。 三、功能实现 1. 粒子效果 通过 JavaScript 动态创建多个粒子元素,并为每个粒子设置随机的大小、位置、动画延迟和时长,实现了粒子在页面中随机漂浮的效果。 document.addEventListener('DOMContentLoaded', function() { const particlesContainer = document.getElementById('particles'); const particleCount = 50; for (let i = 0; i < particleCount; i++) { const particle = document.createElement('div'); particle.classList.add('particle'); const size = Math.random() * 10 + 2; particle.style.width = `${size}px`; particle.style.height = `${size}px`; particle.style.left = `${Math.random() * 100}%`; particle.style.top = `${Math.random() * 100}%`; const delay = Math.random() * 15; const duration = 15 + Math.random() * 20; particle.style.animationDelay = `${delay}s`; particle.style.animationDuration = `${duration}s`; particle.style.opacity = Math.random() * 0.5 + 0.1; particlesContainer.appendChild(particle); } });2. 进度条展示 进度条通过 CSS 动画实现了动态变化,模拟网站迁移的进度。当前显示的进度为 30%,并会在 30% - 40% 之间动态变化。 .progress-bar { height: 100%; width: 30%; background: linear-gradient(to right, #00c9ff, #92fe9d); border-radius: 10px; animation: progress 2s infinite alternate; } @keyframes progress { 0% { width: 30%; } 100% { width: 40%; } }四、响应式设计 为了确保页面在不同设备上都能有良好的显示效果,项目采用了响应式设计。通过媒体查询,当屏幕宽度小于 768px 时,会调整页面元素的字体大小和布局。 @media (max-width: 768px) { .logo { font-size: 2.5rem; } h1 { font-size: 2rem; } .card { padding: 30px 20px; width: 95%; } .domain { font-size: 1.4rem; padding: 12px 20px; } p { font-size: 1rem; } }五、总结 这个网站迁移维护页面项目通过 HTML、CSS 和 JavaScript 实现了一个美观、功能丰富且响应式的页面。它不仅能有效地向用户传达网站正在迁移维护的信息,还能提供一些必要的链接和进度展示,同时通过动画效果提升了用户体验。在实际应用中,我们可以根据需要对页面的内容和样式进行定制,以满足不同网站的需求。
-
趣味web在线小游戏-五子棋 图片 探索 HTML、CSS 和 JavaScript 实现的五子棋游戏 用 HTML、CSS 和 JavaScript 实现各种有趣的小游戏是一种既实用又有趣的学习方式。今天,我们就来深入探索一个用这三种技术打造的五子棋小游戏 {iframe src="https://code.juejin.cn/pen/7530293525473132596" height="70vh"/} 整体项目概述 这个五子棋游戏是一个网页版应用,用户可以在浏览器中直接打开并进行对战。项目的整体结构清晰,由 HTML 构建页面结构,CSS 负责样式美化,JavaScript 实现游戏的核心逻辑。通过三者的协同工作,为玩家提供了一个流畅、有趣的游戏体验。 HTML:搭建游戏的骨架 HTML 文件为游戏搭建了基本的框架,包含了游戏的标题、控制按钮、棋盘区域、游戏信息展示和结果显示等部分。 <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>五子棋游戏</title> <script src="https://cdn.tailwindcss.com"></script> <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet"> <!-- 其他元信息和脚本引入 --> </head> <body> <div class="max-w-5xl w-full bg-white rounded-2xl shadow-xl overflow-hidden"> <!-- 游戏标题 --> <header class="bg-primary text-white p-4 text-center"> <h1 class="text-[clamp(1.8rem,4vw,2.5rem)] font-bold tracking-wide">五子棋</h1> <p class="text-amber-100 mt-1">落子连五获胜</p> </header> <!-- 游戏区域 --> <main class="p-6 md:p-8"> <!-- 游戏控制区 --> <div class="flex flex-col lg:flex-row justify-between items-center mb-6 gap-4"> <!-- 玩家信息和计时器 --> <div class="flex flex-col sm:flex-row items-center gap-3 w-full lg:w-auto"> <div class="flex items-center gap-3"> <div id="current-player" class="w-6 h-6 rounded-full piece-black piece-shadow"></div> <span class="text-lg font-medium">当前玩家: <span id="player-text" class="text-black font-bold">黑棋</span></span> </div> <div class="flex items-center gap-3 mt-2 sm:mt-0"> <span class="text-lg font-medium">游戏时间: <span id="timer" class="text-primary font-bold">00:00</span></span> </div> </div> <!-- 控制按钮 --> <div class="flex gap-3 w-full lg:w-auto justify-center lg:justify-end"> <button id="restart-btn" class="bg-primary hover:bg-primary/90 text-white px-4 py-2 rounded-lg transition-all flex items-center gap-2"> <i class="fa fa-refresh"></i> <span>重新开始</span> </button> <button id="undo-btn" class="bg-gray-200 hover:bg-gray-300 text-gray-800 px-4 py-2 rounded-lg transition-all flex items-center gap-2"> <i class="fa fa-undo"></i> <span>悔棋</span> </button> <button id="hint-btn" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg transition-all flex items-center gap-2"> <i class="fa fa-lightbulb-o"></i> <span>提示</span> </button> </div> </div> <!-- 游戏主区域 --> <div class="flex flex-col lg:flex-row gap-6"> <!-- 棋盘容器 --> <div class="relative mx-auto aspect-square max-w-md w-full bg-board rounded-lg board-shadow overflow-hidden grid-pattern" style="background-size: calc(100% / 14) calc(100% / 14);"> <div id="board" class="absolute inset-0 cursor-pointer"></div> <!-- 棋盘标记点 --> <div class="absolute w-2 h-2 bg-dark rounded-full" style="top: calc(3/14 * 100%); left: calc(3/14 * 100%);"></div> <!-- 其他标记点 --> </div> <!-- 游戏信息和历史 --> <div class="w-full lg:w-80"> <!-- 游戏统计 --> <div class="bg-gray-50 rounded-xl p-4 mb-4"> <h3 class="text-lg font-semibold mb-3 text-gray-800">游戏统计</h3> <div class="grid grid-cols-2 gap-2"> <div class="bg-white p-3 rounded-lg shadow-sm"> <div class="text-sm text-gray-500">黑棋胜场</div> <div id="black-wins" class="text-xl font-bold text-black">0</div> </div> <!-- 其他统计信息 --> </div> </div> <!-- 走棋历史 --> <div class="bg-gray-50 rounded-xl p-4 h-64 overflow-hidden"> <div class="flex justify-between items-center mb-3"> <h3 class="text-lg font-semibold text-gray-800">走棋历史</h3> <button id="clear-history-btn" class="text-xs text-gray-500 hover:text-primary"> <i class="fa fa-trash-o"></i> 清空 </button> </div> <div id="move-history" class="overflow-y-auto h-48 text-sm space-y-1"> <div class="text-gray-500 italic text-center">游戏尚未开始</div> </div> </div> </div> </div> <!-- 游戏结果 --> <div id="result" class="hidden mt-6 text-center p-4 rounded-lg bg-green-100 border border-green-300"> <h2 id="result-text" class="text-xl font-bold text-green-800"></h2> <div class="mt-2 text-sm text-gray-600"> 用时: <span id="game-time">00:00</span> | 步数: <span id="move-count">0</span> </div> <button id="new-game-btn" class="mt-3 bg-primary hover:bg-primary/90 text-white px-6 py-2 rounded-lg transition-all"> 开始新游戏 </button> </div> </main> <!-- 页脚 --> <footer class="bg-gray-100 text-gray-600 p-4 text-center text-sm"> <p>© 2025 五子棋游戏 | 简约而不简单</p> </footer> </div> <script> // JavaScript 代码 </script> </body> </html>从这段代码中可以看出,HTML 页面使用了 Tailwind CSS 框架来快速实现样式布局,同时引入了 Font Awesome 图标库来增强视觉效果。页面结构层次分明,将游戏的各个部分清晰地展示出来,方便用户操作和查看信息。 CSS:美化游戏的外观 CSS 部分主要负责游戏界面的样式设计,通过自定义样式和 Tailwind CSS 的扩展,为游戏增添了丰富的视觉效果。 @layer utilities { .board-shadow { box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2); } .piece-shadow { box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3); } .piece-white { background: radial-gradient(circle at 35% 35%, #ffffff, #e0e0e0); } .piece-black { background: radial-gradient(circle at 35% 35%, #505050, #000000); } .grid-pattern { background-image: linear-gradient(#8B4513 1px, transparent 1px), linear-gradient(90deg, #8B4513 1px, transparent 1px); } .animate-fadeIn { animation: fadeIn 0.5s ease-in-out; } .hover-indicator { position: absolute; width: 6px; height: 6px; border-radius: 50%; background-color: rgba(255, 215, 0, 0.7); opacity: 0; transition: opacity 0.2s ease; } .game-history-item { padding: 0.5rem; border-radius: 0.375rem; transition: background-color 0.2s; } .game-history-item:hover { background-color: rgba(0, 0, 0, 0.05); } } @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }这里定义了棋盘的阴影效果、棋子的渐变背景、网格图案以及动画效果等。例如,piece-white 和 piece-black 类分别为白棋和黑棋设置了不同的径向渐变背景,使其看起来更加立体。而 animate-fadeIn 动画则为游戏结果的显示添加了淡入效果,提升了用户体验。 JavaScript:实现游戏的核心逻辑 JavaScript 是这个五子棋游戏的核心,它负责处理游戏的各种交互和逻辑判断。 游戏状态管理 // 游戏常量 const BOARD_SIZE = 15; const CELL_SIZE = 100 / (BOARD_SIZE - 1); // 百分比单位 const WINNING_LENGTH = 5; // 游戏状态 let currentPlayer = 'black'; let gameBoard = Array(BOARD_SIZE).fill().map(() => Array(BOARD_SIZE).fill(null)); let gameActive = true; let moveHistory = []; let gameStartTime = null; let gameTimer = null; let hintTimeout = null; let hintPosition = null; // 游戏统计 let stats = { blackWins: 0, whiteWins: 0, totalGames: 0, totalTime: 0 };这里定义了游戏的常量和状态变量,包括棋盘大小、获胜条件、当前玩家、游戏棋盘状态、走棋历史等。同时,还使用 stats 对象来记录游戏的统计信息,如黑棋和白棋的胜场数、总对局数和总游戏时间。 初始化棋盘 function initializeBoard() { boardElement.innerHTML = ''; // 创建交叉点 for (let row = 0; row < BOARD_SIZE; row++) { for (let col = 0; col < BOARD_SIZE; col++) { const intersection = document.createElement('div'); intersection.className = 'absolute w-8 h-8 rounded-full flex items-center justify-center transition-all duration-200 hover:bg-black/5 -translate-x-1/2 -translate-y-1/2'; intersection.style.left = `${col * CELL_SIZE}%`; intersection.style.top = `${row * CELL_SIZE}%`; intersection.dataset.row = row; intersection.dataset.col = col; // 添加鼠标悬停指示器 const hoverIndicator = document.createElement('div'); hoverIndicator.className = 'hover-indicator'; intersection.appendChild(hoverIndicator); // 添加点击事件 intersection.addEventListener('click', () => handleIntersectionClick(row, col)); // 添加鼠标进入事件 intersection.addEventListener('mouseenter', () => { if (gameActive && gameBoard[row][col] === null) { hoverIndicator.style.opacity = '1'; } }); // 添加鼠标离开事件 intersection.addEventListener('mouseleave', () => { hoverIndicator.style.opacity = '0'; }); boardElement.appendChild(intersection); } } }initializeBoard 函数用于创建棋盘的交叉点,并为每个交叉点添加鼠标悬停指示器和点击事件。当鼠标悬停在空闲的交叉点上时,指示器会显示出来,提示玩家可以落子。 处理落子事件 function handleIntersectionClick(row, col) { // 检查是否可以落子 if (gameBoard[row][col] !== null || !gameActive) { return; } // 清除提示 clearHint(); // 记录历史 moveHistory.push({row, col, player: currentPlayer}); // 更新走棋历史显示 addToMoveHistory(row, col, currentPlayer); // 落子 placePiece(row, col, currentPlayer); // 检查是否获胜 if (checkWin(row, col, currentPlayer)) { gameActive = false; stopTimer(); // 更新统计 if (currentPlayer === 'black') { stats.blackWins++; } else { stats.whiteWins++; } stats.totalGames++; stats.totalTime += getElapsedTime(); saveStats(); updateStatsDisplay(); showResult(`${currentPlayer === 'black' ? '黑棋' : '白棋'}获胜!`); return; } // 检查是否平局 if (checkDraw()) { gameActive = false; stopTimer(); showResult('平局!'); return; } // 切换玩家 currentPlayer = currentPlayer === 'black' ? 'white' : 'black'; updatePlayerIndicator(); }handleIntersectionClick 函数处理玩家点击交叉点的事件。它会先检查该位置是否可以落子,然后记录走棋历史,放置棋子,并检查是否获胜或平局。如果游戏结束,会更新统计信息并显示结果;否则,切换玩家继续游戏。 检查获胜和平局 function checkWin(row, col, player) { const directions = [ [0, 1], // 水平 [1, 0], // 垂直 [1, 1], // 对角线 [1, -1] // 反对角线 ]; for (const [dx, dy] of directions) { let count = 1; // 当前位置已经有一个棋子 // 正向检查 for (let i = 1; i < WINNING_LENGTH; i++) { const newRow = row + i * dx; const newCol = col + i * dy; if ( newRow >= 0 && newRow < BOARD_SIZE && newCol >= 0 && newCol < BOARD_SIZE && gameBoard[newRow][newCol] === player ) { count++; } else { break; } } // 反向检查 for (let i = 1; i < WINNING_LENGTH; i++) { const newRow = row - i * dx; const newCol = col - i * dy; if ( newRow >= 0 && newRow < BOARD_SIZE && newCol >= 0 && newCol < BOARD_SIZE && gameBoard[newRow][newCol] === player ) { count++; } else { break; } } // 检查是否连成五子 if (count >= WINNING_LENGTH) { // 高亮显示获胜的棋子 highlightWinningPieces(row, col, dx, dy, count); return true; } } return false; } function checkDraw() { for (let row = 0; row < BOARD_SIZE; row++) { for (let col = 0; col < BOARD_SIZE; col++) { if (gameBoard[row][col] === null) { return false; // 还有空位,不是平局 } } } return true; // 棋盘已满,平局 }checkWin 函数通过检查四个方向(水平、垂直、对角线和反对角线)上是否有连续五个相同颜色的棋子来判断是否获胜。如果获胜,会调用 highlightWinningPieces 函数高亮显示获胜的棋子。checkDraw 函数则遍历整个棋盘,检查是否还有空位,如果没有则判定为平局。 总结 通过这个五子棋游戏项目,我们可以看到 HTML、CSS 和 JavaScript 是如何协同工作来创建一个完整的 Web 应用的。HTML 提供了页面的结构,CSS 美化了界面,而 JavaScript 实现了游戏的核心逻辑和交互功能。这个项目不仅适合初学者学习 Web 开发的基础知识,还可以作为一个基础,进一步扩展和优化,例如添加 AI 对手、在线对战等功能。