DS和WiiU商店明年關閉
任天堂官推宣布,將于2023年3月末關閉3DS和WiiU的eShop,關閉后玩家將無法購買任何內容,但此前已經購買的內容仍可重新下載,游戲更新、線上服務等功能還可以繼續使用。
此外,任天堂還推出了一個3DS和WiiU的統計頁面,登錄后可以查看對應機種的總游戲時間和玩過的游戲數量等數據。
傳送門:https://my-nintendo-3ds-wiiu-memories.nintendo.com/ja-JP/index.html#top
寶可夢銀行明年免費
任天堂宣布,在2023年3月末3DS商店關閉后,寶可夢銀行和寶可夢傳送將無法從商店下載,同時寶可夢銀行將改為免費使用,可以將寶可夢銀行中的寶可夢搬家至“寶可夢Home”,該服務的終止時間未定,已經充值過的不予退款。
PS
今天發布的另一篇文章中有歷代寶可夢的傳送方法,有需要的小伙伴可以看看[狗頭]
《茶杯頭》動畫
網飛公開《茶杯頭》動畫劇集《The Cuphead Show!》新預告片,本片將于2月18日在網飛平臺開播。
本周Fami通游戲評分
《寶可夢 阿爾宙斯》
(Switch) – 10/9/9/10 [38/40]
《蘇菲的煉金工房2 ~不可思議夢的煉金術士~》
(PS4, Switch) – 8/8/8/8 [32/40]
《NS運動》免費試玩
任天堂開放《Nintendo Switch 運動》網絡測試資格申請,此次測試僅限Nintendo Switch Online會員參與,在下方各服務器的傳送門可前往免費兌換參與資格,之后在對應eShop兌換下載即可,客戶端容量855M。
美服:https://my.nintendo.com/rewards/7465c9bc0183c858
日服:https://my.nintendo.com/rewards/ab1705a64f670376
歐服:https://my.nintendo.com/rewards/5ef22cb53f7e0914
港服:無
本次測試游玩對應3種項目:保齡球、網球、擊劍,具體開放時間如下
2月19日:11:00~11:45、19:00~19:45
2月20日:3:00-3:45、11:00-11:45、19:00-19:45
想試玩的小伙伴可以按照以下步驟操作:
1.確認賬號是日服/美服/歐服:
確認方法:打開eShop,里面的語言是日語、英語或者其他小語種就行,只要不是繁體中文即可。
改區方法:打開并登陸https://my.nintendo.com,里面有國家/地區的選項。港服有余額的話,轉區余額會被清零。登陸的時候可能需要代理,有的加速器也支持,下同。
2.獲取兌換碼:
手機/電腦打開My Nintendo官網并登陸賬號:https://my.nintendo.com。
找到《Nintendo Switch Sports》的頁面,多次點擊最下面的藍色按鈕,最后的頁面里選擇兌換即可獲取測試客戶端的兌換碼。
3.使用兌換碼:
在NS的eShop里使用該兌換碼即可。兌換碼是分區的,你在哪個區獲得的,就得在哪個區使用。
經典名作《雪人兄弟》
經典街機游戲《雪人兄弟 特別版》確認將登陸NS,發售日和售價未定。
本作繼承了街機原版的可愛設計和操作性并進行了一定程度的升級強化,此外,在原版50關的基礎上再增加30關,追加新BOSS和新怪物。
另外,本作還將包含“怪物挑戰模式”,該模式中玩家可以選擇怪物當作主角進行闖關,每個怪物都有不同的技能,可以體驗與正常闖關完全不同的趣味玩法。該模式將收錄在實體版游戲中,數字版需要額外購買。
《異度神劍3》角色介紹
官推公開了本作部分角色介紹,本作預計將于9月登陸Switch,支持中文。(注:以下內容來自日文官推,部分用語為暫譯)
Yuuni(CV:潘めぐみ)
Yuuni是18歲的科維斯士兵,使用杖型的槍械“槍杖”。她與Noa和Rantsu是青梅竹馬,擅長在戰斗中進行回復,長在頭上的翅膀好像在哪見過!?
Yuuni擁有心直口快的性格,因此有點毒舌,雖然是隊伍里最大大咧咧的人,但卻很擅長講解授課。很尊敬Noa,與Rantsu保持著無話不談的良好關系,對朋友的責任感比任何人都強。
PS
按照異度1的設定,頭上有小翅膀的海恩塔族是非常長壽的,例如梅利亞已經88歲了,但相當于人類的16歲。那Yuuni這18歲的年紀,在海恩塔族里就相當于還是嬰兒了[捂臉]
但有沒有這樣一種可能,18歲只是按照人類推算的大致年齡,實際是個100多歲的老阿姨[捂臉]
Taion(CV:木村良平)
Taion是18歲的安格努斯士兵,使用紙樣的神秘武器“紙人”,還為其起名為“Mondo”并疼愛有加。他是一位深思熟慮的戰術家,擅長支援同伴。黑色眼鏡和橙色圍巾是他的標志。
他與Mio和Sena共同行動,因擁有高水平的洞察力和戰術判斷能力深受同伴信賴。擁有一絲不茍性格,有時也會過于慎重,在不耐煩的時候也會變得粗暴起來,讓人有點困擾。
《阿爾宙斯》新宣傳片
寶可夢官方油管頻道公開《寶可夢傳說 阿爾宙斯》新宣傳片,“新資訊 其伍 未曾謀面的寶可夢與場長篇”。本作已于日前登陸Switch,支持中文。
動森更新
《集合啦!動物森友會》更新2.0.5版本,具體內容如下。
本體
-修復在特定情況下玩家搬家導致攝影棚的說明無法進行的問題
-修復在島上擺放了過多家具等物品并發生對話時,對話框出現的時候會導致游戲無法進行的問題
-修復在夢境搜索中選擇“按島嶼名稱搜索”時,夢美會重復相關說明的問題
-修復小動物穿著在“Able Sisters”中展示的“我的設計”時,會穿上其他樣式服裝的問題
-修復小動物訪問玩家的家時,如果玩家使用了“我的設計展示柜”、“設計”、“房間草稿”中的任意一個后,玩家離開家后小動物仍會留在家里的問題
-修復在“對島民的家進行提案”并掛上門飾后,日期變更會導致門飾消失的問題
-修復/調整其他問題,提升游戲體驗
DLC
-修復在未滿足螞蟻、蝴蝶的出現條件的情況下,在別墅庭院里放置螞蟻、蝴蝶會導致再來別墅時無限加載的問題
-修復在建造設施的特定時間結束游戲,會導致之后的事件無法正常進行的問題
-修復/調整其他問題,提升游戲體驗
《智龍迷城 NS版》
一款3消解謎游戲,將于2月20日登陸eShop,售價500日元,有氪金要素,無中文,無實體版。
玩家將在游戲中利用怪物們和3消解謎的力量進行冒險,共有3種模式“冒險”“對戰”“編輯”。冒險模式支持單人和最多4人合作,目標為打通所有迷宮;對戰模式支持最多8人進行分數對決;編輯模式中可以自由搭配敵人、背景、BGM創造獨特迷宮并上傳分享。
《黎明殺機》x貞子姐姐
《黎明殺機》將于3月9日上線“貞子再臨”聯動內容,追加新殺手貞子、新逃生者淺川陽一。
件被看作是 JavaScript 與網頁之間交互的橋梁,當事件發生時,可以通過 JavaScript 代碼(函數)執行相關的操作。例如,用戶可以通過鼠標拖曳登錄框,改變登錄框的顯示位置;或者在閱讀文章時,選中文本后自動彈出分享、復制選項。本章將對 DOM 中的事件進行詳細講解。
事件可被理解為是 JavaScript 偵測到的行為,這些行為指的就是頁面的加載、鼠標單擊頁面、鼠標滑過某個區域、按下鍵盤等具體的動作,它對實現網頁的交互效果起著重要的作用。在深入學習事件時,需要對一些非常基本又相當重要的概念有一定的了解。
事件處理程序指的就是 JavaScript 為響用戶行為所執行的程序代碼。例如,用戶單擊 button 按鈕時,這個行為就會被 JavaScript 中的click 事件偵測到;然后讓其自動執行,為 click 事件編寫的程序代碼,如在控制臺輸出“按鈕被單擊了”。
事件驅動是指,在 Web 頁面中 JavaScript 的事件,偵測到的用戶行為(如鼠標單擊、鼠標移入等),并執行相應的事件處理程序的過程。
事件綁定指的是為某個元素對象的事件綁定事件處理程序。在 DOM 中提供了3種事件的綁定方式。下面將針對以3種事件綁定方式的語法以及各自的區別進行詳細講解。
事件的行內綁定式是通過HTML標簽的屬性設置實現的,具體語法格式如下。
<div onclick="alert('handle click')"></div>
在上述語法中,div 可以是任意的HTML標簽,如 <button>、<input>標簽等;事件是由 on 和事件名稱組成的一個 HTML 屬性,如單擊事件對應的屬性名為 onclick;事件的處理程序指的是 JavaScript 代碼,如匿名函數等。
需要注意的是,由于開發中提倡 JavaScript 代碼與 HTML 代碼相分離。因此,不建議使用行內綁定事件。
動態的綁定方式很好地解決了JavaScript代碼與HTML代碼混合編寫的問題。在JavaScript代碼中,為需要事件處理的 DOM 元素對象,添加事件與事件處理程序。具體語法格式如下。
div.onclick = function handleClick () {
console.log('handle click');
};
在上述語法中,事件的處理程序一般都是匿名函數或有名的函數。在實際開發中,相對于行內綁定來說,事件的動態綁定的使用居多。
行內綁定與動態綁定除了實現的語法不同以外,本質是相同的,都是給 DOM 元素綁定了一個 onclick 屬性。
為了給同一個 DOM 對象的同一個事件添加多個事件處理程序,DOM中引入了事件流的概念,可以讓DOM對象通過事件監聽的方式實現事件的綁定。由于不同瀏覽器采用的事件流實現方式不同,事件監聽的實現存在兼容性問題。通常根據瀏覽器的內核可以劃分為兩大類,一類是早期版本的IE瀏覽器(如IE6~8),一類遵循W3C標準的瀏覽器(以下簡稱標準瀏覽器)。
接下來,將根據不同類型的瀏覽器,分別介紹事件監聽的實現方式。
(1)早期版本的IE瀏覽器
在早期版本的IE瀏覽器中,事件監聽的語法格式如下。
DOM對象.attachEvent(type,callback);
在上述語法中,參數 type 指的是為 DOM 對象綁定的事件類型,它是由 on 與事件名稱組成的,如 onclick。。參數 callback 表示事件的處理程序。
(2)標準瀏覽器
標準瀏覽器包括IE8版本以上的IE瀏覽器(如IE9~11),新版的Firefox、Chrome等瀏覽器。具體語法格式如下。通過這種方式我們可以給元素注冊多個事件處理函數,而 btn.onclick = fn 是賦值操作只能設置一個事件處理函數。
DOM對象.addEventListener(type, callback, [capture]);
在上述語法中,參數 type 指的是 DOM 對象綁定的事件類型,它是由事件名稱設置的,如 click。參數 callback 表示事件的處理程序。參數 capture 默認值為 false,這個屬性后面單獨介紹,一般情況我們都使用它的默認值。
現在 IE 瀏覽器已經被淘汰,所以我們不需要再去記憶 attachEvent() 的用法,但是我們需要了解過去,過去在使用這種方式注冊事件的時候需要處理瀏覽器的兼容性,下面我們演示下:
function addEventListener(element, type, listener) {
// 能力檢測: 就是要看當前的瀏覽器是否支持此標簽對象的屬性或是方法
if (element.addEventListener) {
element.addEventListener(type, listener, false);
} else if (element.attachEvent) {
element.attachEvent('on' + type, listener);
} else {
element['on' + type] = listener;
}
}
在事件處理函數中的 this 指向當前觸發該事件的 DOM 元素。
link.onclick = function handleLink () {
photo.src = this.href;
p.textContent = this.title;
return false;
};
但是通過行內綁定注冊的事件,調用的函數中 this 指向的是 window。
<button onclick="handle()">按鈕</button>
<script>
function handle () {
// 此處的 this 指向 window
console.log(this);
}
</script>
行內綁定事件 onclick="handle()" 中的 "" 雙引號內部其實可以看做是一個匿名函數,"" 雙引號內部的這個匿名函數才是事件處理函數,在事件處理函數中又調用了 handle() 方法。
<!-- 此處的 this 指向的是觸發事件的對象 button -->
<button onclick="handle(this)">按鈕</button>
<script>
function handle (btn) {
// 此處的 this 指向 window
console.log(btn);
}
</script>
綁定事件的元素可以解除綁定,例如:我們可以讓按鈕點擊一次之后解除事件綁定。三種綁定事件的解除事件的方式不同,下面我們分別來介紹。
行內綁定事件和動態綁定事件本質上都是給 DOM 元素設置 onclick 屬性,對應的解除綁定事件的方式都是把 onclick 屬性重新設置為 null。
當按鈕執行完點擊事件的處理程序后立即解除事件的綁定
<button onclick="handle(this)">按鈕</button>
<script>
function handle (btn) {
alert('Hello');
btn.onclick = null;
}
</script>
btn.onclick = function handle () {
this.onclick = null;
};
標準綁定事件使用 addEventListener(type, callback, [capture]); 方法,對應的解除綁定使用的方法是 removeEventListener(type, callback, [capture]),需要注意的是,如果注冊的事件需要解除的話,使用 addEventListener() 注冊事件的時候,傳入的 callback 不能是匿名函數,因為解除事件綁定的時候還需要引用這個函數。
const div = document.querySelector('#div');
div.addEventListener('click', handle);
function handle () {
alert('hello');
this.removeEventListener('click', handle);
}
我們已經會使用 addEventListener(type, callback, [capture]),方法給元素注冊事件,但是這個方法的第三個參數的作用我們還不清楚,下面我們就來介紹該方法的第三個參數,這里我們需要先來學習 DOM 中的事件流(事件模型)。
DOM (文檔對象模型)結構是一個樹型結構,當一個HTML元素產生一個事件時,該事件會在元素結點與根節點之間按特定的順序傳播,路徑所經過的節點都會收到該事件,這個傳播過程可稱為 DOM 事件流。
事件順序有兩種類型:事件捕捉和事件冒泡。
這是 IE 瀏覽器對事件模型的實現,也是最容易理解的。冒泡,顧名思義,事件像個水中的氣泡一樣一直往上冒,直到頂端。
從DOM 樹型結構上理解,就是事件由葉子節點沿祖先結點一直向上傳遞直到根節點;從瀏覽器界面視圖 HTML 元素排列層次上理解就是事件由具有從屬關系的觸發事件的元素一直傳遞到根元素直到文檔對象。
addEventListener(type, callback, [capture]),該方法的第三個參數為 false 的時候設置觸發事件的方式為事件冒泡,該參數默認為 false。
一般情況下,我們都會使用事件冒泡的方式注冊事件。
const outer = document.querySelector('#outer');
const inner = document.querySelector('#inner');
outer.addEventListener('click', function () {
console.log('點擊了 outer');
}, false);
inner.addEventListener('click', function () {
console.log('點擊了 inner');
}, false);
document.body.addEventListener('click', function () {
console.log('點擊了 body');
}, false);
document.addEventListener('click', function () {
console.log('點擊了 document');
}, false);
window.addEventListener('click', function () {
console.log('點擊了 window');
}, false);
執行結果:
使用行內綁定和動態綁定事件的方式默認使用的是事件冒泡。
Netscape 的實現,它與冒泡型剛好相反,由 DOM 樹最頂層元素一直到觸發事件的元素。
addEventListener(type, callback, [capture]),該方法的第三個參數為 true 的時候設置觸發事件的方式為事件捕獲。
const outer = document.querySelector('#outer');
const inner = document.querySelector('#inner');
outer.addEventListener('click', function () {
console.log('點擊了 outer');
}, true);
inner.addEventListener('click', function () {
console.log('點擊了 inner');
}, true);
document.body.addEventListener('click', function () {
console.log('點擊了 body');
}, true);
document.addEventListener('click', function () {
console.log('點擊了 document');
}, true);
window.addEventListener('click', function () {
console.log('點擊了 window');
}, true);
執行結果:
使用行內綁定和動態綁定事件的方式無法使用事件捕獲。
我們已經對上面兩個不同的事件模型進行了解釋和對比。DOM 標準同時支持兩種事件模型,即事件捕獲與事件冒泡,但是,事件捕獲先發生。兩種事件流都會觸發 DOM 中的所有對象,從 document對象開始,也在 document 對象結束(大部分兼容標準的瀏覽器會繼續將事件是捕捉/冒泡延續到window 對象)。
如圖:首先是捕獲傳遞事件,接著是冒泡傳遞,所以,如果一個處理函數既注冊了捕獲型事件的監聽,又注冊冒泡型事件監聽,那么在 DOM 事件模型中它就會被調用兩次。
DOM 標準的事件模型最獨特的性質是,文本節點也會觸發事件(在IE不會)。
事件委托,通俗地來講,就是把一個元素的處理事件的函數委托到另一個元素。
一般來講,會把一個或者一組元素的事件委托到它的父層或者更外層元素上,真正綁定事件的是外層元素,當事件響應到需要綁定的元素上時,會通過事件冒泡機制從而觸發它的外層元素的綁定事件上,然后在外層元素上去執行函數。
舉個例子,比如一個宿舍的同學同時快遞到了,一種方法就是他們都傻傻地一個個去領取,還有一種方法就是把這件事情委托給宿舍長,讓一個人出去拿好所有快遞,然后再根據收件人一一分發給每個宿舍同學。
在這里,取快遞就是一個事件,每個同學指的是需要響應事件的 DOM 元素,而出去統一領取快遞的宿舍長就是代理的元素,所以真正綁定事件的是這個元素,按照收件人分發快遞的過程就是在事件執行中,需要判斷當前響應的事件應該匹配到被代理元素中的哪一個或者哪幾個。
下面我們來做一個練習,為下面的每一個 li 注冊點擊事件,當點擊當前 li 的時候打印 li 中的文本內容。
<ul id="list">
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
......
<li>item n</li>
</ul>
首先我們用傳統的方式來實現,先獲取到頁面上所有的 li,然后遍歷所有的 li,給每一個 li 注冊點擊事件,這里使用 addEventListener() 注冊事件的時候省略了第三個參數,默認為 false,事件冒泡的方式。
這樣做不好的地方有兩點,第一:我們需要為每一個 li 元素創建一個新的事件處理函數,每次創建都需要銷毀時間和內存。第二:當點擊按鈕往 ul 中添加新的 li 元素的時候需要給新創建的 li 注冊點擊事件。
const lis = document.querySelectorAll('#list li');
lis.forEach(function (li) {
li.addEventListener('click', function () {
console.log(this.textContent)
});
});
下面我們使用事件委托的方式優化上面的代碼,把點擊事件注冊給父元素 ul,當點擊 li 的時候通過事件冒泡把點擊事件傳遞給父元素 ul。
const ul = document.querySelector('#list');
ul.addEventListener('click', function () {
console.log('test');
// 此處的 this 是注冊事件的元素 ul
console.log(this);
});
代碼改完之后點擊 li,這段代碼確實可以執行,但是我們的目標是打印 li 之間的內容,而通過打印發現此處的 this 不是我們想要的當前點擊的 li,而是注冊事件的元素 ul。所以這里需要強調一點,在注冊事件的時候,事件源是注冊事件的對象。
那如何獲取當前觸發事件的元素 li 呢?當事件被觸發的時候事件處理函數會接收一個參數,這個參數叫做事件對象,事件對象可以提供觸發事件的時候相關的數據,下一小節詳細介紹,這里我們先用事件對象解決當前的問題,事件對象中有一個 target 屬性,這個屬性就是當前觸發事件的對象。
在 IE 瀏覽器中獲取事件對象的方式不同,IE 中是通過 window.event 獲取事件對象,以前在獲取事件對象的時候還要處理瀏覽器兼容性問題,IE 瀏覽器現在已經被淘汰所以瀏覽器兼容性的處理我們就不再演示。
const ul = document.querySelector('#list');
// 事件參數(對象) e
ul.addEventListener('click', function (e) {
// e.target 觸發事件的元素
console.log(e.target.textContent);
// 注冊事件的元素
console.log(this);
});
到這里這個案例就完成了,我們再來擴展下這個案例,如果想要點擊特定的 li 來觸發事件該如何實現?
<ul id="list">
<li>item 1</li>
<li class="cls">item 2</li>
<li class="cls">item 3</li>
......
<li>item n</li>
</ul>
如上代碼,如果想點擊具有特性類樣式或者特定 id 的元素觸發事件,可以通過判斷當前點擊的元素 e.target 的類樣式或者 id 屬性進行判斷。
if (e.target.className === 'cls') {
// ....
}
但是如果想像 CSS 選擇器一樣更加靈活的匹配的話,上面的判斷不夠靈活,這里可以使用 元素.matches(選擇器) 來匹配特定元素。當元素匹配指定的選擇器返回 true。
const ul = document.querySelector('#list');
ul.addEventListener('click', function (e) {
// matches 方法,當元素匹配指定的選擇器返回 true
if (e.target.matches('.cls')) {
console.log(e.target.textContent);
}
});
利用事件冒泡的特性,將本應該注冊在子元素上的處理事件注冊在父元素上,這樣點擊子元素時發現其本身沒有相應事件就到父元素上尋找作出相應。這樣做的優勢有:1. 減少內存消耗,避免重復創建相同事件處理函數,只需要把多個子元素的事件委托給父元素。2.隨時可以添加子元素,添加的子元素會自動有相應的處理事件。
const tbody = document.querySelector('tbody');
tbody.addEventListener('click', function (e) {
// 注冊事件的元素 tbody
// console.log(this);
// 觸發事件的元素(你點擊的那個元素)
// console.log(e.target)
// 判斷元素是否是指定的元素
// console.log(e.target.matches('.del'))
if (e.target.matches('.del')) {
e.target.parentNode.parentNode.remove();
}
});
每當觸發一個事件,就會產生一個事件對象 event,該對象包含著所有與事件有關的信息。包括導致事件的元素、事件的類型以及其他與特定事件相關的信息。上一小節中我們使用事件對象獲取觸發事件的元素。
例如:鼠標操作產生的 event中會包含鼠標位置的信息;鍵盤操作產生的event中會包含與按下的鍵有關的信息。
所有瀏覽器都支持 event 對象,但支持方式不同,在標準 DOM 中 event 對象必須作為唯一的參數傳給事件處理函數,在 IE 中 event 是 window 對象的一個屬性。
成員 | 描述 | 備注 |
type | 觸發的事件名稱 | |
eventPhase | 事件流在傳播階段的位置 | |
target | 觸發事件的元素 | |
srcElement | target 的別名,老版本的 IE 中使用 | |
clientX / clientY | 基于瀏覽器的可視區域,鼠標坐標值 | 可配合固定定位,基于窗口定位 |
pageX / pageY | 基于整個頁面,頁面滾動有關,鼠標在頁面的坐標值 | 可配合絕對定位,基于頁面定位 |
key | 獲取按鍵輸入 | |
preventDefault() | 取消默認行為 | |
stopPropagation() | 阻止事件冒泡 |
const img = document.querySelector('#img');
document.addEventListener('mousemove', function (e) {
// 鼠標位置 - 圖片大小的一半
img.style.left = e.clientX - 96 / 2 + 'px';
img.style.top = e.clientY - 80 / 2 + 'px';
});
設置樣式,讓 body 的高度等于 1500px(垂直方向出現滾動條),滾動條下拉這時候移動鼠標,圖片的縱向位置跟鼠標脫離。
原因是 clientX 和 clientY 獲取的是鼠標在當前可視區域的位置。如果出現滾動條的話可以通過 pageX 和 pageY 獲取鼠標在當前文檔中的位置。
const img = document.querySelector('#img');
document.addEventListener('mousemove', function (e) {
img.style.left = e.pageX - 96 / 2 + 'px';
img.style.top = e.pageY - 80 / 2 + 'px';
});
這里獲取圖片大小的時候寫的是具體值,將來圖片替換后,還需要改變這里的大小。我們可以使用 getComputedStyle() 獲取圖片的大小。
const img = document.querySelector('#img');
img.addEventListener('load', function () {
const style = window.getComputedStyle(img, null);
const imgWidth = parseInt(style.width);
const imgHeight = parseInt(style.height);
document.addEventListener('mousemove', function (e) {
img.style.left = e.pageX - imgWidth / 2 + 'px';
img.style.top = e.pageY - imgHeight / 2 + 'px';
});
});
注意:這里需要在 img 標簽加載完畢后獲取圖片的大小,否則獲取到的圖片大小是 0,因為 load 事件代表圖片被加載,否則的話代碼從上到下執行到這個位置,圖片還沒有被下載回來,這個時候獲取圖片的大小是 0。
#img {
width: 100px;
position: absolute;
left: 0;
top: 0;
}
.toLeft {
transform: rotateY(180deg);
}
const img = document.querySelector('#img');
let x = 0;
let y = 0;
document.addEventListener('keydown', function (e) {
switch (e.key) {
case 'ArrowLeft':
x -= 10;
img.classList.add('toLeft');
break;
case 'ArrowRight':
x += 10;
img.classList.remove('toLeft');
break;
case 'ArrowUp':
y -= 10;
break;
case 'ArrowDown':
y += 10;
break;
}
img.style.left = x + 'px';
img.style.top = y + 'px';
});
// contextmenu 鼠標右鍵事件
document.addEventListener('contextmenu', function(e) {
// 禁止點擊的默認行為,即顯示上下文菜單
e.preventDefault()
});
// 禁止選中文字事件
document.addEventListener('selectstart', function(e) {
// 禁止選中文字的默認行為,即不能選中文字
e.preventDefault()
})
const loginBg = document.querySelector('#bg');
const loginLink = document.querySelector('#link');
const loginBox = document.querySelector('#login');
const closeBtn = document.querySelector('#closeBtn');
const loginTitle = document.querySelector('#title');
loginLink.addEventListener('click', function () {
loginBox.style.display = 'block';
loginBg.style.display = 'block';
});
closeBtn.addEventListener('click', function () {
loginBox.style.display = 'none';
loginBg.style.display = 'none';
});
// 拖動事件的三個過程:鼠標按下 mousedowm,鼠標移動 mousemove,鼠標松開 mouseup
const style = window.getComputedStyle(loginBox, null);
// 模態框跟著鼠標走的原理
loginTitle.addEventListener('mousedown', function (e) {
const loginLeft = parseInt(style.left);
const loginTop = parseInt(style.top);
// 步驟一:當鼠標按下時,需要立即得到鼠標在盒子中的坐標
var x = e.pageX - loginLeft;
var y = e.pageY - loginTop;
// 為整個頁面添加鼠標移動事件
document.addEventListener('mousemove', move);
function move(e) {
// 步驟二:模態框的left和top等于鼠標在頁面的坐標減去鼠標在盒子內的坐標
// 注意:一定要加上px
login.style.left = e.pageX - x + 'px';
login.style.top = e.pageY - y + 'px';
}
// 步驟三:鼠標松開時取消整個頁面的鼠標移動事件
document.addEventListener('mouseup', function (e) {
document.removeEventListener('mousemove', move);
});
});
在這之前我們已經使用過了單擊事件、鼠標經過和鼠標離開的事件,瀏覽器給我們提供的事件種類非常多,下面我們列出一些常用的事件,使用的方式都是一樣的。
描述 | 事件名稱 |
鼠標單擊 | click |
鼠標雙擊 | dblclick |
鼠標移入 | mouseover |
鼠標移出 | mouseout |
鼠標移動 | mousemove |
獲取焦點 | focus |
失去焦點 | blur |
鍵盤按下 | keydown |
鍵盤彈起 | keyup |
不能識別功能鍵 ctrl、alt 等 | keypress |
文本框的輸入事件 | input |
const search = document.querySelector('#search');
function hanldeFocus(e) {
if (e.key === 's') {
search.focus();
e.preventDefault();
}
}
document.addEventListener('keydown', hanldeFocus);
search.addEventListener('focus', function () {
document.removeEventListener('keydown', hanldeFocus);
});
search.addEventListener('blur', function () {
document.addEventListener('keydown', hanldeFocus);
});
. 簡介
1.1 總則
編碼規范用于提供統一編碼標準,旨在指導源代碼文件的規范,以保證開發團隊的協作和系統的后期維護能有效進行,編碼規范同時作為代碼評審的依據。
1.2 目的
本規范提供一個C#語言編碼的統一標準,目的在于在軟件開發過程中基于C#語言的代碼能夠始終在整個開發團隊中保持一致。
1.3 適用范圍
本規范適用于所有應用C#語言的項目開發與評審活動。
2. 格 式
2.1 縮進
所有的縮進皆為4個空格。對應的括號通常在同一列的位置上。例如:
1)所有的縮進都用"Tab鍵"形成。
2)所有的if、while和for語句中的語句內容必須用括號括起來,就算只有一個語句。
#001 if (superHero == theTick) #002 { #003 System.out.println("Spoon!"); #004 } |
2.2 間隔
所有的標識符都必須被空白字符包圍。
例如:
#001 int theTick = 5; #002 if (theTick == 5) |
2.3 空行
1)在邏輯代碼段之間放置空行來分隔代碼段;
2)在兩個方法/函數/過程之間以空行來分割;
3)在兩個類或接口的定義之間放置空行來分隔;
4)命名空間引入完畢之后放置空行。
2.4 空格的位置
1)在一個關鍵字和左括號“(”之間。注意:不要在方法名和左括號之間加空格。
2)在參數列表的每個逗號“,”之后。
3)二元操作符前后。注意:一元操作符前后都不加空格。例如:int a = 10; a = a + 1; a++;
4)for語句的每個表達式之間。例如:for (int i = 0; i < 20; i++)…。
2.5 類成員的擺放順序
class Order
{
1. static fields
2. static properties
3. static methods
4. static constructors
5. fields
6. properties
7. constructors
8. methods
}
9. 必須保持private方法被放置在使用該方法的其他方法之上,而在構造器(constr-uctor)之下,即使該構造器有可能調用這些private方法。
2.6 文件格式
文件注釋必須第一個存在。
接著是命名空間的定義。
在命名空間首先應該using指令
再次,是類型的注釋;
示例:
#001 /*************************************** #002 文件注釋 #003 ****************************************/ #004 using System; #005 namespace testMail #006 { #007 #008 /// <summary> #009 /// Form1 的摘要說明。 #010 /// </summary> #011 public class Form1 : System.Windows.Forms.Form #012 { #013 } #014 } |
2.7 行最大長度
不要讓一行代碼的長度超過120個字符,最好是低于80個字符。如果代碼開始向右延伸得很長,你就應該考慮把它分割成更多的方法。
斷行規則:
l 在逗號的后面;
l 在操作符的前面;
l 斷行的起始位置應該比原行表達式的起始位置縮進4個空格。
2.8 括號
使用括號的目的必須是在表達上不但能夠標明優先順序,而且有助于使表達更簡單明了。另外,如果某一段代碼有可能產生歧義,也需加括號。
3. 命名規則
3.1 基本原則
除了以下幾個特例之外,命名時應始終采用完整的英文描述。此外,一般應采用小寫字母,但類名、接口名以及任何非初始單詞的第一個字母要大寫。
注意:不要將同一變量用作多個用途。(如Dataset類型,每查詢一次就要聲明一個變量。)
l 使用完整的英文描述符;
l 采用適用于該領域的術語;
l 盡量少用縮寫,但如果用了,要明智地使用;
l 避免使用長的名字(小于30個字母);
l 避免使用類似的名字,或者僅僅是大小寫不同的名字;
l 避免使用下劃線;
3.2 大小寫
使用下面的三種大寫標識符約定:
l Pascal大小寫:將標識符的首字母和后面連接的每個單詞的首字母都大寫。可以對三字符或更多字符的標識符使用Pascal大小寫。例如:BackColor
l Camel大小寫:標識符的首字母小寫,而每個后面連接的單詞的首字母都大寫。例如:backColor
l 大寫:標識符中的所有字母都大寫。僅對于由兩個或者更少字母組成的標識符使用該約定。例如:System.IO
下表(表1)匯總了大寫規則,并提供了不同類型的標識符的示例。
標識符 | 大小寫 | 示例 |
類 | Pascal | AppDomain |
枚舉類型 | Pascal | ErrorLevel |
枚舉值 | Pascal | FatalError |
事件 | Pascal | ValueChange |
異常類 | Pascal | WebException |
注意 總是以 Exception 后綴結尾。 | ||
只讀的靜態字段 | Pascal | RedValue |
接口 | Pascal | IDisposable |
注意 總是以 I 前綴開始。 | ||
方法 | Pascal | ToString |
命名空間 | Pascal | System.Drawing |
參數 | Camel | typeName |
屬性 | Pascal | BackColor |
受保護的實例字段 | Camel | redValue |
注意 很少使用。屬性優于使用受保護的實例字段。 | ||
公共實例字段 | Pascal | RedValue |
注意 很少使用。屬性優于使用公共實例字段。 | ||
私有字段 | Camel | size |
局部變量 | Camel | score |
方法參數 | Camel | age |
表2-1
3.3 區分大小寫
不要使用要求區分大小寫的名稱。對于區分大小寫和不區分大小寫的語言,組件都必須完全可以使用。不區分大小寫的語言無法區分同一上下文中僅大小寫不同的兩個名稱。因此,在創建的組件或類中必須避免這種情況。
3.4 縮寫
為了避免混淆和保證跨語言交互操作,請遵循有關區縮寫的使用的下列規則:
l 不要將縮寫或縮略形式用作標識符名稱的組成部分。例如,使用GetWindow,而不要使用GetWin。
l 不要使用計算機領域中未被普遍接受的縮寫。
l 在適當的時候,使用眾所周知的縮寫替換冗長的詞組名稱。例如,用UI作為 User Interface的縮寫,用OLAP作為On-line Analytical Processing的縮寫。
l 在使用縮寫時,對于超過兩個字符長度的縮寫請使用Pascal w大小寫或Camel大小寫。例如,使用htmlButton或HtmlButton。但是,應當大寫僅有兩個字符的縮寫,如,System.IO,而不是System.Io。
l 不要在標識符或參數名稱中使用縮寫。如果必須使用縮寫,對于由多于兩個字符所組成的縮寫請使用Camel大小寫,雖然這和單詞的標準縮寫相沖突。
3.5 名字空間的命名
命名名字空間時的一般性規則是使用公司名稱,后跟技術名稱和可選的功能與設計,如下所示:CompanyName.TechnologyName[.Feature][.Design]
例如:
Microsoft.Media
Microsoft.Media.Design
嵌套的命名空間應當在包含它的命名空間中的類型上有依賴項。例如,System.Web.UI.-Design中的類依賴于System.Web.UI 中的類。
應當對命名空間使用Pascal大小寫,并用句點分隔邏輯組件,如Microsoft.Office.Power-Point中所示。
3.6 類的命名
以下規則概述命名類的規范:
l 使用名詞或名詞短語命名類。
l 使用 Pascal大小寫。
l 少用縮寫。
l 不要使用類型前綴,如在類名稱上對類使用C前綴。例如,使用類名稱FileStr-eam,而不是CFileStream。
l 不要使用下劃線字符(_)。
l 有時候需要提供以字母I開始的類名稱,雖然該類不是接口。只要I是作為類名稱組成部分的整個單詞的第一個字母,這便是適當的。例如,類名稱IdentitySt-ore是適當的。
l 在適當的地方,使用復合單詞命名派生的類。派生類名稱的第二個部分應當是基類的名稱。例如,ApplicationException對于從名為Exception的類派生的類是適當的名稱,原因是ApplicationException 是一種Exception。請在應用該規則時進行合理的判斷。例如,Button對于從Control 派生的類是適當的名稱。盡管按鈕是一種控件,但是將Control作為類名稱的一部分將使名稱不必要地加長。
示例:
public class FileStream
3.7 接口命名規范
以下規則概述接口的命名規范:
l 用名詞或名詞短語,或者描述行為的形容詞命名接口。例如,接口名稱IComp-onent使用描述性名詞。接口名稱ICustomAttributeProvider使用名詞短語。名稱IPersistable使用形容詞。
l 使用Pascal大小寫。
l 少用縮寫。
l 給接口名稱加上字母 I 前綴,以指示該類型為接口。
l 在定義類/接口對(其中類是接口的標準實現)時使用相似的名稱。兩個名稱的區別應該只是接口名稱上有字母 I 前綴。
l 不要使用下劃線字符(_)。
3.8 屬性[Attribute]命名指南
應該總是將后綴Attribute添加到自定義屬性類。以下是正確命名的屬性類的示例。
public class ObsoleteAttribute{}
3.9 枚舉類型命名規范
l 枚舉(Enum)值類型從Enum類繼承。以下規則概述枚舉的命名指南:
l 對于Enum類型和值名稱使用Pascal大小寫。
l 少用縮寫。
l 不要在Enum類型名稱上使用Enum后綴。
l 對大多數Enum類型使用單數名稱,但是對作為位域的Enum類型使用復數名稱。
l 總是將FlagsAttribute添加到位域Enum類型。
3.10 靜態字段命名指南
以下規則概述靜態字段的命名指南:
l 使用名詞、名詞短語或者名詞的縮寫命名靜態字段。
l 使用Pascal大小寫。
l 對靜態字段名稱使用匈牙利語表示法前綴。
l 建議盡可能使用靜態屬性而不是公共靜態字段。
3.11 參數命名規范
以下規則概述參數的命名指南:
l 使用描述性參數名稱。參數名稱應當具有足夠的描述性,以便參數的名稱及其類型可用于在大多數情況下確定它的含義。
l 對參數名稱使用Camel大小寫。
l 使用描述參數的含義的名稱,而不要使用描述參數的類型的名稱。開發工具將提供有關參數的類型的有意義的信息。因此,通過描述意義,可以更好地使用參數的名稱。少用基于類型的參數名稱,僅在適合使用它們的地方使用它們。
l 不要使用保留的參數。保留的參數是專用參數,如果需要,可以在未來的版本中公開它們。相反,如果在類庫的未來版本中需要更多的數據,請為方法添加新的重載。
l 不要給參數名稱加匈牙利語類型表示法的前綴。
示例:
Type GetType(string typeName)
3.12 控件名稱縮寫列表
縮寫的基本原則是取控件類名各單詞的第一個字母,如果只有一個單詞,則去掉其中的元音,留下輔音。縮寫全部為小寫。
控件類型 | 縮寫 | 例子 |
Label | Lbl | lblNote |
TextBox | Txt | txtName |
Button | Btn | btnOK |
ImageButton | Ib | ibOK |
LinkButton | Lb | lbJump |
HyperLink | Hl | hlJump |
DropDownList | Ddl | ddlList |
CheckBox | Cb | cbChoice |
CheckBoxList | Cbl | cblGroup |
RadioButton | Rb | rbChoice |
RadioButtonList | Rbl | rblGroup |
Image | Img | imgBeauty |
Panel | Pnl | pnlTree |
TreeView | Tv | tvUnit |
WebComTable | Wct | wctBasic |
ImageDateTimeInput | Dti | dtiStart |
ComboBox | Cb | cbList |
MyImageButton | Mib | mibOK |
TreeView | Tv | tvUnit |
PageBar | Pb | pbMaster |
3.13 方法命名規范
以下規則概述方法的命名指南:
l 使用動詞或動詞短語命名方法。
l 使用Pascal大小寫。
以下是正確命名的方法的實例。
RemoveAll()
3.14 屬性命名規范
以下規則概述屬性的命名指南:
l 使用名詞或名詞短語命名屬性。
l 使用Pascal大小寫。
l 不要使用匈牙利語表示法。
l 考慮用與屬性的基礎類型相同的名稱創建屬性。
3.15 事件命名指南
以下規則概述事件的命名指南:
l 對事件處理程序名稱使用EventHandler后綴。
l 指定兩個名為sender和e的參數。sender參數表示引發事件的對象。sender參數始終是object類型的,即使在可以使用更為特定的類型時也如此。與事件相關聯的狀態封裝在名為e的事件類的實例中。對e參數類型使用適當而特定的事件類。
l 用 EventArgs 后綴命名事件參數類。
l 考慮用動詞命名事件。
l 使用動名詞(動詞的“ing”形式)創建表示事件前的概念的事件名稱,用過去式表示事件后。例如,可以取消的Close事件應當具有 Closing事件和Closed事件。不要使用 BeforeXxx/AfterXxx 命名模式。
l 不要在類型的事件聲明上使用前綴或者后綴。例如,使用Close,而不要使用 OnClose。
l 通常情況下,對于可以在派生類中重寫的事件,應在類型上提供一個受保護的方法(稱為 OnXxx)。此方法只應具有事件參數 e,因為發送方總是類型的實例。
4. 注 釋
為增加程序的可讀性,編寫的代碼應加上注釋,注釋的原則為:
l 避免使用裝飾物;
l 保持注釋的簡潔;
l 在寫代碼之前寫注釋;
l 注釋出為什么做了一些事,而不僅僅是做了什么;
c#語言提供了3種形式的注釋:
//text 從//到本行結束的所有字符均作為注釋而被編譯器忽略。
/* text */ 從/*到*/ 間的所有字符會被編譯器忽略。
項目 | 注釋哪些部分 |
實參/ 參數 | 參數類型 參數用來做什么 任何約束或前提條件 |
字段/屬性 | 字段描述 注釋所有使用的不同變量 可見性決策 |
類 | 類的目的 類的開發/維護歷史 注釋出采用的不同變量 版權信息 |
編譯單元 | 每一個類/類內定義的接口,含簡單的說明文件名和/或標識信息版權信息 |
接口 | 目的 它應如何被使用以及如何不被使用 |
局部變量 | 用處/目的 |
成員函數注釋 | 成員函數做什么以及它為什么做這個 哪些參數必須傳遞給一個成員函數 成員函數返回什么 任何由某個成員函數拋出的異常 成員函數是如何改變對象的 包含任何修改代碼的歷史 如何在適當情況下調用成員函數的例子 |
成員函數 內部注釋 | 控制結構 代碼做了些什么以及為什么這樣做 局部變量 |
表3-1
可以輕松地在C#代碼結構中添加文檔注釋,并通過代碼注釋Web報告進行查看。顯示在代碼注釋Web報告中的注釋和XML標記以注釋語法 /// 開頭。通常,文檔注釋注釋在用戶定義的類型(如類、結構或接口)、成員(如字段、事件、屬性或方法)或命名空間聲明之前輸入。
例如:
在C#代碼中添加文檔注釋:
在編輯器中打開.cs文件。
切換到代碼視圖。
輸入///,后面可跟任何 XML 標記或文本字符串。如果在定義之前的行上輸入///,則編輯器將創建文檔注釋模板并填入參數和其他信息。
例如,文件class1.cs 中,在public Class1()前可輸入下列信息:
///<summary> ///summary description ///</summary> ///<remarks> ///This is a test. ///</remarks> |
在Class1的代碼結構中,<summary></summary>標記中所列出的信息出現在“說明”列。 <remarks></remarks>標記中所列出的信息出現在備注部分的class1詳細信息頁中。
5. 編 碼
一種提高代碼可讀性的方法是給代碼分段,在代碼塊內讓代碼縮進。所有在括號 { 和 } 之內的代碼,構成一個塊。基本思想是,塊內的代碼都應統一地縮進去一個單位。
c#的約定:開括號放在塊的所有者所在行的下面并縮進一級,閉括號也應縮進一級。
在代碼中使用空白。將代碼分為一些小的、容易理解的部分,可以使它更加可讀。建議采用一個空行來分隔代碼的邏輯組,例如控制結構,采用兩個空行來分隔成員函數定義。
遵循30秒條法則。其他的程序員應能在少于30秒鐘的時間內完全理解你的成員函數,理解它做什么,為什么這樣做,它是怎樣做的。一個好的經驗法則是:如果一個成員函數一個屏幕裝不下,那么它就很可能太長了。
寫短小單獨的命令行。每一行代碼只做一件事情。應使代碼盡量容易理解,從而更容易維護和改進。正如同一個成員函數應該并且只能做一件事一樣,一行代碼也只應做一件事情。
應讓代碼在一個屏幕內可見。也不應向右滾動編輯窗口來讀取一整行代碼,包括含有行內注釋語句的代碼。
6. 不要使用的結構
6.1 “do…while”
不要用do…while循環,用while()循環。
6.2 “return”
不要在一個方法的中間使用“return”,“return”只能出現在一個方法的末尾。
原因:在方法的中間使用“return”會給重構(今后將方法拆分成幾個更小的方法)帶來困難;而且它會迫使開發者不得不為該方法考慮多于一個的出口點。
6.3 “continue”
絕不要用“continue”。
原因:“continue”會給將來把一個結構拆分成幾個更小的結構或方法帶來許多困難;而且她也會迫使開發者不得不為該結構考慮多于一個的結束點。
6.4 “break”
“break”只能用于轉換狀態(switch statement)的控制。
原因:在轉換狀態控制之外的情況下使用break,會給將來把一個結構拆分成幾個更小的結構或方法帶來許多困難;而且她也會迫使開發者不得不為該結構考慮多于一個的結束點。
7. 不要混合使用遞增運算符和遞減運算符
不要混合使用遞增運算符和遞減運算符,
原因:在方法調用或是數學運算中混合使用遞增運算符(或遞減運算符)會造成欠經驗的程序員閱讀的困難。
所以,最好在遞增運算符(或遞減運算符)之間加上額外的行。
變量初始化
最好總是在每個變量聲明的時候就馬上進行初始化。
最好只在需要的時候再聲明(declare)一個變量,不然的話會影響代碼的執行效果。
示例:
#001 int secondWide = 12 ; #002 int firstWide = doFoo(20 ,secondWide ); #003 doBar(firstWide ,secondWide ); #004 int totalWide = firstWide + secondWide ; //很好! |
8. 不要使用數字/字符
程序中應盡可能少使用數字/字符,盡可能定義靜態變量來說明該數字/字符的含義,程序中需要賦值或比較時,使用前面定義的靜態變量。
例如:date1.get(1),而應該date1.get(MyDate.YEAR)。
例外:
循環控制:例如:
#001 for (int i = 0; i < 20; i++); |
9. 重復代碼塊
盡量避免使用重復的代碼塊,如果一個類中出現2個以上相同功能的代碼塊,應該將它作為類的私有方法;如果你認為多個類中都可以用到,應該將它作為util中的方法,并通知做工具類的人去寫這個方法。
10. 范圍
原則上類的成員變量必須是總是private,盡量少用protected和public,但以下情況例外:
l 內部類的成員變量(可以為public);
l 子類可繼承的基類成員變量(可以為protected);
l 并發控制中的信號變量(可以為public)。
11. 異常處理
每個頁面加上排除異常代碼,保證程序在發生異常后能繼續正常運行,采用try、catch、finally結構,如:
#001 try #002 { #003 程序體……… #004 } #005 catch(xxxException e) #006 { #007 程序體…… #008 } #009 catch(xxxException e) #010 { #011 程序體……… #012 } #013 catch(xxxException e) #014 { #015 程序體……… #016 } #017 finally #018 { #019 程序體……… #020 } |
說明:Try…Catch…finally異常處理模式是很消耗資源的,所以所加位置要慎重,避免多余的異常處理。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。