網頁播放器開發(四)代碼精煉提純

来源:https://www.cnblogs.com/agoodlife/archive/2019/04/20/10741432.html
-Advertisement-
Play Games

四、精簡提煉 我們的播放器基本實現了,但是代碼復用不高,所以我們要進行封裝,以插件的形式體現。 1.插件的基本運行代碼如下: 上述代碼就是基本的插件代碼,下麵詳細記錄這段代碼所表示的意思。 前面的分號,可以解決插件與其它js合併時,別的代碼可能會產生的錯誤問題; “(function(){})()” ...


四、精簡提煉

我們的播放器基本實現了,但是代碼復用不高,所以我們要進行封裝,以插件的形式體現。

1.插件的基本運行代碼如下: 

;(function(undefined){

'use strict';

... ...

})()

 

 上述代碼就是基本的插件代碼,下麵詳細記錄這段代碼所表示的意思。

前面的分號,可以解決插件與其它js合併時,別的代碼可能會產生的錯誤問題;

“(function(){})()”這個結構表示立即執行第一個括弧內的函數,其實立即執行函數還有另一種寫法,“(function(){}())”。看大家的喜好,我一般喜歡用第一種;

“undefined”做為參數傳入,因為在老一輩的瀏覽器是不被支持的,直接使用會報錯,js框架要考慮到相容性,因此增加一個形參undefined,就算有人把外面的 undefined 定義了,插件裡面的 undefined 依然不受影響。

嚴格模式開發

下麵進一步補充代碼函數內代碼:

'use strict';

這行代碼表示嚴格模式,顧名思義,嚴格模式就是使得 Javascript 在更嚴格的條件下運行,有助於我們更規範的開發。如果在語法檢測時發現語法問題,則整個代碼塊失效,並導致一個語法異常。如果在運行期出現了違反嚴格模式的代碼,則拋出執行異常。

定義我們的播放器插件“playMythology”

下麵我們真正開始我們的插件代碼了,目前整個代碼如下:

;(function(undefined){
'use strict';
var _global;
function playMythology(opt) {
... ...
}
playMythology.prototype = {};
//將插件對象暴露給全局對象
_global = (function() {
return this || (0, eval)('this');
}());
if (typeof module !== "undefined" && module.exports) {
module.exports = playMythology;
} else if (typeof define === "function" && define.amd) {
define(function() {
return playMythology;
});
} else {
!('playMythology' in _global) && (_global.playMythology = playMythology);
}
})()

 

定義“_global”,並把全局環境賦值給一個_global。

並把當前頂級對象賦值給這個變數,代碼如下:

_global = (function() {
return this || (0, eval)('this');
}());

 

看這段代碼又是個立即執行函數,不是上面提到的第一種的立即執行函數,而是這種第二種立即執行函數:(functiong(){})結構;首先先介紹一下eval()函數的作用:eval() 函數計算 JavaScript 字元串,並把它作為腳本代碼來執行如果參數是一個表達式,eval() 函數將執行表達式如果參數是Javascript語句,eval()將執行 Javascript 語句。然後在逐一分析語句:return this表示返回當前對象;第一個括弧內的逗號操作符 對它的每個操作數求值(從左到右),並返回最後一個操作數的值那麼這個(0, eval)('this')相當於evalthis’),那麼為什麼不用evalthis’),而用(0, eval)('this')呢?在嚴格模式下,如果沒有給 this指定值的話,它就是未定義的為了防止在嚴格模式下window變數被賦予undefined,使用(0, eval)(this)就可以把this重新指向全局環境對象因為(0, eval)(this)通過逗號表達式對它的操作數執行了GetValue,計算出一個值this的值指向了全局對象eval(‘this’)計算出的是一個引用是一個直接調用,方法中的this值是obj的引用

 

定義“playMythology”,表示我們插件的名稱。然後我們給這個函數添加屬性,通過prototype來添加,簡單解釋一下prototype是函數的一個屬性,並且是函數的原型對象。prototype只能夠被函數調用

為了實現插件的模塊化並且讓我們的插件也是一個模塊,就得讓我們的插件也實現模塊化的機制。要判斷是否存在載入器,如果存在載入器,我們就使用載入器,如果不存在載入器。我們就使用頂級域對象。下麵代碼就實現了這個功能

if (typeof module !== "undefined" && module.exports) {

module.exports = playMythology;

} else if (typeof define === "function" && define.amd) {

define(function() {

return playMythology;

});

} else {

!('playMythology' in _global) && (_global.playMythology = playMythology);

}

 

 

介紹一下主要的運算符:==”表示相等;“===表示絕對相等“!=”表示不相等;“!==”,表示嚴格不相等JavaScript中,unllundefined並不相同但是null==undefined為真,null===undefined為假,所以null !== undefined 為真。

“typeof ”表示返回數據類型,2種使用方式:typeof(表達式)typeof 變數名,第一種是對錶達式做運算,第二種是對變數做運算。回類型為字元串,值包括如下幾種:

       1. 'undefined'              --未定義的變數或值

        2. 'boolean'                 --布爾類型的變數或值

        3. 'string'                     --字元串類型的變數或值

        4. 'number'                  --數字類型的變數或值

        5. 'object'                    --對象類型的變數或值,或者null(這個是js歷史遺留問題,將null作為object類型處理)

        6. 'function'                 --函數類型的變數或值module.exports 對象是由模塊系統創建的。在我們自己寫模塊的時候,需要在模塊最後寫好模塊介面,聲明這個模塊對外暴露什麼內容,module.exports 提供了暴露介面的方法。這種方法可以返回全局共用的變數或者方法。

介紹一下AMD,AMD是一種規範就是其中比較著名一個,全稱是Asynchronous Module Definition,即非同步模塊載入機制。從它的規範描述頁面看,AMD很短也很簡單,但它卻完整描述了模塊的定義,依賴關係,引用關係以及載入機制。感興趣的朋友可以認真研究一下,requireJSNodeJsDojoJQuery全部在使用,可見它的價值

 

2.基本函數

引入CSS文件函數:前端開發引入CSS文件是必不可少的,css主要功能是對頁面佈局進行美化,我希望開發的插件的皮膚可以動態設置,所以要動態引入CSS文件,定義了引入CSS文件函數,具體代碼如下:

//path表示引入CSS文件路徑

function cssinto(path) {

//如果CSS文件錯誤,拋出錯誤異常

if (!path || path.length === 0) {

throw new Error('argument "path" is required !');

}

//獲取head 對象

var head = document.getElementsByTagName('head')[0];

//創建link標簽並插入到head標簽內

var link = document.createElement('link');

link.href = path;

link.rel = 'stylesheet';

link.type = 'text/css';

head.appendChild(link);

}

 

時間轉換函數:主要功能,講audio currentTime 時間戳轉換轉化成“分:秒”顯示格式。

//path表示引入CSS文件路徑

//時間顯示轉換

function conversion(value) {

let minute = Math.floor(value / 60)

minute = minute.toString().length === 1 ? ('0' + minute) : minute

let second = Math.round(value % 60)

second = second.toString().length === 1 ? ('0' + second) : second

return minute+":"+second

}

 

引入json文件函數:file值json文件路徑,callback只得是回調函數,當文件載入完畢就調用該函數。

function readTextFile(file, callback) {

var rawFile = new XMLHttpRequest();

rawFile.overrideMimeType("application/json");

rawFile.open("GET", file, true);

rawFile.onreadystatechange = function() {

if (rawFile.readyState === 4 && rawFile.status == "200") {

callback(rawFile.responseText);

}

}

rawFile.send(null);

}

 

getElementsByClass因為我們未講window傳入插件,所以有些方法我們是不能使用的,所以我們定義下麵方法實現,通過class查找html中dom對象。

//判斷插件是否存在“getElementsByClass”,沒存在,將使用下麵方法實現該功能。

if (!('getElementsByClass' in HTMLElement)) {

//prototype在前面已經提到過了,通過“prototype”給HTMLElement添加屬性方法“getElementsByClass”

HTMLElement.prototype.getElementsByClass = function(n) {

var el = [],

_el = this.getElementsByTagName('*');

for (var i = 0; i < _el.length; i++) {

if (!!_el[i].className && (typeof _el[i].className == 'string') && _el[i].className.indexOf(n) > -1) {

el[el.length] = _el[i];

}

}

return el;

};

((typeof HTMLDocument !== 'undefined') ? HTMLDocument : Document).prototype.getElementsByClass = HTMLElement.prototype

.getElementsByClass;

}

 

參數合併函數: 對象合併,這個主要用於插件預設參數賦值操作,如果設置就使用新的參數,如果不設置就使用預設參數

//表示原有參數,n表示新參數,override表示是否進行覆蓋

function extend(o, n, override) {

for (var key in n) {

if (n.hasOwnProperty(key) && (!o.hasOwnProperty(key) || override)) {

o[key] = n[key];

}

}

return o;

}

 

3.基本功能

參數初始化,裡面有詳細的註釋。

_initial: function(opt) {

// 預設參數

var def = {

skinID: "default", //預設皮膚路徑

domID: "musicbox" //設置播放器容器ID

};

//如果函數初始化時,設置參數時,進行合併,如果沒有設置使用預設參數

this.def = extend(def, opt, true);

//用於JSON文件存儲數據

this.data = {};

//播放器初始音量為0.3

this.sound = 0.3;

this.currentID = 0;

//創建audion

this.audion = document.createElement("AUDIO");

//獲取播放器dom對象

this.dom = document.getElementById(def.domID);

//播放器初始音量

this.audion.volume = this.sound;

//定義定時器,用於進度條調整,歌曲滾動等功能

this.timecolick;

//歌曲容器

this.songBox;

//播放器狀態,0表示順序播放;1表示迴圈播放;2表示隨機播放。

this.isPlayState = 0;

//歌曲列表用於存儲歌曲數據

this.songList;

//歌曲播放進度條

this.songProgress;

//播放進度條上的播放頭

this.songPlayHead;

//判斷歌曲是否允許滾動,0表示允許,1表示不允許

this.isSlide = 0;

//播放進度,0表示初始位置

this.playprogress = 0;

//最大

this.playMax = 0;

//播放器是否在播放,0表示正在播放,1表示暫停

this.isPlaying = 0;

//歌曲列表滾動距離

this.scollHeight = 20;

//初始化播放器,並開始播放

this._GetData();

},

 

播放器界面初始化,並播放歌曲

//設置播放器界面

var _this = this;//把當前對象存到_this

//初始化CSS文件

cssinto("skin/" + this.def.skinID + "/css/music.css");

//讀取json數據

readTextFile("skin/" + this.def.skinID + "/data.json", function(text) {

//數據讀取到data

_this.data = JSON.parse(text);

//把界面HTML代碼插入容器,界面初始化

_this.dom.innerHTML = _this.data[0].MusicHtml;

//設置歌曲列表

var htmlinsert = "";

//過去歌曲容器dom對象

_this.songBox = _this.dom.getElementsByClass(_this.data[0].musiclistbox)[0];

//存儲歌曲數據

_this.songList = _this.data[0].Songlist;

for (var i = 0; i < _this.songList.length; i++) {

htmlinsert += '<li><span>' + _this.songList[i].songname + '</span></li>';

}

_this.songBox.innerHTML = htmlinsert;

//設置音樂列表單擊事件

for (var i = 0; i < _this.songBox.childNodes.length; i++) {

(

function(j) {

_this.songBox.childNodes[j].onclick = function() {

_this._PlaySong(j);

}

})(i)

}

//所有數據載入完畢,開始播放歌曲

_this._PlaySong(0);

 

暫停播放功能。

//播放停止按鈕事件 _this.dom.getElementsByClass(_this.data[0].playBT)[0].onclick = function(e) {

//如果正在播放則停止播放

if (_this.isPlaying == 0) {

this.className = "playbutton";

_this.isPlaying = 1;

_this.audion.pause()

} else //如果停止播放則開始播放

{

this.className = "pausebutton";

_this.isPlaying = 0;

_this.audion.play();

}

}

 

 

歌曲切換功能,上一首,下一首切換。

//上一首按鈕

_this.dom.getElementsByClass(_this.data[0].preBton)[0].onclick = function(e) {

if (_this.currentID > 0) {

_this.currentID--;

} else {

_this.currentID = _this.songList.length - 1;

}

_this._PlaySong(_this.currentID)

}

//下一首按鈕

_this.dom.getElementsByClass(_this.data[0].nextBton)[0].onclick = function(e) {

if (_this.currentID < _this.songList.length - 1) {

_this.currentID++;

} else {

_this.currentID = 0;

}

_this._PlaySong(_this.currentID)

}

 

隨機播放功能,按鈕點擊後歌曲將實現隨機播放。

//隨機播放按鈕

var randombtn = _this.dom.getElementsByClass(_this.data[0].randombtn)[0];

randombtn.onclick = function(e) {

if (_this.isPlayState == 1) {

_this.isPlayState = 0;

this.className = _this.data[0].shuffle;

return;

}

if (_this.isPlayState == 2) {

onereplay.className = _this.data[0].replay;

}

_this.isPlayState = 1;

this.className = _this.data[0].shuffleon;

}

 

單曲迴圈功能,按鈕點擊後歌曲將實現單曲迴圈播放。

//單曲迴圈按鈕

var onereplay = _this.dom.getElementsByClass(_this.data[0].onereplay)[0];

onereplay.onclick = function(e) {

if (_this.isPlayState == 2) {

_this.isPlayState = 0;

this.className = _this.data[0].replay;

return;

}

if (_this.isPlayState == 1) {

randombtn.className = _this.data[0].shuffleon;

}

_this.isPlayState = 2;

this.className =  _this.data[0].replay;

 

}

 

音量調節功能,拖放調節音量功能。

//音量調節按鈕

var soundHead = _this.dom.getElementsByClass(_this.data[0].soundHead)[0];

var soundBox = _this.dom.getElementsByClass(_this.data[0].soundBox)[0];

var soundCurrentTime = _this.dom.getElementsByClass(_this.data[0].soundCurrentTime)[0];

soundHead.style.left = _this.sound * 100 + 'px';

soundCurrentTime.style.width = _this.sound * 100 + '%';

soundHead.onmousedown = function(e) {

var x = (e || window.event).clientX;

var l = this.offsetLeft;

var max = soundBox.offsetWidth - this.offsetWidth;

document.onmousemove = function(e) {

var thisX = (e || window.event).clientX;

var to = Math.min(max, Math.max(-2, l + (thisX - x)));

if (to < 0) {

to = 0;

}

soundHead.style.left = to + 'px';

//此句代碼可以除去選中效果

window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();

_this.audion.volume = to / max;

//document.querySelector('.now')

soundCurrentTime.style.width = to / max * 100 + '%';

}

//註意此處是document 才能有好的拖動效果

document.onmouseup = function() {

document.onmousemove = null;

};

}

 

進度條功能。

//獲取進度條dom

_this.songProgress = _this.dom.getElementsByClass(_this.data[0].SongProgress)[0];

//獲取進度條上的播放頭

_this.songPlayHead = _this.dom.getElementsByClass(_this.data[0].playHead)[0];

//單擊進度條 調整發播放進度

_this.songProgress.onclick = function(e) {

var x = (e || window.event).clientX;

var left = x - this.offsetLeft - _this.songPlayHead.offsetWidth;

var maxwidth = _this.songProgress.offsetWidth;

_this.dom.getElementsByClass(_this.data[0].playHead)[0].style.left = left + 'px';

var currenttime = _this.audion.duration * (left / maxwidth)

var p = left / maxwidth

_this.audion.currentTime = p * _this.audion.duration;

_this.audion.play();

};

//拖動播放頭,調整播放進度

_this.songPlayHead.onmousedown = function(e) {

var x = (e || window.event).clientX;

var l = this.offsetLeft;

var max = _this.songProgress.offsetWidth - this.offsetWidth;

_this.playMax = max;

document.onmousemove = function(e) {

var thisX = (e || window.event).clientX;

var to = Math.min(max, Math.max(-2, l + (thisX - x)));

if (to < 0) {

to = 0;

}

_this.playprogress = to;

_this.isSlide = 1;

_this.songPlayHead.style.left = to + 'px';

_this.dom.getElementsByClass(_this.data[0].SingerCurrentTime)[0].innerHTML = conversion(_this.audion.duration * (_this

.playprogress / _this.playMax));

//此句代碼可以除去選中效果

window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();

// _this.audion.currentTime = to / max;

 

}

//註意此處是document 才能有好的拖動效果

document.onmouseup = function() {

_this.isSlide = 0;

_this.audion.currentTime = (_this.playprogress / _this.playMax) * _this.audion.duration;

_this.audion.play();

document.onmousemove = null;

};

 

定時函數功能

//定時函數

_this.timecolick = setInterval(function() {

if (_this.isSlide == 1) {

return;

}

//設置進度條

var percent = Math.floor(_this.audion.currentTime / _this.audion.duration * 10000) / 100 + "%";

_this.songPlayHead.style.left = percent;

//設置當前播放時間

_this.dom.getElementsByClass(_this.data[0].SingerCurrentTime)[0].innerHTML = conversion(_this.audion.currentTime);

if (_this.audion.ended) {

if (_this.isPlayState == 0) //順序播放

{

if (_this.currentID < _this.songList.length - 1) {

_this.currentID++;

} else {

_this.currentID = 0;

}

} else if (_this.isPlayState == 1) //隨機播放

{

_this.currentID = Math.floor(Math.random() * _this.songList.length - 1)

} else //單曲迴圈

{

_this.currentID = _this.currentID;

}

console.log(_this.currentID)

_this._PlaySong(_this.currentID);

}

}, 100)

 

歌曲播放功能

__PlaySong: function(songID) {

var _this = this;

this.audion.setAttribute("src", this.data[0].Songlist[songID].songurl);

this.dom.getElementsByClass(this.data[0].SongName)[0].innerHTML = _this.data[0].Songlist[songID].songname;

_this.dom.getElementsByClass(this.data[0].Singer)[0].innerHTML = this.data[0].Songlist[songID].songer;

_this.audion.onloadedmetadata = function() {

_this.dom.getElementsByClass(this.data[0].SingerCurrentTime)[0].innerHTML = conversion(_this.audion.currentTime);

_this.dom.getElementsByClass(this.data[0].showalltime)[0].innerHTML = conversion(_this.audion.duration)

}

this.audion.play();

var Songlist = _this.songBox.childNodes;

for (var i = 0; i < Songlist.length; i++) {

if (songID == i) {

Songlist.item(i).setAttribute("class", this.data[0].currentSong);

} else {

Songlist.item(i).setAttribute("class", "")

}

}

//console.log(_this.scollHeight*songID)

_this._scollToMusiclist(songID, _this.dom.getElementsByClass(this.data[0].MusicList)[0])

 

}

 

歌曲滾動功能。

_scollToMusiclist: function(singID, wmusicbox) {

//ok  2019年4月5日,終於調試成功,長時間不開發真的不行,好多事情想不到,剛纔不停的滾動現象是由於我沒有對最大值進行判斷,如果超過最大值,我們需要把最大值賦給變數,那樣就不會不停的閃爍了。

var gundong = singID * 20;

var maxgundong = wmusicbox.scrollHeight - wmusicbox.offsetHeight;

if (gundong > maxgundong) {

gundong = maxgundong;

}

var scollTime = setInterval(function() {

console.log(wmusicbox.scrollTop)

if (wmusicbox.scrollTop < gundong) {

wmusicbox.scrollTop = wmusicbox.scrollTop + 1;

console.log(gundong)

} else if (wmusicbox.scrollTop > gundong) {

wmusicbox.scrollTop = wmusicbox.scrollTop - 1;

console.log("2")

} else {

console.log("=")

clearInterval(scollTime);

}

})

}

 

ok,這網我們的網頁播放器已經全部編寫完畢,我把源代碼打包,提供大家下載,多提寶貴意見。 單擊下載

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 近些年,由於智能手機的迅速普及推動移動互聯網技術的蓬勃發展,全球數據呈現爆髮式的增長。2018年5月企鵝號的統計結果:互聯網每天新增的數據量達2.5*10^18位元組,而全球90%的數據都是在過去的兩年間創造出來的。隨著5G技術的商用,未來連接萬物的物聯網設備必將帶來更大量級的數據。大膽預期,我們即將 ...
  • 資料庫設計 資料庫設計的4個步驟: 需求分析: 資料庫存儲數據是什麼 數據有哪些屬性 數據和屬性的特點有那些 邏輯設計: 資料庫進行邏輯建模 物理設計: 根據資料庫自身特點把邏輯設計轉換成物理設計 維護優化: 新的需求建表 索引優化 大表拆分 需求分析: 邏輯設計: 物理設計: 維護優化: 需求分析 ...
  • 前言 之前寫過屏蔽系統導航欄功能的文章,具體可看 "Android6.0 源碼修改之屏蔽導航欄虛擬按鍵(Home和RecentAPP)/動態顯示和隱藏NavigationBar" 在某些特殊定製的版本中要求完全去掉導航欄,那麼當用戶點進一些系統自帶的應用界面如設置、聯繫人等,就沒法退出了,雖然可以在 ...
  • 在我們平時生活當中,經常會看到一些表白女朋友的html網頁,但是Android端的表白軟體可以說是基本沒有,筆者在全網搜了一下,就沒有一個可以用的。安卓端可以給人一種定製和精美的感覺,這是網頁所做不到的,網頁鏈接不見了就沒了。因此在這裡將自己寫的Android軟體製作流程以及代碼全部開源,這裡採用了 ...
  • 寫在前面: 網上有各種富文本編輯器,微博分享等操作,這些功能非常實用,他們就是使用 range,selection 對象來實現的,這兩個對象偏冷門,不涉及編輯器一般用不到,range 對象是對選區的操作,選區是滑鼠在頁面上按下,然後拖動選擇的內容,range 對象就是對這個選區的操作;selecti ...
  • 應用場景 在前端開發的過程中,時常有這樣的一個需求,需要將某個組件,展示在不同的頁面中。常見的有,頭部菜單欄、底部版權,如下圖中的菜單,就需要在不同頁面中進行顯示。 解決方法 假設有這樣一個需求,希望把下麵的這個頭部菜單在 Home 和 About 這兩個頁面中顯示 在頁面中,引入公共組件 在需要顯 ...
  • 一、安裝Node.js (以下安裝環境均為win10) 下載鏈接:https://nodejs.org/en/download/ 官網給出了兩個版本,LTS和Curren。字面意思是推薦大多數用戶使用LTS版本,而Current版本則是含有最新功能,百度了下LTS是長期維護版本,沒有特殊要求這裡就下 ...
  • 對於函數的使用,和對函數的參數和返回值的理解,給出了一些例題,以便理解! ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...