怕自己忘記,稍微紀錄一下。
各種各種理由(其中一個就是Vue,不能綁定在body上),導致時常需要一個包在body中的div,當作body來用,像這樣:
===
<body>
<div id="divBody">
<ALL CONTENT HERE>
</div>
</body>
===.
以前我叫這玩意兒divBody,之後打算改一個更像關鍵字的名字,於是想叫他rib──肋骨,又索性改叫做ribody,一方面表示他就是用來取代body的,一方面這個單字是自創的,辨識性更高一點。
2019年2月15日 星期五
2019年2月14日 星期四
[Node.js] 用Express建立伺服器
首先npm install express。
通常會把伺服器寫在server.js裡。
首先使用express()建立一個網埠監聽器(貌似大家都稱他為app,不過在Electron中可能跟electron.app搞混,或是當我們需要多個網埠監聽器的時候,總之app這個名字是可以變的,反正就是變數名稱)。
===
const express = require("express");
const bodyParser = require("body-parser");
let app = express();
app.use(bodyParser.text());
app.use(bodyParser.urlencoded({ extended: true }));
===.
bodyParser是為了後面可以使用req.body來接收客戶端的資料。沒有使用bodyParser的話會導致req.body未定義。
通常會把伺服器寫在server.js裡。
首先使用express()建立一個網埠監聽器(貌似大家都稱他為app,不過在Electron中可能跟electron.app搞混,或是當我們需要多個網埠監聽器的時候,總之app這個名字是可以變的,反正就是變數名稱)。
===
const express = require("express");
const bodyParser = require("body-parser");
let app = express();
app.use(bodyParser.text());
app.use(bodyParser.urlencoded({ extended: true }));
===.
bodyParser是為了後面可以使用req.body來接收客戶端的資料。沒有使用bodyParser的話會導致req.body未定義。
基本的都OK了。接下來要先定義各種路由的監聽函式。簡單來說就是當客戶端GET「/about/」的時候,要用哪個listener回應;當客戶端POST「/weather/today/」的時候,又要用哪個listener回應。其中,「/about/」和「/weather/today/」就稱為路由。
在listener中,req表示客戶端傳來的請求,res代表準備送出的伺服器回應。
res.send(response)後,這個res就不能再被傳送第二次了。
===
app.get(route, function (req, res) {
res.send("server response");
res.send("this is no use"); // 這個send是無效的
});
===.
在客戶端,為了向伺服器傳送請求,通常是這樣做的:
===
// 客戶端
let xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
console.log(this.readyState);
console.log(this.status);
console.log(this.responseText);
};
xhttp.open(method, url, async);
xhttp.send("client request");
===.
所謂的method指的就是"GET"或"POST"(字串型別);async則是是否使用非同步處理。
在onreadystatechange的監聽器中,有關readyState和status的差異,可以參考W3School。
簡單來說,readyState是指說一個請求是否被傳送出去了、是否收到回應了,其中4代表收到回應。status描述的則是伺服器對於你的請求給出了什麼樣的回應。200表示正常,404表示找不到你所請求的頁面等等。
一般來說若可以檢查到readyState === 4 && status === 200表示收到了正常的伺服器回應。
經過xhttp.send()之後,請求就會被傳送到伺服器。
由於前面有使用bodyParser,因此傳送到伺服器的附加資訊──也就是"client request"──可以由req.body取得。
===
app.get(route, function (req, res) {
console.log(req.body);
});
===.
基本上我的作法是這樣的:不論是req.body還是xhttp.send()的附加資訊,他們傳送和接收的都是字串。因此我會把JSON物件資訊先轉換為字串,接收後再解析回JSON物件。
===
// 客戶端
xhttp.send(JSON.stringify(content));
// 伺服端
console.log(JSON.parse(req.body));
===.
回到路由的部分,那個route可以是字串,比如"/about/",也可以是正規表達式。
註冊多個路由監聽函式的時候,先註冊的有高的優先權。
===
app.get("/", listener1);
app.get("/", listener2); // 這個是無用的,因為會被上面那個監聽函式搶走。
===.
而我則是習慣讓所有請求都衝著"/"來,不管甚麼方法都用同一個函式監聽。
===
app.all("/", listener);
2018年12月14日 星期五
[JavaScript] 索引類別是否影響速度
一個物件的索引可以是數字也可以是字串。是否影響速度?
LeetCode一道題目「Longest String Without Repeating Characters」中,我使用了以下方法解題:
===
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
let head = -1;
let max = 0;
let last = {};
for (let i = 0, len = s.length; i < len; i++) {
let c = <INDEX>; // INDEX
if (!(c in last)) {
last[c] = -1;
} else {
head = Math.max(head, last[c]);
}
max = Math.max(max, i - head);
last[c] = i;
}
return max;
};
===.
在<INDEX>那邊我有了兩個版本:一個是直接拿s[i]當索引的字元版本;另一個是用s.charCodeAt(i)取得ASCII碼,以數值作為索引的數值版本。
字元版本跑了160ms,數值版只要76~80ms,有著十分明顯的差距。
因此,若求速度的話,還是要用數值索引會比較適當。
LeetCode一道題目「Longest String Without Repeating Characters」中,我使用了以下方法解題:
===
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
let head = -1;
let max = 0;
let last = {};
for (let i = 0, len = s.length; i < len; i++) {
let c = <INDEX>; // INDEX
if (!(c in last)) {
last[c] = -1;
} else {
head = Math.max(head, last[c]);
}
max = Math.max(max, i - head);
last[c] = i;
}
return max;
};
===.
在<INDEX>那邊我有了兩個版本:一個是直接拿s[i]當索引的字元版本;另一個是用s.charCodeAt(i)取得ASCII碼,以數值作為索引的數值版本。
字元版本跑了160ms,數值版只要76~80ms,有著十分明顯的差距。
因此,若求速度的話,還是要用數值索引會比較適當。
2018年12月13日 星期四
[JavaScript] require
為了做模組化,可以在module.js中用export把想要的變數匯出。在main.js中用import匯入。
===
// module.jslet variable;
let func;
export {vairable, func};
// main.js
import {variable, func} from "module.js";
===.
可惜的是這個標準支援度不高,在NodeJS中也無法使用。因此可以用require代替。
基本上跟export/import是一樣的道理。
===
// module.js
let variable;
let func;
exports.variable = variable;
exports.func = func;
// main.js
const {variable, func} = require("module.js");
===.
===
// module.jslet variable;
let func;
export {vairable, func};
// main.js
import {variable, func} from "module.js";
===.
可惜的是這個標準支援度不高,在NodeJS中也無法使用。因此可以用require代替。
基本上跟export/import是一樣的道理。
===
// module.js
let variable;
let func;
exports.variable = variable;
exports.func = func;
// main.js
const {variable, func} = require("module.js");
===.
2018年11月19日 星期一
[JavaScript] random
let random = (start, end, base = 1) => {
if (Array.isArray(start)) {
return start[random(0, start.length - 1)];
} else {
return Math.floor(Math.random() * ((end - start) / base + 1)) * base + start;
}
};
if (Array.isArray(start)) {
return start[random(0, start.length - 1)];
} else {
return Math.floor(Math.random() * ((end - start) / base + 1)) * base + start;
}
};
2018年10月20日 星期六
[JavaScript] MutationObserver(監聽DOM物件的改變)
MutationObserver可以用來監聽一個DOM物件的內容是否被修改。然而,監視對象並不是在初始化階段設置的,而是在之後用方法observe時提供的。
初始化階段只聲明這個observer被觸發時的callback函式,參數有兩個:mutations,那些被監聽到的變化;target,監聽對象。
===
var observer = new MutationObserver(function (mutations, target) {
// callback
});
var options = {
childList: true,
attributes: true,
characterData: true,
subtree: true,
attributeFilter: undefined
};
observer.observe(target, options);
observer.disconnect();
===.
呼叫observe方法時監聽才開始。options中childList代表是否監聽子節點變化;attributes代表屬性的變化;characterData代表資料;subtree代表是否往下遞迴。
初始化階段只聲明這個observer被觸發時的callback函式,參數有兩個:mutations,那些被監聽到的變化;target,監聽對象。
===
var observer = new MutationObserver(function (mutations, target) {
// callback
});
var options = {
childList: true,
attributes: true,
characterData: true,
subtree: true,
attributeFilter: undefined
};
observer.observe(target, options);
observer.disconnect();
===.
呼叫observe方法時監聽才開始。options中childList代表是否監聽子節點變化;attributes代表屬性的變化;characterData代表資料;subtree代表是否往下遞迴。
2018年8月7日 星期二
[SQL Server+Node.js] 建立連線
在Node.js伺服器上要跟Microsoft的SQL Server連線需要套件mssql。
只談連線的話基本上是這樣做的。
===
const mssql = require("mssql");
var dbConfig = {
user: "<username>",
password: "<password>",
server: "localhost\\SQLEXPRESS",
database: "<database-name>"
};
mssql.connect(dbConfig, (error) => {
// 連線以後的東西在這邊不講
});
===.
問題在於有些必須做的東西很多人沒講。
從這篇可以看到,在Windows的「電腦管理/服務與應用程式」裡可以找到SQL Server的傳輸協定的設定,TCP/IP必須開啟,然後SQL Server Browser也必須開啟。為了重新啟動服務最好直接重新開機。
然而還有一種問題是SQL Server Browser無法開啟(右鍵選單啥都沒有),這種狀況下參考這篇,到「服務」裡找到SQL Server Browser右鍵內容,把他從停用改為自動或啟用。
另外有時候腦袋蠢蠢的,在<database-name>填入資料表的名稱,當然她媽不會動,這種狀況下回傳的錯誤是登入失敗(因為他找不到那個資料庫)。
只談連線的話基本上是這樣做的。
===
const mssql = require("mssql");
var dbConfig = {
user: "<username>",
password: "<password>",
server: "localhost\\SQLEXPRESS",
database: "<database-name>"
};
mssql.connect(dbConfig, (error) => {
// 連線以後的東西在這邊不講
});
===.
問題在於有些必須做的東西很多人沒講。
從這篇可以看到,在Windows的「電腦管理/服務與應用程式」裡可以找到SQL Server的傳輸協定的設定,TCP/IP必須開啟,然後SQL Server Browser也必須開啟。為了重新啟動服務最好直接重新開機。
然而還有一種問題是SQL Server Browser無法開啟(右鍵選單啥都沒有),這種狀況下參考這篇,到「服務」裡找到SQL Server Browser右鍵內容,把他從停用改為自動或啟用。
另外有時候腦袋蠢蠢的,在<database-name>填入資料表的名稱,當然她媽不會動,這種狀況下回傳的錯誤是登入失敗(因為他找不到那個資料庫)。
[JavaScript] select元件手動觸發onchange事件
select元件就是下拉式選單。它的結構長得像這樣。
===
<select>
<option value="option0">Apple</option>
<option value="option1">Banana</option>
</select>
===.
要透過JavaScript來改變select元件的值使用的是下面的方法
===
element.value = "<value>";
===.
element指的是select元件。此處的<value>要參考option元件的value值。
到這邊都是好理解的,問題在於這個做法好像有點bug,就是onchange事件不會正確地觸發。因此修改完value以後還要特地去觸發onchange事件。
===
element.value = "<value>";
var ev = document.createElement("HTMLEvents");
ev.initEvent("change", false, true);
element.dispatchEvent(ev);
===.
===
<select>
<option value="option0">Apple</option>
<option value="option1">Banana</option>
</select>
===.
要透過JavaScript來改變select元件的值使用的是下面的方法
===
element.value = "<value>";
===.
element指的是select元件。此處的<value>要參考option元件的value值。
到這邊都是好理解的,問題在於這個做法好像有點bug,就是onchange事件不會正確地觸發。因此修改完value以後還要特地去觸發onchange事件。
===
element.value = "<value>";
var ev = document.createElement("HTMLEvents");
ev.initEvent("change", false, true);
element.dispatchEvent(ev);
===.
2018年6月28日 星期四
[Git] VS Code
首先要安裝Git。然後安裝VS Code(Visual Studio Code)。
先登入並在GitHub網頁上建立倉庫(repository),複製倉庫網址,在本機系統上找到要放置倉庫的目錄,右鍵開啟Git Bash,輸入指令
===
git clone <倉庫網址>
===.
要注意,不要先行建立倉庫名稱的目錄,會產生衝突。
複製(clone)完以後應該會有一個倉庫名稱的目錄,這就是本機倉庫,裡面會有一個隱藏目錄.git。
如果Git安裝的時候並沒有設置全域使用者,在這邊就要特別設置。
一樣,在Git Bash中移動到倉庫目錄下,執行指令
===
git config user.email <GitHub帳戶>
===.
這樣之後就會以這個帳戶的身分做推提與同步。
這種設置方法是針對倉庫的,也就是說以上的指令用來設定目前工作目錄的倉庫的帳戶身分,與其他倉庫則與此無關。
如果想要設置全域的帳戶就要加上--global。
===
git config --global user.email <GitHub帳戶>
===.
總之,設置好倉庫與帳戶身分之後,就可以在VS Code以開啟目錄的方式打開這個倉庫。在VS Code的左側欄位有一個原始檔控制(Ctrl+Shift+G),這邊可以看到原始檔控制使用的是GIT,下面則標記了被變更(modified)的檔案(會標記M)、被暫存(staged)的變更。
在變更列表中,點擊被變更檔案右側的加號可以暫存該檔案的變更;或是在「變更」的右側點擊加號可以暫存所有檔案的變更。同樣的,在暫存的變更列表中,點擊減號可以取消暫存。
當暫存的變更已經可以認可(commit)的時候,在上面輸入「訊息」並點擊Ctrl+Enter以認可目前的暫存。
在VS Code的左下角,可以看到目前工作的分支(branch),這個分支預設會是master,可以理解為主線。在分支名稱的後面,星號「*」代表在本機倉庫中有尚未暫存的變更、加號「+」代表在本機倉庫中有尚未認可的暫存。
無論如何,這些版本都是存儲在本機倉庫中的,必須要推送(push)到中央(?)倉庫──也就是GitHub上的倉庫──才能做合併(merge)。同樣的,要更新本機的倉庫資訊也需要提取(pull),或者使用同步(sync)。三者都可以在原始檔控制欄的右上角找到。
比較奇妙的是,提取的時候似乎不是整個倉庫做提取,而是和目前聚焦的檔案有關,因此在提取的時候可能要先把想提取的檔案打開。
先登入並在GitHub網頁上建立倉庫(repository),複製倉庫網址,在本機系統上找到要放置倉庫的目錄,右鍵開啟Git Bash,輸入指令
===
git clone <倉庫網址>
===.
要注意,不要先行建立倉庫名稱的目錄,會產生衝突。
複製(clone)完以後應該會有一個倉庫名稱的目錄,這就是本機倉庫,裡面會有一個隱藏目錄.git。
如果Git安裝的時候並沒有設置全域使用者,在這邊就要特別設置。
一樣,在Git Bash中移動到倉庫目錄下,執行指令
===
git config user.email <GitHub帳戶>
===.
這樣之後就會以這個帳戶的身分做推提與同步。
這種設置方法是針對倉庫的,也就是說以上的指令用來設定目前工作目錄的倉庫的帳戶身分,與其他倉庫則與此無關。
如果想要設置全域的帳戶就要加上--global。
===
git config --global user.email <GitHub帳戶>
===.
總之,設置好倉庫與帳戶身分之後,就可以在VS Code以開啟目錄的方式打開這個倉庫。在VS Code的左側欄位有一個原始檔控制(Ctrl+Shift+G),這邊可以看到原始檔控制使用的是GIT,下面則標記了被變更(modified)的檔案(會標記M)、被暫存(staged)的變更。
在變更列表中,點擊被變更檔案右側的加號可以暫存該檔案的變更;或是在「變更」的右側點擊加號可以暫存所有檔案的變更。同樣的,在暫存的變更列表中,點擊減號可以取消暫存。
當暫存的變更已經可以認可(commit)的時候,在上面輸入「訊息」並點擊Ctrl+Enter以認可目前的暫存。
在VS Code的左下角,可以看到目前工作的分支(branch),這個分支預設會是master,可以理解為主線。在分支名稱的後面,星號「*」代表在本機倉庫中有尚未暫存的變更、加號「+」代表在本機倉庫中有尚未認可的暫存。
無論如何,這些版本都是存儲在本機倉庫中的,必須要推送(push)到中央(?)倉庫──也就是GitHub上的倉庫──才能做合併(merge)。同樣的,要更新本機的倉庫資訊也需要提取(pull),或者使用同步(sync)。三者都可以在原始檔控制欄的右上角找到。
比較奇妙的是,提取的時候似乎不是整個倉庫做提取,而是和目前聚焦的檔案有關,因此在提取的時候可能要先把想提取的檔案打開。
2018年5月31日 星期四
[Node.js] 建立伺服器
典型的伺服器建立方式。下面是伺服器的程式碼。這個程式碼通常取名為server.js,置放在伺服器根目錄,之後在console用「node server.js」來運行他。
===
var http = require("http");
http.createServer(function (request, response) {
response.writeHead(code, {"ContentType": mime});
response.write(content);
response.end();
}).listen(port, ip);
===.
裡面的function應該挺容易懂的,是對於客戶端得請求如何作答覆。code是200正常、404找不著那個;mime是指內容的類型,最基本的是text/plain,常見的還有text/html、text/css、text/javascript,這部分在處理一些讓客戶端自動請求的CSS、JS時需要特別處理一下,否則會發現伺服器把這些檔案當成text/plain或text/html傳出去。response.end()之後這個回應就被送出了。
http.createServer().listen()則是實質地在本機的「ip:port」上啟動一個伺服器。
伺服器開啟後,console會被占用,輸入Ctrl+C強制跳出後伺服器就算關閉了。
===
var http = require("http");
http.createServer(function (request, response) {
response.writeHead(code, {"ContentType": mime});
response.write(content);
response.end();
}).listen(port, ip);
===.
裡面的function應該挺容易懂的,是對於客戶端得請求如何作答覆。code是200正常、404找不著那個;mime是指內容的類型,最基本的是text/plain,常見的還有text/html、text/css、text/javascript,這部分在處理一些讓客戶端自動請求的CSS、JS時需要特別處理一下,否則會發現伺服器把這些檔案當成text/plain或text/html傳出去。response.end()之後這個回應就被送出了。
http.createServer().listen()則是實質地在本機的「ip:port」上啟動一個伺服器。
伺服器開啟後,console會被占用,輸入Ctrl+C強制跳出後伺服器就算關閉了。
2018年5月25日 星期五
[JavaScript] 取得視窗卷軸位置
討論垂直方向,視窗的卷軸位置在window.scrollY。
如果要知道卷軸是否碰底,可以拿視窗卷軸位置與視窗高度相加,看是否與body的高度吻合。
===
return window.scrollY + window.innerHeight === document.body.clientHeight;
===.
如果要知道卷軸是否碰底,可以拿視窗卷軸位置與視窗高度相加,看是否與body的高度吻合。
===
return window.scrollY + window.innerHeight === document.body.clientHeight;
===.
2018年5月13日 星期日
[JavaScript] 滑鼠事件中取得滑鼠位置
在滑鼠事件中,從參數ev我們可以找到ev.target,表示滑鼠的作用對象,其中ev.target.getBoundingClientRect()會回傳一個rect,這個rect包含了x、y、left、right、top、bottom、width、height,表示的是元件的位置和長寬,滑鼠的位置在ev.pageX和ev.pageY,用他減去rect.x和rect.y就行了。
補充,如果目標元件是position: fixed的話,使用ev.pageX、ev.pageY就會有問題,因為這兩個是滑鼠之於整個document的相對位置,而上面所得到的rect是元件之於視窗的位置。為了拿到滑鼠相對於視窗的位置我們可以使用ev.clientX與ev.clientY。有人會騙你去用screenX、screenY,這兩個是相對於螢幕的,與client會有些差距。
補充,如果目標元件是position: fixed的話,使用ev.pageX、ev.pageY就會有問題,因為這兩個是滑鼠之於整個document的相對位置,而上面所得到的rect是元件之於視窗的位置。為了拿到滑鼠相對於視窗的位置我們可以使用ev.clientX與ev.clientY。有人會騙你去用screenX、screenY,這兩個是相對於螢幕的,與client會有些差距。
2018年5月12日 星期六
[JavaScript] common
修正createElement。
===
var common = {};
common.createElement = function (tag, attributes, parent) {
var element = document.createElement(tag);
for (var key in attributes) {
element.setAttribute(key, attributes[key]);
}
if (parent !== undefined) {
parent.appendChild(element);
}
return element;
};
window.common = common;
===.
===
var common = {};
common.createElement = function (tag, attributes, parent) {
var element = document.createElement(tag);
for (var key in attributes) {
element.setAttribute(key, attributes[key]);
}
if (parent !== undefined) {
parent.appendChild(element);
}
return element;
};
window.common = common;
===.
[JavaScript] 偵測元件外的點擊事件(Outclick)
有些元件需要偵測在自身以外發生的點擊事件,通常依此進行失焦。
基本原理是偵測document的點擊事件,在事件參數ev中有個事件目標ev.target,顯示了點擊事件的目標元件。從這個事件目標開始往父元件搜尋,若沒比對到註冊事件的元件的話,就觸發監聽器。
暫且把這個事件稱作外點擊事件Outclick。
===
===
document.onOutclickedListeners = [];
document.addEventListener("click", function (ev) {
var listeners = $.extend(true, [], document.onOutclickedListeners);
var target = ev.target;
do {
for (var l = 0; l < listeners.length; ++l) {
var listener = listeners[l];
if (listener.element === target) {
listeners.splice(l, 1);
}
}
target = target.parentNode;
} while (target);
for (var listener of listeners) {
listener.func(ev);
}
});
document.addEventListener("click", function (ev) {
var listeners = $.extend(true, [], document.onOutclickedListeners);
var target = ev.target;
do {
for (var l = 0; l < listeners.length; ++l) {
var listener = listeners[l];
if (listener.element === target) {
listeners.splice(l, 1);
}
}
target = target.parentNode;
} while (target);
for (var listener of listeners) {
listener.func(ev);
}
});
===.
[CSS] 文字雙邊對齊(justify)
就是紀錄一下這個雙邊對齊的英文名稱叫「justify」,是text-align這個屬性的可填值之一(回想Office,雙邊對齊與靠左對齊、靠右對齊是同質的選項)。
[HTML+CSS] 修改Blogger的中文字型
該死的洋人。
從GUI修改字型的話,只有那些Arial之類的,沒有中文字型。
邏輯是這樣的:找一個WebFont(畢竟是中文,WebFont是必須的),嵌入到部落格的模板HTML中。
WebFont的嵌入分兩個部分,一部份是連結,總之就是用<link>把字型檔讀進來;另一部份就是實用,在某個我們想要套用的對象上用CSS去聲明他的字型。
<link>簡單,找到<head>隨便插入就可。
以Google提供的WebFont為例的話,就是像這樣:
===
<link href="https://fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet" />
===.
字型可以從這裡找,Source Code Pro也在其中,是個很棒的等寬字型。
中文部分就使用Noto吧。要注意在上面的網址中找到的Noto是西文版的,沒有中日韓。
中日韓版本的叫做Noto Sans CJK TC或Noto Serif CJK TC(有分區域的,TC是正體中文),在這裡。
連結是如此簡單。問題來了,字型的實用應該寫在哪裏?
在<head>寫一個CSS聲明body的字型是沒有用的,哪怕我們加上無數個!important(想當然的)。
我所知的方法是,總之先在HTML中搜尋「font」,會看到在一個叫做<b:skin>的標籤裡有很多看似被註解的XML tags,我們會看到一些關鍵字「body.font」、「header.font」等等,看來就是這裡了。
那些Variable標籤的屬性default裡記錄的東西一目瞭然,就是我們想修改的字型,而我們的WebFont就在這裡實用。
字型的實用有很多大佬給過意見了,這一篇就很實在。
簡單來說,英文,然後中文。
我的建議就是
===
'Source Code Pro', 'Noto Sans CJK TC',
===.
後面的Arial和一大票預設字型我是沒刪的。
留意一下,我們所修改的東西實質上是個字串,外面包的是雙引號,所以字型名稱的部分用的是單引號。
從GUI修改字型的話,只有那些Arial之類的,沒有中文字型。
邏輯是這樣的:找一個WebFont(畢竟是中文,WebFont是必須的),嵌入到部落格的模板HTML中。
WebFont的嵌入分兩個部分,一部份是連結,總之就是用<link>把字型檔讀進來;另一部份就是實用,在某個我們想要套用的對象上用CSS去聲明他的字型。
<link>簡單,找到<head>隨便插入就可。
以Google提供的WebFont為例的話,就是像這樣:
===
<link href="https://fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet" />
===.
字型可以從這裡找,Source Code Pro也在其中,是個很棒的等寬字型。
中文部分就使用Noto吧。要注意在上面的網址中找到的Noto是西文版的,沒有中日韓。
中日韓版本的叫做Noto Sans CJK TC或Noto Serif CJK TC(有分區域的,TC是正體中文),在這裡。
連結是如此簡單。問題來了,字型的實用應該寫在哪裏?
在<head>寫一個CSS聲明body的字型是沒有用的,哪怕我們加上無數個!important(想當然的)。
我所知的方法是,總之先在HTML中搜尋「font」,會看到在一個叫做<b:skin>的標籤裡有很多看似被註解的XML tags,我們會看到一些關鍵字「body.font」、「header.font」等等,看來就是這裡了。
那些Variable標籤的屬性default裡記錄的東西一目瞭然,就是我們想修改的字型,而我們的WebFont就在這裡實用。
字型的實用有很多大佬給過意見了,這一篇就很實在。
簡單來說,英文,然後中文。
我的建議就是
===
'Source Code Pro', 'Noto Sans CJK TC',
===.
後面的Arial和一大票預設字型我是沒刪的。
留意一下,我們所修改的東西實質上是個字串,外面包的是雙引號,所以字型名稱的部分用的是單引號。
[JavaScript] common
更新craeteElement,自動將建立的元件加入到parent。
===
var common = {};
common.createElement = function (tag, attributes, parent) {
var element = document.createElement(tag);
for (var attribute of attributes) {
element.setAttribute(attribute, attributes[attribute]);
}
if (parent !== undefined) {
parent.appendChild(element);
}
return element;
};
===.
===
var common = {};
common.createElement = function (tag, attributes, parent) {
var element = document.createElement(tag);
for (var attribute of attributes) {
element.setAttribute(attribute, attributes[attribute]);
}
if (parent !== undefined) {
parent.appendChild(element);
}
return element;
};
===.
[JavaScript] common
新增createElement,在建立元件的同時設置他的屬性。
===
var common = {};
common["createElement"] = function (tag, attributes) {
var element = document.createElement(tag);
for (var attribute of attributes) {
element.setAttribute(attribute, attributes[attribute]);
}
return element;
};
===.
===
var common = {};
common["createElement"] = function (tag, attributes) {
var element = document.createElement(tag);
for (var attribute of attributes) {
element.setAttribute(attribute, attributes[attribute]);
}
return element;
};
===.
[JavaScript] 網頁自動腳本的建議格式(Greasemonkey、Tampermonkey)
自動腳本最好還是在網頁讀取完畢之後再執行,有些情況下甚至需要一個延遲時間。大致上如下。
===
window.loadelay = 0; // 延遲時間
window.main = function () {
// 程序內容
};
window.addEventListener("load", function (ev) {
setTimeout(window.main, window.loadelay);
};
===.
===
window.loadelay = 0; // 延遲時間
window.main = function () {
// 程序內容
};
window.addEventListener("load", function (ev) {
setTimeout(window.main, window.loadelay);
};
===.
訂閱:
文章 (Atom)
[HTML] ribody
怕自己忘記,稍微紀錄一下。 各種各種理由(其中一個就是Vue,不能綁定在body上),導致時常需要一個包在body中的div,當作body來用,像這樣: === <body> <div id="divBody"> ...
-
自動腳本最好還是在網頁讀取完畢之後再執行,有些情況下甚至需要一個延遲時間。大致上如下。 === window.loadelay = 0; // 延遲時間 window.main = function () { // 程序內容 }; window.addEve...
-
let random = (start, end, base = 1) => { if (Array.isArray(start)) { return start[random(0, start.length - 1)]; } else...
-
在Node.js伺服器上要跟Microsoft的SQL Server連線需要套件mssql。 只談連線的話基本上是這樣做的。 === const mssql = require("mssql"); var dbConfig = { user: ...