从零开发HarmonyOS(鸿蒙)运动手表小游戏—数字华容道
zhezhongyun 2025-07-02 00:15 38 浏览
本个demo将从零基础开始完成鸿蒙小游戏APP在可穿戴设备上的编译,此处以运动手表为例,在项目中我们所使用到的软件为DevEco Studio,下载地址为:DevEco Studio下载、DevEco Studio安装教程,在项目中我们要实现的内容为数字华容道APP的开发。
- 在初始界面中显示4*4的方阵,方阵中分布有随意打乱的1至15的数字和一个空白方格,方阵上方增加一个计时器,显示游戏进行的时间,单位为秒,方阵下方显示一个“重新开始”的按钮,为用户提供重新开始游戏的机会。
- 向上、下、左、右任一方向滑动,空白方格周围对应位置的方格便会随之向对应的方向移动一格,计时器也会显示游戏开始到当前的时间。
- 经过若干次移动后,当所有的数字按顺序排列后,则会弹出游戏成功的界面,再滑动也不会有任何变化,此时方阵上方的计时器停止计时,点击“重新开始”的按钮后则会重新返回步骤1界面所示。
正文
创建项目
DevEco Studio下载安装成功后,打开DevEco Studio,点击左上角的File,点击New,再选择New Project,选择Lite Wearable选项,选择默认的模板,然后选择保存路径,将文件命名为Game1(文件名不能出现中文或者特殊字符,否则将无法成功创建项目文件),最后点击Finish。
主要编写的文件为index.css、index.hml和index.js,打开路径如图所示,index.hml用于描述页面中包含哪些组件,index.css用于描述页面中的组件都长什么样,index.js用于描述页面中的组件是如何进行交互的。
实现开始界面的布局
首先,我们要先画出一个4*4的方阵,方阵中按照顺序显示1至15的数字,方阵上方显示“当前秒数:0”,方阵下方有一个“重新开始”的按钮。
1.在index.hml中添加相应的页面组件:
首先创建一个基础容器div类名为container,用于盛装所有的其他组件
<div class="container" >
</div>然后在此基础容器中添加一个文字组件text类名为seconds,且注明显示的固定部分“当前秒数:”,为动态变换部分赋予一个名为currentSteps的变量,用于动态显示游戏进行的秒数
<text class="seconds">
当前秒数:{
{
currentSeconds}}
</text>再添加一个画布组件canvas类名为canvas,增加一个引用属性ref,用来指定指向子元素或子组件的引用信息,该引用将注册到父组件的$refs 属性对象上,以便在此画布上画出4*4的方阵
<canvas class="canvas" ref="canvas" >
</canvas>最后添加一个普通按钮组件,类名为bit,并赋值“重新开始”,用于重新开始游戏
<input type="button" value="重新开始" class="bit"/>至此,index.hml文件已经全部编写完毕
<div class="container" >
<text class="seconds">
当前秒数:{
{
currentSeconds}}
</text>
<canvas class="canvas" ref="canvas" ></canvas>
<input type="button" value="重新开始" class="bit"/>
</div>2.在index.css中描述刚才添加的页面组件的样式:
首先编写container的样式,flex-direction为容器主轴方向,选择column(垂直方向从上到下),justify-content为容器当前行的主轴对齐格式,选择center(项目位于容器的中心),align-items为容器当前行的交叉轴对齐格式,选择center(元素在交叉轴居中),width、height分别为容器以像素为单位的宽度和高度,都设定为450px
.container {
flex-direction: column;
justify-content: center;
align-items: center;
width:450px;
height:450px;
}然后编写seconds的样式,font-size为设置文本的尺寸,设定为18px,text-align为设置文本的文本对齐方式,选择center(文本居中对齐),width、height分别设定为300px和20px,letter-spacing为设置文本的字符间距,设定为0px,margin-top为设置上外边距,设定为10px
.seconds{
font-size: 18px;
text-align:center;
width:300px;
height:20px;
letter-spacing:0px;
margin-top:10px;
}再编写canvas的样式,width、height都设定为320px,background-color为设置背景颜色,设定为#FFFFFF
.canvas{
width:305px;
height:305px;
background-color: #FFFFFF;
}最后编写bit的样式,width、height分别设定为150px和30px,background-color设定为#AD9D8F,font-size设定为24px,margin-top设定为10px
.bit{
width:150px;
height:30px;
background-color:#AD9D8F;
font-size:24px;
margin-top:10px;
}至此,index.css文件已经全部编写完毕
3.在index.js中描述页面中的组件交互情况:
首先在data中为当前秒数currentSeconds赋值为0
data: {
currentSeconds:0,
}然后在文件开头定义一个全局变量context,定义一个全局变量的二维数组grids,其中的值为1至15和0,定义全局常量方格的边长SIDELEN为70,方格的间距MARGIN为5,创建一个onReady()函数,用于定义2d绘画工具
var grids=[[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 0]];
var context;
const SIDELEN = 70;
const MARGIN = 5;
onReady(){
context=this.$refs.canvas.getContext('2d');
}再创建drawGrids()函数,先将grids的值利用toString()函数全部转化为字符串,fillStyle为画图工具context的方格的颜色,方格的背景颜色定义为#BBADA0,数字的颜色定义为#000000,fillRect为画图工具context的画图矩形的大小,其中有四个参数,第一个参数指定矩形左上角的x坐标,第二个参数指定矩形左上角的y坐标,第三个参数指定矩形的高度,第四个参数指定矩形的宽度。font为为画图工具context的字体大小,定义为30px HYQiHei-65S,因为要出现一个空白的方格,所以需要添加一个判断语句,当数字为0时不显示数字。fillText为画图工具context的文本字体大小,其中有三个参数,第一个参数为绘制的文本,第二个参数指定文本左上角的x坐标,第三个参数指定文本左上角的y坐标,最后创建onShow()函数,用于调用drawGrids()函数
onShow() {
this.drawGrids();
},
drawGrids() {
for (let row = 0; row < 4; row++) {
for (let column = 0; column < 4; column++) {
let gridStr = grids[row][column].toString();
context.fillStyle = "#BBADA0";
let leftTopX = column * (MARGIN + SIDELEN) + MARGIN;
let leftTopY = row * (MARGIN + SIDELEN) + MARGIN;
context.fillRect(leftTopX, leftTopY, SIDELEN, SIDELEN);
context.font = "30px HYQiHei-65S";
if (gridStr != "0") {
context.fillStyle = "#000000";
let offsetX = (4 - gridStr.length) * (SIDELEN / 8);
let offsetY = (SIDELEN - 30) / 2;
context.fillText(gridStr, leftTopX + offsetX, leftTopY + offsetY);
}
}
}
}至此,index.jd文件已经全部编写完毕,运行即可得出上述界面布局了
var grids=[[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 0]];
var context;
const SIDELEN = 70;
const MARGIN = 5;
export default {
data: {
currentSeconds:0,
},
onReady() {
context = this.$refs.canvas.getContext('2d');
},
onShow() {
this.drawGrids();
},
drawGrids() {
for (let row = 0; row < 4; row++) {
for (let column = 0; column < 4; column++) {
let gridStr = grids[row][column].toString();
context.fillStyle = "#BBADA0";
let leftTopX = column * (MARGIN + SIDELEN) + MARGIN;
let leftTopY = row * (MARGIN + SIDELEN) + MARGIN;
context.fillRect(leftTopX, leftTopY, SIDELEN, SIDELEN);
context.font = "30px HYQiHei-65S";
if (gridStr != "0") {
context.fillStyle = "#000000";
let offsetX = (4 - gridStr.length) * (SIDELEN / 8);
let offsetY = (SIDELEN - 30) / 2;
context.fillText(gridStr, leftTopX + offsetX, leftTopY + offsetY);
}
}
}
},
}实现数字的随机打乱和方格的移动
其次我们要在屏幕上随机生成一个数字被随意打乱的4*4的方阵,并且向任意方向滑动屏幕,空白方格周围对应位置的方格便会随之向对应的方向移动一格
1.在index.hml中添加相应的页面组件:
我们需要在画布中添加一个swipe属性,用于响应滑动事件,赋予一个所自动调用的函数swipeGrids
<canvas class="canvas" ref="canvas" onswipe="swipeGrids"></canvas>至此,index.hml文件已经全部编写完毕
2.在index.css中描述刚才添加的页面组件的样式:
这一部分不需要添加或修改页面组件的样式
3.在index.js中描述页面中的组件交互情况:
首先我们得先实现方格的移动,创建一个函数changeGrids(direction),接受一个参数direction指示滑动的方向,先找出空白方格所在位置对应的二维数组下标,接着判断参数direction为’left’、‘right’、‘up’ 或’down’时,对应的方格和空白方格对应的二维数组的数值对调,创建响应滑动事件所自动调用的函数swipeGrids(event),参数为滑动事件,调用函数changeGrids(direction),并传入滑动的方向,最后调用函数drawGrids()
swipeGrids(event) {
this.changeGrids(event.direction);
this.drawGrids();
},
changeGrids(direction) {
let x;
let y;
for (let row = 0; row < 4; row++) {
for (let column = 0; column < 4; column++) {
if (grids[row][column] == 0) {
x = row;
y = column;
break;
}
}
}
let temp;
if (direction == 'left' && (y + 1) < 4) {
temp = grids[x][y + 1];
grids[x][y + 1] = grids[x][y];
grids[x][y] = temp;
} else if (direction == 'right' && (y - 1) > -1) {
temp = grids[x][y - 1];
grids[x][y - 1] = grids[x][y];
grids[x][y] = temp;
} else if (direction == 'up' && (x + 1) < 4) {
temp = grids[x + 1][y];
grids[x + 1][y] = grids[x][y];
grids[x][y] = temp;
} else if (direction == 'down' && (x - 1) > -1) {
temp = grids[x - 1][y];
grids[x - 1][y] = grids[x][y];
grids[x][y] = temp;
}
}然后添加一个函数initGrids(),用于随机打乱排列规则的数字,先创建一个一维数组变量array,赋值为上下左右四个方向"left",“up”,“right”,“down”,Math.random()函数是随机[0,1)内的小数,Math.random() * 4是随机[0,4)内的小数,Math.floor(x)为得出小于或等于x的最大整数,随机生成一个数字,读取数组array对应的值,调用函数this.changeGrids(direction)并将刚才的array对应的值传入,便能移动一次方格,循环此步骤若干次便可随机打乱排列规则的数字,生成一个数字被随意打乱的4*4的方阵
initGrids(){
let array=["left","up","right","down"];
for (let i = 0; i < 100; i++){
let randomIndex = Math.floor(Math.random() * 4);
let direction = array[randomIndex];
this.changeGrids(direction);
}
}最后在函数onShow()中调用函数initGrids()
onShow() {
this.initGrids();
this.drawGrids();
}至此,index.jd文件已经全部编写完毕,运行即可得出上述界面布局了
实现计时器、重新开始和游戏成功
最后我们要在方阵上方动态显示游戏开始到当前的时间,并且当数字按顺序排列后弹出“游戏成功”界面,点击“重新开始”按钮能够重新随机生成一个数字被随意打乱的4*4的方阵,当前秒数置为0 ,且能够重新开始计时
1.在index.hml中添加相应的页面组件:
为了使数字按顺序排列后才显示“游戏成功”界面,需要添加一个栈stack类名设定为stack,使画布先进栈,“游戏成功”后进栈,这样就能达到“游戏成功”界面显示在画布上方了
<stack class="stack">
</stack>在栈stack组件中增加一个游戏成功的容器div类名为subcontainer,以isShow控制该容器是否进栈,当isShow为true时才进栈,增加文本组件text,类名gameover,并赋值“游戏成功”
<div class="subcontainer" show="{
{isShow}}">
<text class="gameover">
游戏成功
</text>
</div>最后为“重新开始”按钮增加一个点击事件click,所调用的函数为restartGame
<input type="button" value="重新开始" class="bit" onclick="restartGame"/>至此,index.hml文件已经全部编写完毕
<div class="container" >
<text class="seconds">
当前秒数:{
{
currentSeconds}}
</text>
<stack class="stack">
<canvas class="canvas" ref="canvas" onswipe="swipeGrids"></canvas>
<div class="subcontainer" show="{
{isShow}}">
<text class="gameover">
游戏成功
</text>
</div>
</stack>
<input type="button" value="重新开始" class="bit" onclick="restartGame"/>
</div>2.在index.css中描述刚才添加的页面组件的样式:
首先编写stack的样式,width、height都设定为320px,margin-top设定为10px
.stack{
width: 305px;
height: 305px;
margin-top: 10px;
}然后编写subcontainer的样式,left为指示距边界框左上角的以像素为单位的水平坐标,top为指示距边界框左上角的以像素为单位的垂直坐标,width、height分别设定为220px和130px,justify-content选择center,align-items选择center, background-color设定为#E9C2A6
.subcontainer {
left:50px;
top:95px;
width: 220px;
height: 130px;
justify-content: center;
align-items: center;
background-color: #E9C2A6;
}最后编写gameover的样式,font-size设定为38px,color设定为black
.gameover {
font-size: 38px;
color: black;
}至此,index.css文件已经全部编写完毕
3.在index.js中描述页面中的组件交互情况:
首先在data函数中给isShow赋值为false,将开头的全局变量grids赋值删除,增加一个函数onInit()给grids赋值,并调用函数initGrids()和this.drawGrids()
var grids;
data: {
currentSeconds:0,
isShow: false
},
onInit() {
grids=[[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 0]];
this.initGrids();
this.drawGrids();
}然后在开头定义一个全局变量timer赋值为null,在函数onShow()中增加一个计时器setInterval(),其中有两个参数,第一个参数为调用的函数,第二个参数为每隔多长时间调用一次函数,单位为毫秒,再定义调用的函数run(),用于每次currentSeconds加1,至此计时器便完成了
var timer = null;
onShow() {
this.initGrids();
this.drawGrids();
timer = setInterval(this.run, 1000);
}
run(){
this.currentSeconds += 1;
}再在函数中swipeGrids(event)增加判断数字是否有顺序地排列好即判断游戏是否成功,循环判断当前二维数组的数值是否等于有顺序排列好的二维数组的数值即可判断游戏是否成功,当游戏成功时将isShow赋值为true,使游戏成功界面显示在最上方,并且调用函数clearInterval停止计时
swipeGrids(event) {
this.changeGrids(event.direction);
this.drawGrids();
let originalgrids=[[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 0]];
let k = 1;
for (let row = 0; row < 4; row++) {
for (let column = 0; column < 4; column++) {
if (grids[row][column] != originalgrids[row][column]){
k = 0;
}
}
}
if(k){
clearInterval(timer);
this.isShow = true;
}
}最后创建点击“重新开始”按钮所自动调用的函数restartGame(),调用函数onInit(),重新随机生成一个数字被随意打乱的4*4的方阵,将isShow赋值为false,使“游戏成功”界面隐藏,将currentSeconds置为0,将time赋值为null,调用函数onShow()重新开始计时
restartGame(){
this.onInit();
this.isShow = false;
timer = null;
this.onShow();
this.currentSeconds = 0;
}至此,index.jd文件已经全部编写完毕,整个demo也全部完成了
心得体会
本个demo整体难度不高,涉及的组件或样式都是很常见的,需要掌握栈、按钮、画布、计时器、滑动等组件即可完成编写,组件交互采用二维数组串连整个项目,十分适合刚入门的读者编写与学习,其中组件学习可以前往官方文档查看更详细的介绍:官方文档,较之第一个游戏黑白翻棋,组件虽多了一种,但算法更简单了,代码更优化,可读性更加强,建议读者在学习时可以与第一个游戏黑白翻棋对照一起学习:黑白翻棋。
结语
本次项目为博主学习了鸿蒙一些基础后自行编写完成的,感兴趣的读者可以自行跟着本博客编写,相信你们也能够完成的。如果有遇到什么问题,或者查找出其中的错误之处,欢迎留言,本博主也欢迎与各位感兴趣的读者一起学习HarmonyOS(鸿蒙)开发。
源代码
index.hml如下:
<div class="container" >
<text class="seconds">
当前秒数:{
{
currentSeconds}}
</text>
<stack class="stack">
<canvas class="canvas" ref="canvas" onswipe="swipeGrids"></canvas>
<div class="subcontainer" show="{
{isShow}}">
<text class="gameover">
游戏成功
</text>
</div>
</stack>
<input type="button" value="重新开始" class="bit" onclick="restartGame"/>
</div>index.css如下:
.container {
flex-direction: column;
justify-content: center;
align-items: center;
width:450px;
height:450px;
}
.seconds{
font-size: 18px;
text-align:center;
width:300px;
height:20px;
letter-spacing:0px;
margin-top:10px;
}
.canvas{
width:305px;
height:305px;
background-color: #FFFFFF;
}
.bit{
width:150px;
height:30px;
background-color:#AD9D8F;
font-size:24px;
margin-top:10px;
}
.stack{
width: 305px;
height: 305px;
margin-top: 10px;
}
.subcontainer {
left:50px;
top:95px;
width: 220px;
height: 130px;
justify-content: center;
align-items: center;
background-color: #E9C2A6;
}
.gameover {
font-size: 38px;
color: black;
}index.js如下:
var grids;
var context;
var timer = null;
const SIDELEN = 70;
const MARGIN = 5;
export default {
data: {
currentSeconds:0,
isShow: false
},
onInit() {
grids=[[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 0]];
this.initGrids();
this.drawGrids();
},
initGrids(){
let array=["left","up","right","down"];
for (let i = 0; i < 100; i++){
let randomIndex = Math.floor(Math.random() * 4);
let direction = array[randomIndex];
this.changeGrids(direction);
}
},
onReady() {
context = this.$refs.canvas.getContext('2d');
},
onShow() {
this.initGrids();
this.drawGrids();
timer = setInterval(this.run, 1000);
},
drawGrids() {
for (let row = 0; row < 4; row++) {
for (let column = 0; column < 4; column++) {
let gridStr = grids[row][column].toString();
context.fillStyle = "#BBADA0";
let leftTopX = column * (MARGIN + SIDELEN) + MARGIN;
let leftTopY = row * (MARGIN + SIDELEN) + MARGIN;
context.fillRect(leftTopX, leftTopY, SIDELEN, SIDELEN);
context.font = "30px HYQiHei-65S";
if (gridStr != "0") {
context.fillStyle = "#000000";
let offsetX = (4 - gridStr.length) * (SIDELEN / 8);
let offsetY = (SIDELEN - 30) / 2;
context.fillText(gridStr, leftTopX + offsetX, leftTopY + offsetY);
}
}
}
},
run(){
this.currentSeconds += 1;
},
swipeGrids(event) {
this.changeGrids(event.direction);
this.drawGrids();
let originalgrids=[[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 0]];
let k = 1;
for (let row = 0; row < 4; row++) {
for (let column = 0; column < 4; column++) {
if (grids[row][column] != originalgrids[row][column]){
k = 0;
}
}
}
if(k){
clearInterval(timer);
this.isShow = true;
}
},
changeGrids(direction) {
let x;
let y;
for (let row = 0; row < 4; row++) {
for (let column = 0; column < 4; column++) {
if (grids[row][column] == 0) {
x = row;
y = column;
break;
}
}
}
let temp;
if (direction == 'left' && (y + 1) < 4) {
temp = grids[x][y + 1];
grids[x][y + 1] = grids[x][y];
grids[x][y] = temp;
} else if (direction == 'right' && (y - 1) > -1) {
temp = grids[x][y - 1];
grids[x][y - 1] = grids[x][y];
grids[x][y] = temp;
} else if (direction == 'up' && (x + 1) < 4) {
temp = grids[x + 1][y];
grids[x + 1][y] = grids[x][y];
grids[x][y] = temp;
} else if (direction == 'down' && (x - 1) > -1) {
temp = grids[x - 1][y];
grids[x - 1][y] = grids[x][y];
grids[x][y] = temp;
}
},
restartGame(){
this.onInit();
this.isShow = false;
timer = null;
this.onShow();
this.currentSeconds = 0;
}
}内容来源于:
https://my.oschina.net/u/4837360/blog/4733357
相关推荐
- Python入门学习记录之一:变量_python怎么用变量
-
写这个,主要是对自己学习python知识的一个总结,也是加深自己的印象。变量(英文:variable),也叫标识符。在python中,变量的命名规则有以下三点:>变量名只能包含字母、数字和下划线...
- python变量命名规则——来自小白的总结
-
python是一个动态编译类编程语言,所以程序在运行前不需要如C语言的先行编译动作,因此也只有在程序运行过程中才能发现程序的问题。基于此,python的变量就有一定的命名规范。python作为当前热门...
- Python入门学习教程:第 2 章 变量与数据类型
-
2.1什么是变量?在编程中,变量就像一个存放数据的容器,它可以存储各种信息,并且这些信息可以被读取和修改。想象一下,变量就如同我们生活中的盒子,你可以把东西放进去,也可以随时拿出来看看,甚至可以换成...
- 绘制学术论文中的“三线表”具体指导
-
在科研过程中,大家用到最多的可能就是“三线表”。“三线表”,一般主要由三条横线构成,当然在变量名栏里也可以拆分单元格,出现更多的线。更重要的是,“三线表”也是一种数据记录规范,以“三线表”形式记录的数...
- Python基础语法知识--变量和数据类型
-
学习Python中的变量和数据类型至关重要,因为它们构成了Python编程的基石。以下是帮助您了解Python中的变量和数据类型的分步指南:1.变量:变量在Python中用于存储数据值。它们充...
- 一文搞懂 Python 中的所有标点符号
-
反引号`无任何作用。传说Python3中它被移除是因为和单引号字符'太相似。波浪号~(按位取反符号)~被称为取反或补码运算符。它放在我们想要取反的对象前面。如果放在一个整数n...
- Python变量类型和运算符_python中变量的含义
-
别再被小名词坑哭了:Python新手常犯的那些隐蔽错误,我用同事的真实bug拆给你看我记得有一次和同事张姐一起追查一个看似随机崩溃的脚本,最后发现罪魁祸首竟然是她把变量命名成了list。说实话...
- 从零开始:深入剖析 Spring Boot3 中配置文件的加载顺序
-
在当今的互联网软件开发领域,SpringBoot无疑是最为热门和广泛应用的框架之一。它以其强大的功能、便捷的开发体验,极大地提升了开发效率,成为众多开发者构建Web应用程序的首选。而在Spr...
- Python中下划线 ‘_’ 的用法,你知道几种
-
Python中下划线()是一个有特殊含义和用途的符号,它可以用来表示以下几种情况:1在解释器中,下划线(_)表示上一个表达式的值,可以用来进行快速计算或测试。例如:>>>2+...
- 解锁Shell编程:变量_shell $变量
-
引言:开启Shell编程大门Shell作为用户与Linux内核之间的桥梁,为我们提供了强大的命令行交互方式。它不仅能执行简单的文件操作、进程管理,还能通过编写脚本实现复杂的自动化任务。无论是...
- 一文学会Python的变量命名规则!_python的变量命名有哪些要求
-
目录1.变量的命名原则3.内置函数尽量不要做变量4.删除变量和垃圾回收机制5.结语1.变量的命名原则①由英文字母、_(下划线)、或中文开头②变量名称只能由英文字母、数字、下画线或中文字所组成。③英文字...
- 更可靠的Rust-语法篇-区分语句/表达式,略览if/loop/while/for
-
src/main.rs://函数定义fnadd(a:i32,b:i32)->i32{a+b//末尾表达式}fnmain(){leta:i3...
- C++第五课:变量的命名规则_c++中变量的命名规则
-
变量的命名不是想怎么起就怎么起的,而是有一套固定的规则的。具体规则:1.名字要合法:变量名必须是由字母、数字或下划线组成。例如:a,a1,a_1。2.开头不能是数字。例如:可以a1,但不能起1a。3....
- Rust编程-核心篇-不安全编程_rust安全性
-
Unsafe的必要性Rust的所有权系统和类型系统为我们提供了强大的安全保障,但在某些情况下,我们需要突破这些限制来:与C代码交互实现底层系统编程优化性能关键代码实现某些编译器无法验证的安全操作Rus...
- 探秘 Python 内存管理:背后的神奇机制
-
在编程的世界里,内存管理就如同幕后的精密操控者,确保程序的高效运行。Python作为一种广泛使用的编程语言,其内存管理机制既巧妙又复杂,为开发者们提供了便利的同时,也展现了强大的底层控制能力。一、P...
- 一周热门
- 最近发表
- 标签列表
-
- HTML 教程 (33)
- HTML 简介 (35)
- HTML 实例/测验 (32)
- HTML 测验 (32)
- JavaScript 和 HTML DOM 参考手册 (32)
- HTML 拓展阅读 (30)
- HTML文本框样式 (31)
- HTML滚动条样式 (34)
- HTML5 浏览器支持 (33)
- HTML5 新元素 (33)
- HTML5 WebSocket (30)
- HTML5 代码规范 (32)
- HTML5 标签 (717)
- HTML5 标签 (已废弃) (75)
- HTML5电子书 (32)
- HTML5开发工具 (34)
- HTML5小游戏源码 (34)
- HTML5模板下载 (30)
- HTTP 状态消息 (33)
- HTTP 方法:GET 对比 POST (33)
- 键盘快捷键 (35)
- 标签 (226)
- opacity 属性 (32)
- transition 属性 (33)
- 1-1. 变量声明 (31)
