Created By JishuBao on 2019-04-22 12:38:22
Recently revised in 2019-04-23 20:59css
歡迎你們來到技術寶的掘金世界,您的star是我寫文章最大的動力!GitHub地址
最近新公司在制定一套UI規範,說是爲了之後前端「即託即用」作準備。
前端
原本前端人數就很少的我和個人小郝哥開始抓緊了節奏,準備開始寫一些UI規範,可是因爲咱們倆都沒有完整的瞭解過相關的方面的製做,咱們在文檔上煞費苦心,在製做UI規範文檔中,咱們發如今Vue中並不能直接像markdown同樣寫一些代碼註釋等。致使須要這樣寫,你們感覺下: vue
其實咱們的心裏是崩潰的!若是每寫一個都這樣的話,咋整!也不是說難,就是太繁瑣,咱也不敢想!因此技術寶以爲這樣不行,而後靈機一動想到平時所用的ui框架vant,人家的官網作的是多麼的好看,而後我打開了vant的源碼,一開始我是沒怎麼看懂,後來我發現他用的是md文檔,當時我心想,這麼so easy的嗎?git
而後我直接引入了markdown文檔格式文件md文件,而後...github
明明別人的就能引入不報錯,而後我發現那些Ui框架裏面的package.json文件裏面基本上都有一個vue-markdown-loader,機智的我很快就反應過來,他不識別md格式,就和不加vue-loader不能使用Vue同樣,因此咱們仍是要加上這個vue-markdown-loader,技術寶這個時候忽然萌生了一個想法,若是本身寫一個loader呢,這樣以來,既能理解,又可以對於這個loader瞭如指掌。話很少啥,開始啓動咱們的教程吧。正則表達式
你須要知道loader是幹嗎用的,其實Loader就至關於一個「處理器」,將ts文件轉化爲js文件,將圖像轉化成內聯data url等...json
咱們來寫一個簡單的loader瀏覽器
module.exports = function (src) {
const res = (
`<template>\n` +
`<h1>hello world</h1>\n` +
`</template>`
)
return res
}
複製代碼
我認可這個loader長的確實是有一點智障的,可是這個Loader確實也作到了大部分Loader所作的事。緩存
包名稱 | 功能說明 |
---|---|
markdown-it | 渲染markdown基本語法 |
markdown-it-anchor | 爲各級標題添加瞄點 |
markdown-it-container | 用於建立自定義的塊級容器 |
markdown-it-emoji | 渲染emoji |
markdown-it-table-of-contents | 自動生成目錄 |
highlight.js | 代碼高亮 |
hash-sum | 產生一個基於的四字節十六進制哈希value |
lru-cache | 一個緩存對象,用於刪除最近最少使用的項目 |
section h1{
font-size:2em;
}
複製代碼
參考連接:h1和h2大小一致、如何去掉瀏覽器的默認樣式markdown
stringObject.replace(regexp/substr,replacement)
參數 | 參數類型 | 描述 | 是否必需 |
---|---|---|---|
stringObject | 字符串 | 一個字符串類型的值 | 是 |
regexp/substr | 正則對象/字符串 | 規定子字符串或要替換的模式的 RegExp 對象。值得注意的是若是該值是一個字符串,則將它做爲要檢索的直接量文本模式,而不是首先被轉換爲 RegExp 對象。 | 是 |
replacement | 一個字符串值 | 規定了替換文本或生成替換文本的函數 | 是 |
一個新的字符串,是用 replacement 替換了 regexp 的第一次匹配或全部匹配以後獲得的。
字符串 stringObject 的 replace() 方法執行的是查找並替換的操做。它將在 stringObject 中查找與 regexp 相匹配的子字符串,而後用replacement來替換這些子串。若是 regexp 具備全局標誌 g,那麼 replace() 方法將替換全部匹配的子串。不然,它只替換第一個匹配子串。replacement 能夠是字符串,也能夠是函數。若是它是字符串,那麼每一個匹配都將由字符串替換。可是 replacement 中的 $ 字符具備特定的含義。以下表所示,它說明從模式匹配獲得的字符串將用於替換。
字符 | 替換文本 |
---|---|
$一、$二、...、$99 | 與 regexp 中的第 1 到第 99 個子表達式相匹配的文本。 |
$& | 與 regexp 相匹配的子串。 |
$` | 位於匹配子串左側的文本。 |
$' | 位於匹配子串右側的文本。 |
$$ | 直接量符號。 |
"Jsbao是是是男神".replace('是','不是');//Jsbao不是是是男神(只匹配第一個子串)
複製代碼
2.正則表達式第一個參數是正則對象。
"Jsbao是是是男神".replace(/是/,'不是');//Jsbao不是是是男神(只匹配第一個子串)
複製代碼
3.正則表達式第一個參數是正則對象且有g全局標誌。
"Jsbao是是是男神".replace(/是/g,'不是');//Jsbao不是否是不是男神(匹配全部子串)
複製代碼
4.正則表達式第二個參數是帶有特殊含義的符號
"Jsbao是是是男神".replace(/(是)/g,'不$1');//Jsbao不是否是不是男神(匹配全部子串)
複製代碼
注意$1此類特殊符號表明匹配的子項,故正則須要加(),表明匹配子項
5.正則表達式第二個參數是函數。
"Jsbao是男神".replace(/(是|男)/g,function(value){return value==='是'?'不是':'女'});//Jsbao不是女神
複製代碼
此文中遇到的replace
str.replace(/(<pre|<code)/g,'$1 v-pre');//意思應該是將<pre或者<code替換成<pre v-pre或<code pre的形式
複製代碼
參考連接:replace函數的做用
Object.defineProperty() 方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現有屬性, 並返回這個對象。
Object.defineProperty(obj, prop, descriptor)
參數 | 描述 |
---|---|
obj | 要在其上定義屬性的對象 |
prop | 要定義或修改的屬性的名稱 |
descriptor | 將定義或修改的屬性描述符 |
被傳遞給函數的對象。
在ES6中,因爲 Symbol類型的特殊性,用Symbol類型的值來作對象的key與常規的定義或修改不一樣,而Object.defineProperty 是定義key爲Symbol的屬性的方法之一。
該方法容許精確添加或修改對象的屬性。經過賦值操做添加的普通屬性是可枚舉的,可以在屬性枚舉期間呈現出來(for...in 或 Object.keys 方法), 這些屬性的值能夠被改變,也能夠被刪除。這個方法容許修改默認的額外選項(或配置)。默認狀況下,使用 Object.defineProperty() 添加的屬性值是不可修改的。
對象裏目前存在的屬性描述符有兩種主要形式:數據描述符和存取描述符。數據描述符是一個具備值的屬性,該值多是可寫的,也可能不是可寫的。存取描述符是由getter-setter函數對描述的屬性。描述符必須是這兩種形式之一;不能同時是二者。
屬性 | 描述 | 是不是數據描述符屬於的鍵值 | 是不是存取描述符屬於的鍵值 |
---|---|---|---|
configurable | 當且僅當該屬性的 configurable 爲 true 時,該屬性描述符纔可以被改變,同時該屬性也能從對應的對象上被刪除。默認爲 false。 | 是 | 是 |
enumerable | 當且僅當該屬性的enumerable爲true時,該屬性纔可以出如今對象的枚舉屬性中。默認爲 false。 | 是 | 是 |
value | 該屬性對應的值。能夠是任何有效的 JavaScript 值(數值,對象,函數等)。默認爲 undefined。 | 是 | 否 |
writable | 當且僅當該屬性的writable爲true時,value才能被賦值運算符改變。默認爲 false。 | 是 | 否 |
get | 一個給屬性提供 getter 的方法,若是沒有 getter則爲undefined。當訪問該屬性時,該方法會被執行,方法執行時沒有參數傳入,可是會傳入this對象(因爲繼承關係,這裏的this並不必定是定義該屬性的對象)。默認爲 undefined。 | 否 | 是 |
set | 一個給屬性提供 setter 的方法,若是沒有 setter 則爲undefined。當屬性值修改時,觸發執行該方法。該方法將接受惟一參數,即該屬性新的參數值。默認爲 undefined。 | 否 | 是 |
若是一個描述符不具備value,writable,get 和 set 任意一個關鍵字,那麼它將被認爲是一個數據描述符。若是一個描述符同時有(value或writable)和(get或set)關鍵字,將會產生一個異常。
記住,這些選項不必定是自身屬性,若是是繼承來的也要考慮。爲了確認保留這些默認值,你可能要在這以前凍結 Object.prototype,明確指定全部的選項,或者經過 Object.create(null)將__proto__屬性指向null。
// 使用 __proto__
var obj = {};
var descriptor = Object.create(null); // 沒有繼承的屬性
// 默認沒有 enumerable,沒有 configurable,沒有 writable
descriptor.value = 'static';
Object.defineProperty(obj, 'key', descriptor);
// 顯式
Object.defineProperty(obj, "key", {
enumerable: false,
configurable: false,
writable: false,
value: "static"
});
// 循環使用同一對象
function withValue(value) {
var d = withValue.d || (
withValue.d = {
enumerable: false,
writable: false,
configurable: false,
value: null
}
);
d.value = value;
return d;
}
// ... 而且 ...
Object.defineProperty(obj, "key", withValue("static"));
// 若是 freeze 可用, 防止代碼添加或刪除對象原型的屬性
// (value, get, set, enumerable, writable, configurable)
(Object.freeze||Object)(Object.prototype);
複製代碼
若是對象中不存在指定的屬性,Object.defineProperty()就建立這個屬性。當描述符中省略某些字段時,這些字段將使用它們的默認值。擁有布爾值的字段的默認值都是false。value,get和set字段的默認值爲undefined。一個沒有get/set/value/writable定義的屬性被稱爲「通用的」,並被「鍵入」爲一個數據描述符。
var o = {}; // 建立一個新對象
// 在對象中添加一個屬性與數據描述符的示例
Object.defineProperty(o, "a", {
value : 37,
writable : true,
enumerable : true,
configurable : true
});
// 對象o擁有了屬性a,值爲37
// 在對象中添加一個屬性與存取描述符的示例
var bValue;
Object.defineProperty(o, "b", {
get : function(){
return bValue;
},
set : function(newValue){
bValue = newValue;
},
enumerable : true,
configurable : true
});
o.b = 38;
// 對象o擁有了屬性b,值爲38
// o.b的值如今老是與bValue相同,除非從新定義o.b
// 數據描述符和存取描述符不能混合使用
Object.defineProperty(o, "conflict", {
value: 0x9f91102,
get: function() {
return 0xdeadbeef;
}
});
// throws a TypeError: value appears only in data descriptors, get appears only in accessor descriptors
複製代碼
若是屬性已經存在,Object.defineProperty()將嘗試根據描述符中的值以及對象當前的配置來修改這個屬性。若是舊描述符將其configurable 屬性設置爲false,則該屬性被認爲是「不可配置的」,而且沒有屬性能夠被改變(除了單向改變 writable 爲 false)。當屬性不可配置時,不能在數據和訪問器屬性類型之間切換。
當試圖改變不可配置屬性(除了value和writable 屬性以外)的值時會拋出TypeError,除非當前值和新值相同。
當writable屬性設置爲false時,該屬性被稱爲「不可寫」。它不能被從新分配。
var o = {}; // Creates a new object
Object.defineProperty(o, 'a', {
value: 37,
writable: false
});
console.log(o.a); // logs 37
o.a = 25; // No error thrown
// (it would throw in strict mode,
// even if the value had been the same)
console.log(o.a); // logs 37. The assignment didn't work.
// strict mode
(function() {
'use strict';
var o = {};
Object.defineProperty(o, 'b', {
value: 2,
writable: false
});
o.b = 3; // throws TypeError: "b" is read-only
return o.b; // returns 2 without the line above
}());
複製代碼
enumerable定義了對象的屬性是否能夠在 for...in 循環和 Object.keys() 中被枚舉。
var o = {};
Object.defineProperty(o, "a", { value : 1, enumerable:true });
Object.defineProperty(o, "b", { value : 2, enumerable:false });
Object.defineProperty(o, "c", { value : 3 }); // enumerable defaults to false
o.d = 4; // 若是使用直接賦值的方式建立對象的屬性,則這個屬性的enumerable爲true
for (var i in o) {
console.log(i);
}
// 打印 'a' 和 'd' (in undefined order)
Object.keys(o); // ["a", "d"]
o.propertyIsEnumerable('a'); // true
o.propertyIsEnumerable('b'); // false
o.propertyIsEnumerable('c'); // false
複製代碼
configurable特性表示對象的屬性是否能夠被刪除,以及除value和writable特性外的其餘特性是否能夠被修改。
var o = {};
Object.defineProperty(o, "a", { get : function(){return 1;},
configurable : false } );
// throws a TypeError
Object.defineProperty(o, "a", {configurable : true});
// throws a TypeError
Object.defineProperty(o, "a", {enumerable : true});
// throws a TypeError (set was undefined previously)
Object.defineProperty(o, "a", {set : function(){}});
// throws a TypeError (even though the new get does exactly the same thing)
Object.defineProperty(o, "a", {get : function(){return 1;}});
// throws a TypeError
Object.defineProperty(o, "a", {value : 12});
console.log(o.a); // logs 1
delete o.a; // Nothing happens
console.log(o.a); // logs 1
複製代碼