近教學過程中需要實現form表單中的input文本框在用戶點擊按鈕時自動生成新的文本框,在完成數據填寫之后通過ajax批量將填寫的信息存儲到數據庫中。每一行文本框對應數據庫表中的記錄。初始狀態如下圖:
文本框組合(行)
如上圖,前端用戶需要借助文本框批量提交數據,每一行有5個文本框,對應后臺表中的一條記錄。用戶可填寫數據,完成填寫后點擊添加,頁面自動添加新的一行文本框。效果如下:
動態文本框行添加生成效果
上圖給出了點擊添加之后的新效果,整個文檔HTML代碼描述如下:
表單代碼
代碼描述如上,文本框以label標簽為基礎進行分組,每5個為一行,所有的input文本框具有相同的class名稱。
針對待解決的問題,設計采用JavaScript DOM文檔對象模型提供的方法,將表單看成結點,調用附加結點方法實現動態結點的添加。主要涉及使用到的方法函數如下:
(1) getElementById()方法
獲取元素(結點)函數,通過使用HTML標記對應的ID標簽值獲取該元素,返回元素對象,可進一步執行元素的操作。
(2) createElement()方法
創建結點元素方法,該方法用于實現動態創建新結點元素,為下一步添加新結點奠定基礎。
(3) setAttribute()方法
該方法主要用于實現結點屬性的設置,函數需要提供兩個參數,分別為屬性名稱與屬性值。
(4) appendChild()方法
附加結點方法,該方法主要用于將新創建結點附加到指定結點的尾部。
(5) getElementsByClassName()方法
該方法主要用于返回HTML文檔中具有相同Class名字的一組元素的集合,并可通過下標訪問其中的每一個元素。
為將前端表單文本框組合與數據表中行對應,涉及采用插入數據類insetv實現對每一行文本框數據進行存儲。該類設計描述如下:
行數據(記錄)類
每一行使用實例化的insetv進行數據存儲,針對多行的情況,設計采用數組對每一行進行存儲。即數組的每一個元素都是insetv對象。最終實現數組按照數據行對填寫信息進行存儲。然后自定義兩個按鈕的onclick消息響應函數,實現存儲數據與動態表格生成。其中addRow用于生成新的行,該函數實現代碼描述如下:
添加文本框(行)函數
定義insert方法用于獲取表單所有文本框填寫的信息,并采用數組對獲取的信息進行存儲,數組每一個元素為insetv對象,對應每一條記錄。Insert方法實現描述如下圖所示:
插入數據操作函數
本例所有的文本框行都是JS編碼實現,因此需要在window對象的onload實踐中調用addRows方法實現初始化時生成第一行。實現代碼如下:
初始化首行函數
為方便測試演示與展示,我們將獲取的數據直接在本頁面進行展示,實際測試過程描述如下動圖所示:
動態實現效果展示
在插入操作過程我們使用console.log()對輸入數據對應數組進行了控制臺的輸出。輸出結果如下:
數據獲取存儲結果
本頭條號長期關注編程資訊分享;編程課程、素材、代碼分享及編程培訓。如果您對以上方面有興趣或代碼錯誤、建議與意見,可以聯系作者,共同探討。期待大家關注!如需案例完整代碼請關注并私信,該案例相關文章鏈接如下:
前端開發-拼圖游戲(N數碼問題)A*算法智能求解效果展示
前端設計-JavaScript美女拼圖游戲開發實例
前端設計-教你如何快速繪制HTML5動畫
在本文中,我們將與大家分享 10個最佳的極簡 CSS 框架,它們能夠為你提供建站必備的組件,幫助你節省時間。
希望對大家有所幫助!
一、Spectre(一個輕量級、響應式的現代 CSS 框架,用于快速建站和擴展程序的開發。它通過最佳編碼實踐和一致性的設計語言,為排版與元素、基于 Flexbox 的響應布局系統、CSS 組件提供了基本樣式。)
二、Milligram(提供了極簡樣式設置,便于你快速、簡潔的開啟建站之旅。雖然它不是一個 UI 框架,但它的設計理念卻是以提供優秀的性能、高效的開發效率以及最少的屬性重置而構建的。同時,它也是輕量的)
三、Mobi(是一個輕量級、可擴展、移動優先的 CSS 框架。它專注于細節,對于內容豐富的網頁能夠提供優質的用戶體驗。雖然,它專注移動端,但桌面客戶端的體驗也是很棒的。)
四、Mini(作為一個 Gzip 壓縮后不到 7KB 大小的極簡框架,它具備響應式、易用性和定制性等特性,旨在為你提供盡可能多的功能。由于它是輕量框架,不僅讓你創建的網站和應用程序具備更快的加載速度,而且它所提供的組件可以滿足基本的開發要求。)
五、 Siimple(是一個助你打造扁平化網站風格的輕量、響應式的開源框架。它內置了 SASS / SCSS,為你的網頁設計提供了簡潔的開始。)
六、Base(一個穩固的響應式 HTML 與 CSS 框架。)
七、Scooter(專注為 Dropbox 提供基礎樣式、CSS 組件以及快速靜態原型的 SCSS 框架。)
八、Responsive(一個功能強大、對開發人員友好的,用于構建響應式網站的輕量級前端框架。)
九、 拼圖 Pintuer (國內優秀的HTML、CSS、JS跨屏響應式開源前端框架,使用最新瀏覽器技術,為快速的前端開發提供一系統的文本、圖標、媒體、表格、表單、按鈕、菜單、網格系統等樣式工具包,占用資源小,使用拼圖可以快速構建簡潔、優雅而且自動適應手機、平板、桌面電腦等設備的前端界面,讓前端開發像玩游戲一下快樂而輕松。)
十、 BluCSS (是一個簡便易記的CSS框架。可輕松應用在項目中。)
相信大家都會自己心中最喜歡的工具,如果本文沒有列舉出來,歡迎大家在評論區留下自己心目中最喜歡、最有價值的工具~~
切圖 qietu(.com)
學lufylegend.js之日,我用lufylegend.js開發了第一個HTML5小游戲——拼圖游戲,還寫了篇博文來炫耀一下:HTML5小游戲《智力大拼圖》發布,挑戰你的思維風暴。不過當時初學游戲開發,經驗淺薄,所以沒有好好專研游戲里的算法和代碼的缺陷,導致游戲出現了很多bug,甚至拼圖打亂后很可能無法復原。最近經常有朋友問起這個游戲,希望我能把代碼里的bug改一下方便初學者學習,順便我也打算測試一下自己寫這種小游戲的速度,所以就抽出了一些時間將這個游戲從頭到尾重新寫了一遍,計算了一下用時,從準備、修改素材到最后完成游戲,一共用了大約2h的時間。
以下是游戲地址:
由于頭條禁止在文章頁面加入鏈接,大家私信我“拼圖”即可獲取下載地址。
這是我的游戲記錄,歡迎各位挑戰:
接下來就來講講如何開發完成這款游戲的。(按“編年體”)
準備lufylegend游戲引擎,大家可以去官方網站下載:
由于頭條禁止在文章頁面加入鏈接,大家私信我“拼圖”即可獲取下載地址。
引擎文檔地址:
由于頭條禁止在文章頁面加入鏈接,大家私信我“拼圖”即可獲取下載地址。
可以說,如果沒有強大的lufylegend引擎,這種html5小游戲用原生canvas制作,少說要一天呢。
準備素材(10min) + 修改素材(20min)。由于在下實在手殘,不善于P圖,修改圖片用了大約20min,囧……
開發開始界面。游戲不能沒有開始界面所以我們首先實現這部分代碼。在此之前是index.html里的代碼,代碼如下:
<!DOCTYPE html>
<html>
<head>
<title>Puzzle</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
<script type="text/javascript" src="./lib/lufylegend-1.10.1.simple.min.js"></script>
<script type="text/javascript" src="./js/Main.js"></script>
</head>
<body style="margin: 0px; font-size: 0px; background: #F2F2F2;">
<div id="mygame"></div>
</body>
</html>
主要是引入一些js文件,不多說。然后準備一個Main.js文件,在這個文件里添加初始化界面和加載資源的代碼:
/** 初始化游戲 */
LInit(60, "mygame", 390, 580, main);
var imgBmpd;
/** 游戲層 */
var stageLayer, gameLayer, overLayer;
/** 拼圖塊列表 */
var blockList;
/** 是否游戲結束 */
var isGameOver;
/** 用時 */
var startTime, time, timeTxt;
/** 步數 */
var steps, stepsTxt;
function main () {
/** 全屏設置 */
if (LGlobal.mobile) {
LGlobal.stageScale=LStageScaleMode.SHOW_ALL;
}
LGlobal.screen(LGlobal.FULL_SCREEN);
/** 添加加載提示 */
var loadingHint=new LTextField();
loadingHint.text="資源加載中……";
loadingHint.size=20;
loadingHint.x=(LGlobal.width - loadingHint.getWidth()) / 2;
loadingHint.y=(LGlobal.height - loadingHint.getHeight()) / 2;
addChild(loadingHint);
/** 加載圖片 */
LLoadManage.load(
[
{path : "./js/Block.js"},
{name : "img", path : "./images/img.jpg"}
],
null,
function (result) {
/** 移除加載提示 */
loadingHint.remove();
/** 保存位圖數據,方便后續使用 */
imgBmpd=new LBitmapData(result["img"]);
gameInit();
}
);
}
function gameInit (e) {
/** 初始化舞臺層 */
stageLayer=new LSprite();
stageLayer.graphics.drawRect(0, "", [0, 0, LGlobal.width, LGlobal.height], true, "#EFEFEF");
addChild(stageLayer);
/** 初始化游戲層 */
gameLayer=new LSprite();
stageLayer.addChild(gameLayer);
/** 初始化最上層 */
overLayer=new LSprite();
stageLayer.addChild(overLayer);
/** 添加開始界面 */
addBeginningUI();
}
以上代碼有詳細注釋,大家可以對照引擎文檔和注釋進行閱讀。有些全局變量會在以后的代碼中使用,大家可以先忽略。接下來是addBeginningUI函數里的代碼,用于實現開始界面:
function addBeginningUI () {
var beginningLayer=new LSprite();
beginningLayer.graphics.drawRect(0, "", [0, 0, LGlobal.width, LGlobal.height], true, "#EDEDED");
stageLayer.addChild(beginningLayer);
/** 游戲標題 */
var title=new LTextField();
title.text="拼圖游戲";
title.size=50;
title.weight="bold";
title.x=(LGlobal.width - title.getWidth()) / 2;
title.y=160;
title.color="#FFFFFF";
title.lineWidth=5;
title.lineColor="#000000";
title.stroke=true;
beginningLayer.addChild(title);
/** 開始游戲提示 */
var hint=new LTextField();
hint.text="- 點擊屏幕開始游戲 -";
hint.size=25;
hint.x=(LGlobal.width - hint.getWidth()) / 2;
hint.y=370;
beginningLayer.addChild(hint);
/** 開始游戲 */
beginningLayer.addEventListener(LMouseEvent.MOUSE_UP, function () {
beginningLayer.remove();
startGame();
});
}
到此,運行代碼,得到我們的開始界面:
看到這個畫面,其實我自己都想吐槽一下實在是太“樸素”了,囧……
不過我這次圖個制作速度,所以還望各位看官海量。
這40分鐘的時間,是最關鍵時期,期間我們要完成整個游戲的主體部分。首先,我們需要用代碼來實現以下過程:
初始化游戲界面數據(如游戲時間、所用步數)和顯示一些UI部件(如圖樣)
|
-> 獲取隨機的拼圖塊位置
|
-> 顯示打亂后的拼圖塊
我們將這些步驟做成一個個的函數方便我們統一調用:
function startGame () {
isGameOver=false;
/** 初始化時間和步數 */
startTime=(new Date()).getTime();
time=0;
steps=0;
/** 初始化拼圖塊列表 */
initBlockList();
/** 打亂拼圖 */
getRandomBlockList();
/** 顯示拼圖 */
showBlock();
/** 顯示縮略圖 */
showThumbnail();
/** 顯示時間 */
addTimeTxt();
/** 顯示步數 */
addStepsTxt();
stageLayer.addEventListener(LEvent.ENTER_FRAME, onFrame);
}
函數一開始,我們把isGameOver變量設定為false代表游戲未結束,在后期的代碼里,我們會看到這個變量的作用。接著我們初始化了用于表示時間和步數的time和steps這兩個全局變量,另外初始化變量startTime的值用于后面計算游戲時間。
接下來,我們就要開始初始化拼圖塊了。見initBlockList里的代碼:
function initBlockList () {
blockList=new Array();
for (var i=0; i < 9; i++) {
/** 根據序號計算拼圖塊圖片顯示位置 */
var y=(i / 3) >>> 0, x=i % 3;
blockList.push(new Block(i, x, y));
}
}
這里我們使用了一個Block類,這個類用于顯示拼圖塊和儲存拼圖塊的數據,并提供了一些方法來操控拼圖塊,下面是其構造器的代碼:
function Block (index, x, y) {
LExtends(this, LSprite, []);
var bmpd=imgBmpd.clone();
bmpd.setProperties(x * 130, y * 130, 130, 130);
this.bmp=new LBitmap(bmpd);
this.addChild(this.bmp);
var border=new LShape();
border.graphics.drawRect(3, "#CCCCCC", [0, 0, 130, 130]);
this.addChild(border);
this.index=index;
this.addEventListener(LMouseEvent.MOUSE_UP, this.onClick);
}
Block類繼承自LSprite,屬于一個顯示對象,所以我們在這個類中添加了一個位圖對象用于顯示拼圖塊對應的圖片。除此之外,我們還為拼圖塊添加了一個邊框,在顯示時用于隔開周圍的拼圖塊。Block類有一個index屬性,代表拼圖塊在拼圖塊列表blockList中的正確位置。最后,我們為此類添加了一個鼠標按下事件,用于處理鼠標按下后移動圖塊操作。
接下來我們還要介紹這個類的一個方法setLocation:
Block.prototype.setLocation=function (x, y) {
this.locationX=x;
this.locationY=y;
this.x=x * 130;
this.y=y * 130;
};
這個方法用于設置拼圖塊對象的顯示位置以及保存拼圖塊的“數組位置”。什么是“數組位置”呢?各位看官可以通過下面的圖片加以了解:
可以看到,“數組位置”就類似于二維數組中的元素下標。儲存這個位置的作用在于可以很方便地從blockList中獲取到附近的其他拼圖塊。這個方法在我們顯示拼圖時有調用到,在顯示拼圖之前,我們得先打亂拼圖,見如下代碼:
function getRandomBlockList () {
/** 隨機打亂拼圖 */
blockList.sort(function () {
return 0.5 - Math.random();
});
/** 計算逆序和 */
var reverseAmount=0;
for (var i=0, l=blockList.length; i < l; i++) {
var currentBlock=blockList[i];
for (var j=i + 1; j < l; j++) {
var comparedBlock=blockList[j];
if (comparedBlock.index < currentBlock.index) {
reverseAmount++;
}
}
}
/** 檢測打亂后是否可還原 */
if (reverseAmount % 2 !=0) {
/** 不合格,重新打亂 */
getRandomBlockList();
}
}
打亂拼圖部分直接用數組的sort方法進行隨機打亂:
blockList.sort(function () {
return 0.5 - Math.random();
});
其實打亂算法有很多種,我這里采用最粗暴的方法,也就是隨機打亂。這種算法簡單是簡單,壞在可能出現無法復原的現象。針對這個問題,就有配套的檢測打亂后是否可還原的算法,具體的算法理論我借用lufy大神的評論:
此類游戲能否還原關鍵是看它打亂后的逆序次數之和是否為偶數
假設你打亂后的數組中的每一個小圖塊為obj0,obj1,obj2,…它們打亂之前的序號分別為obj0.num,obj1.num…
接下來循環數組,如果前面元素的序號比此元素后某個元素的序號大,如obj0.num > obj1.num或者obj2.num > obj4.num就表示一個逆序
當全部的逆序之和為奇數時表示不可還原,重新打亂即可,打亂后重新檢測,直到逆序之和為偶數為止
舉個例子,如果有一個數組為[3, 4, 2, 1],那么里面3 2, 3 1, 2 4, 4 1, 2 1是逆序的,所以逆序數是5。
上面我給出的getRandomBlockList里的代碼就是在實現打亂算法和檢測是否可還原算法。
還有一種打亂方式,大家可以嘗試嘗試:和復原拼圖一樣,將空白塊一步一步地與周圍的拼圖隨機交換順序。這個打亂算法較上一種而言,不會出現無法復原的現象,而且可以根據打亂的步數設定游戲難度。
在完成打亂拼圖塊后,如期而至的是顯示拼圖塊:
function showBlock() {
for (var i=0, l=blockList.length; i < l; i++) {
var b=blockList[i];
/** 根據序號計算拼圖塊位置 */
var y=(i / 3) >>> 0, x=i % 3;
b.setLocation(x, y);
gameLayer.addChild(b);
}
}
顯示了拼圖塊后,我們要做的就是添加操作拼圖塊的功能。于是需要拓展Block類,為其添加事件監聽器onClick方法:
Block.prototype.onClick=function (e) {
var self=e.currentTarget;
if (isGameOver) {
return;
}
var checkList=new Array();
/** 判斷右側是否有方塊 */
if (self.locationX > 0) {
checkList.push(Block.getBlock(self.locationX - 1, self.locationY));
}
/** 判斷左側是否有方塊 */
if (self.locationX < 2) {
checkList.push(Block.getBlock(self.locationX + 1, self.locationY));
}
/** 判斷上方是否有方塊 */
if (self.locationY > 0) {
checkList.push(Block.getBlock(self.locationX, self.locationY - 1));
}
/** 判斷下方是否有方塊 */
if (self.locationY < 2) {
checkList.push(Block.getBlock(self.locationX, self.locationY + 1));
}
for (var i=0, l=checkList.length; i < l; i++) {
var checkO=checkList[i];
/** 判斷是否是空白拼圖塊 */
if (checkO.index==8) {
steps++;
updateStepsTxt();
Block.exchangePosition(self, checkO);
break;
}
}
};
首先,我們在這里看到了isGameOver全局變量的作用,即在游戲結束后,阻斷點擊拼圖塊后的操作。
在點擊了拼圖塊后,我們先獲取該拼圖塊周圍的拼圖塊,并將它們裝入checkList,再遍歷checkList,當判斷到周圍有空白拼圖塊后,即周圍有index屬性等于8的拼圖塊后,先更新操作步數,然后將這兩個拼圖塊交換位置。具體交換拼圖塊位置的方法詳見如下代碼:
Block.exchangePosition=function (b1, b2) {
var b1x=b1.locationX, b1y=b1.locationY,
b2x=b2.locationX, b2y=b2.locationY,
b1Index=b1y * 3 + b1x,
b2Index=b2y * 3 + b2x;
/** 在地圖塊數組中交換兩者位置 */
blockList.splice(b1Index, 1, b2);
blockList.splice(b2Index, 1, b1);
/** 交換兩者顯示位置 */
b1.setLocation(b2x, b2y);
b2.setLocation(b1x, b1y);
/** 判斷游戲是否結束 */
Block.isGameOver();
};
還有就是Block.getBlock靜態方法,用于獲取給定的“數組位置”下的拼圖塊:
Block.getBlock=function (x, y) {
return blockList[y * 3 + x];
};
在Block.exchangePosition中,我們通過Block.isGameOver判斷玩家是否已將拼圖復原:
Block.isGameOver=function () {
var reductionAmount=0, l=blockList.length;
/** 計算還原度 */
for (var i=0; i < l; i++) {
var b=blockList[i];
if (b.index==i) {
reductionAmount++;
}
}
/** 計算是否完全還原 */
if (reductionAmount==l) {
/** 游戲結束 */
gameOver();
}
};
到這里,我們就實現了打亂和操作拼圖塊部分。
最后30min用于細枝末節上的處理,如顯示拼圖縮略圖、顯示&更新時間和步數,以及添加游戲結束畫面,這些就交給如下冗長而簡單的代碼來完成吧:
function showThumbnail() {
var thumbnail=new LBitmap(imgBmpd);
thumbnail.scaleX=130 / imgBmpd.width;
thumbnail.scaleY=130 / imgBmpd.height;
thumbnail.x=(LGlobal.width - 100) /2;
thumbnail.y=410;
overLayer.addChild(thumbnail);
}
function addTimeTxt () {
timeTxt=new LTextField();
timeTxt.stroke=true;
timeTxt.lineWidth=3;
timeTxt.lineColor="#54D9EF";
timeTxt.color="#FFFFFF";
timeTxt.size=18;
timeTxt.x=20;
timeTxt.y=450;
overLayer.addChild(timeTxt);
updateTimeTxt();
}
function updateTimeTxt () {
timeTxt.text="時間:" + getTimeTxt(time);
}
function getTimeTxt () {
var d=new Date(time);
return d.getMinutes() + " : " + d.getSeconds();
};
function addStepsTxt () {
stepsTxt=new LTextField();
stepsTxt.stroke=true;
stepsTxt.lineWidth=3;
stepsTxt.lineColor="#54D9EF";
stepsTxt.color="#FFFFFF";
stepsTxt.size=18;
stepsTxt.y=450;
overLayer.addChild(stepsTxt);
updateStepsTxt();
}
function updateStepsTxt () {
stepsTxt.text="步數:" + steps;
stepsTxt.x=LGlobal.width - stepsTxt.getWidth() - 20;
}
function onFrame () {
if (isGameOver) {
return;
}
/** 獲取當前時間 */
var currentTime=(new Date()).getTime();
/** 計算使用的時間并更新時間顯示 */
time=currentTime - startTime;
updateTimeTxt();
}
function gameOver () {
isGameOver=true;
var resultLayer=new LSprite();
resultLayer.filters=[new LDropShadowFilter()];
resultLayer.graphics.drawRoundRect(3, "#BBBBBB", [0, 0, 350, 350, 5], true,"#DDDDDD");
resultLayer.x=(LGlobal.width - resultLayer.getWidth()) / 2;
resultLayer.y=LGlobal.height / 2;
resultLayer.alpha=0;
overLayer.addChild(resultLayer);
var title=new LTextField();
title.text="游戲通關"
title.weight="bold";
title.stroke=true;
title.lineWidth=3;
title.lineColor="#555555";
title.size=30;
title.color="#FFFFFF";
title.x=(resultLayer.getWidth() - title.getWidth()) / 2;
title.y=30;
resultLayer.addChild(title);
var usedTimeTxt=new LTextField();
usedTimeTxt.text="游戲用時:" + getTimeTxt(time);
usedTimeTxt.size=20;
usedTimeTxt.stroke=true;
usedTimeTxt.lineWidth=2;
usedTimeTxt.lineColor="#555555";
usedTimeTxt.color="#FFFFFF";
usedTimeTxt.x=(resultLayer.getWidth() - usedTimeTxt.getWidth()) / 2;
usedTimeTxt.y=130;
resultLayer.addChild(usedTimeTxt);
var usedStepsTxt=new LTextField();
usedStepsTxt.text="所用步數:" + steps;
usedStepsTxt.size=20;
usedStepsTxt.stroke=true;
usedStepsTxt.lineWidth=2;
usedStepsTxt.lineColor="#555555";
usedStepsTxt.color="#FFFFFF";
usedStepsTxt.x=usedTimeTxt.x;
usedStepsTxt.y=180;
resultLayer.addChild(usedStepsTxt);
var hintTxt=new LTextField();
hintTxt.text="- 點擊屏幕重新開始 -";
hintTxt.size=23;
hintTxt.stroke=true;
hintTxt.lineWidth=2;
hintTxt.lineColor="#888888";
hintTxt.color="#FFFFFF";
hintTxt.x=(resultLayer.getWidth() - hintTxt.getWidth()) / 2;
hintTxt.y=260;
resultLayer.addChild(hintTxt);
LTweenLite.to(resultLayer, 0.5, {
alpha : 0.7,
y : (LGlobal.height - resultLayer.getHeight()) / 2,
onComplete : function () {
/** 點擊界面重新開始游戲 */
stageLayer.addEventListener(LMouseEvent.MOUSE_UP, function () {
gameLayer.removeAllChild();
overLayer.removeAllChild();
stageLayer.removeAllEventListener();
startGame();
});
}
});
}
Ok,2h下來,整個游戲就搞定咯~不得不表揚一下lufylegend這個游戲引擎,實在是可以大幅提升開發效率。
最后奉上源代碼:
由于頭條禁止在文章頁面加入鏈接,大家私信我“拼圖”即可獲取下載地址。
這篇博文在最初寫成的時候,我沒有對逆序算法進行深入研究,再加上我的測試不仔細,我沒有發現算法的錯誤之處。因此,在博文發布后,不少讀者發現游戲無解現象并將此問題反饋給了我,經過網友熱心幫助,我才找到了問題所在,并更正了算法。在此對這些熱心的網友表示真心的感謝,也為我學習不深入,以及誤導了不少讀者而感到十分內疚自責。
如果大家對本文有任何意見或不解,歡迎留言~
*請認真填寫需求信息,我們會在24小時內與您取得聯系。