資料彙總

天貓精靈998發表於2020-06-24

指定內容

由淺入深,66條JavaScript面試知識點
ES6入門 - 阮一峰
在阿里我是如何當面試官的
第三期:前端九條bug分享
記一次grid佈局實戰應用分享會
最強大的 CSS 佈局 —— Grid 佈局
JavaScript 繼承的八種寫法
「前端料包」深究JavaScript作用域(鏈)知識點和閉包
「牛客網」45道JS能力測評經典題總結
Vue經常會問到的面試題
正規表示式不要背
「前端料包」深入理解JavaScript原型和原型鏈

8月29日內容彙總

this.$nextTick的實現
其實就是利用promise把nextTick要執行的內容放到微任務佇列,微任務佇列裡的任務會在當前一次的事件迴圈結束後執行,不支援promise的話就會換成setTimeout

8月28日內容彙總

cookie相關

Cookie 的SameSite屬性用來限制第三方 Cookie,從而減少安全風險。可以設定三個值:Strict,Lax,None
Cookie 的 SameSite 屬性 - 阮一峰

只要在Set-Cookie中附帶了HttpOnly這個屬性,那麼這個Cookie就無法被JS指令碼獲取
怎樣指定當前cookie不能通過js指令碼獲取

moment.js設定24小時制

設定24小時制:小時格式設定為大寫HH,例如:
YYYY-MM-DD HH:mm:ss==>2018-01-18 20:01:17
設定12小寫時為12小時制,例如
YYYY-MM-DD hh:mm:ss==>2018-01-18 08:01:17

8月27日內容彙總

銀行EPI專項試題
農業銀行筆試試題
2018農業銀行春季校園招聘科技崗筆試科目及經驗 - 百度文庫
中國農業銀行2018年校園招聘筆試考試真題及答案【最新】

8月26日內容彙總

今天看了一個Object.create的實現,裡面有一步是給空函式指定prototype,感覺這個用法比較奇怪,後來看了JS的繼承,這實際上就是原型式繼承,利用一個空物件作為中介,將某個物件直接賦值給空物件建構函式的原型。

Object.myCreate = function (obj, properties)  {
  var F = function ()  {}
  F.prototype = obj
  if (properties) {
     Object.defineProperties(F, properties)
  }
  return new F()
}

Object.myCreate({}, {a: {value: 1}})     // {a: 1}

Object.create() 和 new Object()
JavaScript 繼承的八種寫法

8月25日內容彙總

Vue雙向繫結實現

vue.js 則是採用資料劫持結合釋出者-訂閱者模式的方式,通過Object.defineProperty()來劫持各個屬性的setter,getter,在資料變動時釋出訊息給訂閱者,觸發相應的監聽回撥。

核心:通過Object.defineProperty()來實現對屬性的劫持,達到監聽資料變動的目的
要實現mvvm的雙向繫結,就必須要實現以下幾點:

1、實現一個資料監聽器Observer,能夠對資料物件的所有屬性進行監聽,如有變動可拿到最新值並通知訂閱者
2、實現一個指令解析器Compile,對每個元素節點的指令進行掃描和解析,根據指令模板替換資料,以及繫結相應的更新函式
3、實現一個Watcher,作為連線Observer和Compile的橋樑,能夠訂閱並收到每個屬性變動的通知,執行指令繫結的相應回撥函式,從而更新檢視
4、mvvm入口函式,整合以上三者

vue雙向繫結原理分析
剖析Vue原理&實現雙向繫結MVVM

8月24日內容彙總

JS物件的hasOwnProperty方法

Object的hasOwnProperty()方法返回一個布林值,判斷物件是否包含特定的自身(非繼承)屬性。

var obj = {name: "32233232332"};
console.log(obj.hasOwnProperty(name)); // true

常見用法:
1.判斷自身屬性是否存在;
2.判斷自身屬性與繼承屬性;
3.遍歷一個物件的所有自身屬性;
for…in迴圈物件的所有列舉屬性,然後再使用hasOwnProperty()方法來忽略繼承屬性
js屬性物件的hasOwnProperty方法

JS中的reduce()方法

reduce() 方法接收一個函式作為累加器,陣列中的每個值(從左到右)開始縮減,最終計算為一個值。

array.reduce(function(total, currentValue, currentIndex, arr), initialValue)

total:必須,初始值, 或者計算結束後的返回值。如果沒有指定初始值initialValue,那麼total開始的值為陣列第一項。
currentValue:必須,當前元素。

常見用法:

var arr = [3,9,4,3,6,0,9];

// 1. 求陣列項之和
var sum = arr.reduce(function (prev, cur) {
    return prev + cur;
},0);

// 2. 求陣列項最大值
var max = arr.reduce(function (prev, cur) {
    return Math.max(prev,cur);
});

// 3. 陣列去重
var newArr = arr.reduce(function (prev, cur) {
    prev.indexOf(cur) === -1 && prev.push(cur);
    return prev;
},[]);

// 4. 統計陣列中每個元素出現的次數
const arr = ["j", "s", "h", "d", "j", "s", "i", "h", "h"];
const obj = arr.reduce((pre,item) => {
	pre[item] ? pre[item] ++ : pre[item] = 1
	return pre
},{})
console.log(obj) // {j: 2, s: 2, h: 3, d: 1, i: 1}

8月23日內容彙總

初始化Vue模板
VS Code輸入vue然後ta’b

我在阿里招前端,我該怎麼幫你?
拿不到大廠offer ?簡歷你就寫錯了!
前端效能優化:當頁面渲染遇上邊緣計算
Vue面試題彙總【精品問答】
58道Vue常見面試題集錦,涵蓋入門到精通,自測 Vue 掌握程度
22個ES6面試、複習乾貨知識點彙總

8月21日內容彙總

ES6箭頭函式

箭頭函式不能訪問arguments

// 這樣寫會報錯
const getArgs = () => arguments
// 但是可以通過剩餘運算子取到所有引數
const getArgs2 = (...rest) => rest

箭頭函式沒有自己的this值,它捕獲詞法作用域函式的this值,在此示例中,addAll函式將複製computeResult 方法中的this值。

const data = {
  result: 0,
  nums: [1, 2, 3, 4, 5],
  computeResult() {
    const addAll = () => {
      let {result, nums} = this;
      console.log(result, nums);
    }
    return addAll()
  }
}
data.computeResult(); // 0 [1, 2, 3, 4, 5]

如果箭頭函式外面沒有函式,那麼this就指向window物件。換句話說,箭頭函式如果想取到當前物件的this,那就必須巢狀在一個函式中。

const data = {
  result: 0,
  nums: [1, 2, 3, 4, 5],
  addAll: () => {
    let {result, nums} = this;
    console.log(result, nums);
  }
}
data.addAll(); // undefined undefined

其他內容

圖解 Vue 響應式原理
圖解 Vue 非同步更新原理
網頁佈局都有哪種?一般都用什麼佈局?- 淘系技術
有意思的 Node.js 記憶體洩漏問題

8月20日內容彙總

微軟實習招聘

2021 Graduates Summer Intern - Software Engineer Intern - Cloud + AI – Shanghai

混入mixin和moment外掛

報錯replace of undefined導致頁面載入阻塞

混入mixin類似於Object.assign,可以用於全域性註冊某些方法,比如全域性註冊時間處理函式。

混入 (mixin) 提供了一種非常靈活的方式,來分發 Vue元件中的可複用功能。當元件和混入物件含有同名選項時,資料物件在內部會進行遞迴合併,並在發生衝突時以元件資料優先。

混入 - vue官方文件

格式化時間外掛moment
Moment.js官方文件
moment.js外掛使用

8月19日內容彙總

JS中require和import的區別

JS 中的require 和 import 區別 - 莉莉安~
JS 中的require 和 import 區別 - 大橙子

JS中訪問物件屬性

在JavaScript中,可以使用“ . ”和“ [ ] ”來訪問物件的屬性。其中“ . ”既可以用來訪問屬性,也能用來設定屬性,而“ [ ] ”只能用來訪問屬性,不能用來設定屬性。

JS Object物件方法

Object本身是一個函式,可以當作工具方法使用,將任意值轉為物件。
Object不僅可以當作工具函式使用,還可以當作建構函式使用,即前面可以使用new命令。

注意,通過var obj = new Object()的寫法生成新物件,與字面量的寫法var obj = {}是等價的。或者說,後者只是前者的一種簡便寫法。

Object 物件的靜態方法
所謂“靜態方法”,是指部署在Object物件自身的方法

1.Object.keys() 遍歷物件的(屬性名,索引),並返回一個陣列,該陣列成員都是物件自身的(不是繼承的),Object.keys方法只返回可列舉的屬性
2.Object.getOwnPropertyNames() 遍歷物件的(屬性名,索引),並返回一個陣列,該陣列成員都是物件自身的(不是繼承的),Object.getOwnPropertyNames方法還能返回不可列舉的屬性名
3.Object.getOwnPropertyDescriptor( obj, prop) 返回一個指定物件上的自有屬性對應的屬性描述 (自由屬性指,直接賦值的屬性,不需要從原型上查詢的屬性)
4.Object.defineProperty( obj, prop, decriptor) 直接在一個物件上定義一個新屬性,或修改一個物件的現有屬性,並返回這個物件,預設情況下使用此方法新增的屬性值是不能被修改的
5.Object.assign() 法用於物件的合併,將源物件(source)的所有可列舉屬性,複製到目標物件(target)

Object物件的例項方法
除了Object物件本身的方法,還有不少方法是部署在Object.prototype物件上的,所有Object的例項物件都繼承了這些方法。Object例項物件的方法,主要有以下六個

a). valueOf() 返回當前物件對應的值
b). toString() 返回當前物件對應的字串形式,用來判斷一個值的型別
c). toLocaleString() 返回當前物件對應的本地字串形式
d). hasOwnProperty() 判斷某個屬性是否為當前物件自身的屬性,還是繼承自原型物件的屬性
e). isPrototypeOf() 判斷當前物件是否為另一個物件的原型
f). propertyIsEnumerable() 判斷某個屬性是否可列舉

JS Object物件的方法總結( ES5 與 ES6 )
ES6入門教程——物件的擴充套件 - 阮一峰

JS檢查空物件

將json物件轉化為json字串,再判斷該字串是否為"{}"。這裡不能用toString,否則無論是否為空,一律返回"[object Object]"。

var data = {};
var b = (JSON.stringify(data) == "{}");
console.log(b) // true

ES6的Object.keys()方法,返回值是物件中屬性名組成的陣列。

var data = {};
var arr = Object.keys(data);
console.log(arr.length == 0); // true

Vue中的data為什麼要寫成函式形式

Vue中的data通常是這樣寫的

同一個元件被複用多次,會建立多個例項。這些例項用的是同一個建構函式,如果data是一個物件的話。那麼所有元件都共享了同一個物件。為了保證元件的資料獨立性要求每個元件必須通過data函式返回一個物件作為元件的狀態。

<script>
export default {
	data: function() {
		return {
		}
	}
	// 也可以這樣簡寫
	data() {
		return {
		}
	}
}
</script>

類陣列轉陣列彙總

將類陣列,例如Set物件,arguments物件轉為陣列

let ary = new Set([5, 6, 7, 8]);
arr = Array.prototype.slice.call(ary); // ES5中常用方法
arr = Array.hasOwnProperty('from') && Array.from(ary);
arr = [...ary];

附件上傳實現loading

直接使用element的v-loading實現

upload(item) {
  const formData = new FormData();
  formData.append("mpf", item.file);
  const _t = this;

  _t.edit.uploading = true; // 開啟loading
  api.sysInfo
    .uploadImage(formData)
    .then(res => {
      const a = {
        url: res.url,
        name: res.name
      };
      if (_t.baseform.demandAttachments == null) {
        _t.baseform.demandAttachments = [];
      }
      if (_t.demandAttachments == null) {
        _t.demandAttachments = [];
      }
      _t.baseform.demandAttachments = [..._t.baseform.demandAttachments, a];
      _t.demandAttachments.push(res);
      this.$message.success("檔案上傳成功");
      this.changeCommand(
        this.demand,
        _t.baseform.demandAttachments,
        "demandAttachments"
      );
    })
    .catch(err => {
      this.$message.error(`${err}`);
    })
    .finally( () => {
      this.edit.uploading = false; // 關閉loading
    });
},

Object.assign()的用法

在專案中有一個場景,有一個標籤列表tagList,可以從tagList中選取標籤關聯到實體上,即將標籤加入selectedTags中,同時tagList中的標籤還支援編輯。互動的同學提了一個要求,編輯tagList裡面的標籤,如果這個標籤已被關聯,那麼實體上的標籤也需要同步更新。換句話說,selectedTags是tagList的子集,當tagList中有元素更新的話,如果selectedTags中也有這個元素,那麼這個元素也需要更新。

之前的方案是更新之後將這個元素傳過來,通過forEach迴圈根據id查詢selectedTags有沒有匹配項,如果有那就將這個元素裡面的每個欄位賦值給selectedTags中的元素。後來將forEach改為find方法,用Object.assign方法代替每個欄位賦值。這樣發現有個問題,如果find沒有找到元素,那麼tag就是undefined,但undefined是無法新增屬性的。

 modifuSuccess(obj) {
	const tag = this.selectedTags.find(({id}) => id === obj.id);
	Object.assign(tag, obj);
},

這裡這樣改一下就正常了。

 modifuSuccess(obj) {
	const tag = this.selectedTags.find(({id}) => id === obj.id);
	tag && Object.assign(tag, obj);
},

這裡順便說一下Object.assign()的用法。

這裡是tag物件中的屬性

color: "6"
createTime: "2020-08-18T13:39:47.147+0800"
creator: "加菲貓"
id: "5f3a20a7d2829a00014b1915"
modifier: "加菲貓"
modifyTime: "2020-08-19T15:40:59.336+0800"
name: "京東錢包"
projectId: 185
status: 1

這裡是obj物件的屬性,可以看到,這裡color和name被更新了。如果想要將obj中的內容合併到tag中,就可以使用Object.assign()方法。對tag和obj進行合併,改動也會同步到selectedTags上,因為這兩個實際上是聯動的。

color: "4"
id: "5f3a20a7d2829a00014b1915"
name: "京東錢包2333"

Object.assign是ES6新新增的介面,主要的用途是用來合併多個JavaScript的物件。

Object.assign()介面可以接收多個引數,第一個引數是目標物件,後面的都是源物件,assign方法將多個原物件的屬性和方法都合併到了目標物件上面,如果在這個過程中出現同名的屬性(方法),後合併的屬性(方法)會覆蓋之前的同名屬性(方法)。

var target  = {a : 1}; //目標物件
var source1 = {b : 2}; //源物件1
var source2 = {c : 3}; //源物件2
var source3 = {c : 4}; //源物件3,和source2中的物件有同名屬性c
var result = Object.assign(target,source1,source2,source3); // {a:1,b:2,c:4}

注意:Object.assign進行的是淺拷貝,所以上面result和target是聯動的。
淺談Object.assign

8月18日內容彙總

v-if和v-for不能同時使用

在vue的官方文件中是這樣說的: 注意我們不推薦在同一標籤上使用 v-if 和 v-for。當它們處於同一節點,v-for 的優先順序比 v-if 更高,v-for會先於v-if執行,這意味著 v-if 將分別重複執行於每個 v-for 迴圈中,造成效能浪費。v-if巢狀v-for和v-for巢狀v-if都是可以的,也可以使用計算屬性computed。

template的使用

如下所示,在v-for的外面套一個div,使用v-if進行判斷,這樣的話,在渲染之後在迴圈的div外面還會多一個div。

<div v-if="true">
	<div v-for="(item, index) in array" :key="index">
		{{ item.name }}
	</div>
</div>

在這裡插入圖片描述

如果不希望有這個div,可以使用template

<template v-if="true">
	<div v-for="(item, index) in array" :key="index">
		{{ item.name }}
	</div>
</template>

其他內容
VMware 虛擬化技術
我在阿里寫程式碼學會的六件事

8月17日內容彙總

Grid 網格佈局

專案中需要實現一個三欄的佈局(如下所示),用彈性佈局比較難實現,因為彈性佈局實際上是軸線佈局,即使把每一個專案的寬度設為33%,當空間不足的時候還是會換行(專案有一個最小寬度)。而且彈性佈局還有一個很大的問題,彈性佈局的專案之間預設是不會有間距的,也就是上下左右都是緊挨著的,當需要設定間距的時候一般用margin-right和margin-bottom,但是這樣的話每個專案佔的寬度就不好確定了,box-sizing屬性也不管用了,所以也沒辦法準確知道每個專案的比例是多少。
在這裡插入圖片描述
網格佈局特別適合這樣的場景,當設定了行數或者列數之後,專案的佈局就確定了,不會發生換行。而且在網格佈局下,專案之間如果需要有間距,不用設定margin,直接設定行間距和列間距即可,順便還解決了邊緣元素的margin問題。

啟用grid佈局,只需要將父容器的display屬性設為grid即可。

.box {
	display: grid;
}

啟用了grid佈局之後,使用瀏覽器審查元素就會出現下面的網格。
在這裡插入圖片描述
想要實現三欄佈局,只需要設定一下列數和列寬

.container {
  display: grid;
  grid-template-columns: 100px 100px 100px; /* 可以指定具體長度作為列寬 */
  grid-template-columns: 33.33% 33.33% 33.33%; /* 也可以使用百分比作為列寬 */
  grid-template-columns: repeat(3, 33.33%); /* 重複寫同樣的值用repeat就行 */
  grid-template-columns: 70% 30%; /* 兩欄式佈局只要這樣寫 */
  grid-template-columns: 1fr 2fr; /* fr即片斷,表示剩餘空間做等分,後者的寬度是前者的兩倍 */
  grid-template-columns: repeat(12, 1fr); /* 傳統的十二網格佈局 */
  grid-template-columns: repeat(3, 1fr); /* 實現三欄佈局 */
  grid-template-columns: repeat(3, 33.33%); /* 使用百分比也是可以的 */
}

實際開發的時候發現, 使用grid-template-columns: repeat(3, 1fr);的話,某個專案內部如果有很多內容,這一欄就會特別寬。
在這裡插入圖片描述
使用grid-template-columns: repeat(3, 33%);則沒有這樣的問題。
在這裡插入圖片描述
同樣的方法還可以設定行數和行高。

.container {
  display: grid;
  grid-template-rows: repeat(3, 33.33%);
}

設定行間距和列間距。需要注意的是,設定了列間距後,列間距本身也會佔據一部分父容器寬度,所以在三欄佈局下,如果專案寬度還是按33.33%的話,那麼內部元素寬度就會超出父容器,這種情況下推薦使用fr來表示列寬。

.container {
  grid-row-gap: 20px; /* 行間距 */
  grid-column-gap: 20px; /* 列間距 */
  grid-gap: 20px 20px; /* grid-gap屬性是grid-column-gap和grid-row-gap的合併簡寫形式 */
  
  /* 根據最新標準,上面三個屬性名的grid-字首已經刪除 */
  row-gap: 20px; /* grid-row-gap寫成row-gap */
  column-gap: 20px; /* grid-column-gap寫成column-gap */
  gap: 20px 20px; /* grid-gap寫成gap */
}

參考:CSS Grid 網格佈局教程 - 阮一峰

JS內建物件

Arguments, Boolean, Date, Error, Function, JSON, Math, Number, Array, Object, RegExp, String
JS所有內建物件屬性和方法彙總

Call()的實現

昨天看了一個視訊,是關於call()的實現,看了下程式碼都是ES5的老語法,很多地方其實可以優化的。

  1. 那句for迴圈,其實就是為了取除第一項之外的剩餘引數,我們可以使用ES6的剩餘運算子;

  2. 然後為了將陣列中的元素拆分出來給函式傳參,他這裡用了字串拼接和eval()函式,在ES6中只要一個延展運算子就能解決問題;

有同學看到這裡用了ES5裡面常用的邏輯或,可能會說ES6中不是有函式預設值嗎,為什麼不用函式預設值呢?因為只有傳入的引數為undefined才會觸發預設值,在這裡傳入的物件可以是null,這樣就會報錯了,因為不能給null新增屬性。

有同學說既然是把陣列的第一項拿掉,可不可以用shift()呢?實際上把陣列的第一項移除,那麼剩下的每一項的下標都要往前移一位,所以shift()的複雜度也是O(n),跟迴圈或者剩餘運算子沒有區別。順便一提,…放在等號右邊叫延展運算子,…放在等號左邊或者形參上叫剩餘運算子,兩者的作用恰好相反,其內部也是通過for of迴圈實現的。

// 可以使用shift()方法
const newArguments = Array.from(arguments).shift();
// 也可以使用剩餘運算子
[obj, ...newArguments] = arguments;

這裡說明一下,arguments物件其實不是真正的陣列,而是類陣列(array-like)的物件,類陣列雖然可以像陣列一樣通過下標訪問元素(例如arguments[0]),並且也有length屬性,但是類陣列不能直接呼叫陣列的API,陣列的操作方法都不能用,類陣列的迴圈遍歷只能用for(試了一下for in和for of也是可以的)。這裡如果要呼叫陣列的shift方法,需要使用Array.from將類陣列轉為陣列。

原來的程式碼如下:

Function.prototype.newCall = function(obj) {
    var obj = obj || window;
    obj.p = this;
    var newArguments = [];
    for (var i=1; i<arguments.length; i++) {
        newArguments.push('arguments[' + i + ']');
    }
    var result = eval('obj.p(' + newArguments + ')');
    delete obj.p;
    return result
}

優化以後的程式碼如下:

Function.prototype.newCall = function(obj, ...newArguments ) {
    var obj = obj || window;
    obj.p = this;
    var result = obj.p(...newArguments);
    delete obj.p;
    return result
}

上測試用例:

function person(a, b, c, d) {
    return {
        name: this.name,
        a: a, b: b, c: c, d: d
    }
}

const user = { name: '加菲貓' };

let res = person.newCall(user, '肥宅', '吃雞', '桌遊', '王者');
console.log(res);

成功拿到結果

{name: "加菲貓", a: "肥宅", b: "吃雞", c: "桌遊", d: "王者"}

其他內容

最新!Apache Struts 又爆安全漏洞(危害程度特別大)

8月16日內容彙總

Koa - 基於 node.js 平臺的下一代 web 開發框架

8月15日內容彙總

Vue 3.0 開發文件

Vue 3.0 開發文件

重點內容:

Vite(官方推薦的用於替代webpack的構建工具)
Composition API
新的響應式機制
計算屬性和偵聽器
teleport (傳送)
Fragment(碎片)
自定義事件($emit 驗證)
元件的 v-model 升級

TypeScript

TypeScript 是由微軟開發的開源、跨平臺的程式語言。它是 JavaScript 的超集,最終會被編譯為 JavaScript 程式碼。TypeScript 起源於使用 JavaScript 開發的大型專案。由於 JavaScript 的侷限性,難以勝任和維護大型專案開發。因此微軟開發了 TypeScript ,使其能夠勝任開發大型專案。

其他內容
使用Nuxt.js搭建VUE應用的SSR(服務端渲染)
兩種方式識別“傳統”圖片驗證碼 - 淘系技術
從架構到原始碼:一文了解Flutter渲染機制 - 阿里技術
阿里淘系優質開源專案推薦 - 淘系技術

8月14日內容彙總

彈框展開載入內容

經常遇到一個場景,當一個彈框元件展開的時候自動載入內容,元件關閉的時候又要自動清空內容。之前的做法就是通過watch監聽isShow的變化,如果為true,那麼就去請求介面,如果為false,就去清空內容。(不能用created鉤子,因為彈框關閉後元件並不會銷燬,所以再次點開彈框並不能觸發請求)

今天遇到一個問題,有同事需要確定彈框的高度,如果是先顯示彈框再載入內容的話,高度就無法確定了。那就只能把載入的方法拿到外面執行。在元件內部定義載入內容方法和清空內容方法,然後通過外部呼叫去執行。

這裡做個簡單示範,TagRelatedPopup.vue彈框元件內容如下

<template>
	<div>
		<popup-wrap :visible.sync="isShow"></popup-wrap>
	</div>
</template>

<script>
import PopupWrap from '@/views/common/PopupWrap';
export default {
	components: {
		PopupWrap
	},
	data() {
		isShow: false,
		tagList: []
	},
	props: {
		selectedTags: {
	      type: Array,
	      default: () => {
	        return []
	      }
	    },
	}
	methods: {
		// 從後端介面拉取資料的方法
		getCustomTags() {
			let id = this.$route.params.id;
			return api.minderTag.getTag(id)
				.then((data) => {
					this.tagList = [...data];
				})
				.catch((err) => {
				  	this.$message.error(err);
				})
		},
		// 從props獲取已關聯的標籤
		getRelatedTags() {
  			this.selected = this.selectedTags.map(x => x.id)
	    },
	    // 開啟彈框的方法
		async handleOpen() {
			// 獲取非同步資料
			await this.getCustomTags();
			// 獲取同步資料
			this.getRelatedTags();
			this.isShow= true;
		}
	}
}
</script>

從外部呼叫handleOpen方法

<template>
	<tag-relate-popup ref="tagRelateBox"></tag-relate-popup>
</template>

<script>
import TagRelatePopup from '@/views/common/TagRelatePopup';
export default {
	components: {
		TagRelatePopup
	},
	methods: {
		showtagRelateBox() {
	    	this.$refs.tagRelateBox.handleOpen();
	    }
	}
}
</script>

utils.js的用法

專案中有一個場景,後端傳數字,前端根據數字匹配顏色,而數字和顏色的對映關係是儲存在前端的。這個對映關係可以直接寫在data中,但是如果別的地方需要呼叫就不方便了。可以將這個關係儲存在utils.js檔案中。

// utils.js 的內容
export const tagColorMapping = [
  '#3D3D3D',
  '#00C565',
  '#1E83FF',
  '#953EFF',
  '#00C7CF',
  '#FFA200',
  '#FF7516',
  '#FF3C84',
  '#FF4D4D',
  '#0FBCEB'
]

有元件需要呼叫的話,直接import一下就行了

<script>
import { tagColorMapping as colorMapping } from '@/views/common/utils';
export default {
	data() {
		colorMapping
	}
}
</script>

JS中map(),filter()和forEach()

map()方法跟forEach()方法類似,map() 方法返回一個新陣列,不改變原始陣列。需要注意的是,map()中的回撥函式必須要return返回值,不然會返回一個undefind的陣列

array.map(function(currentValue,index,arr), thisValue)

常見的用法是將原始陣列的值經過處理後裝到新的陣列裡面

const arr = [1, 2, 3, 4, 5];
const arr2 = arr.map(item => return item + 1);

filter() 方法建立一個新的陣列,新陣列中的元素是通過檢查指定陣列中符合條件的所有元素,並且回撥函式中也需要return返回值

const arr = [1, 2, 2, 3, 4, 4, 5, 6];
// 陣列去重
const unique = arr.filter((item, index) => {
	// 過濾條件是陣列下標與檢索下標一致
	return arr.indexOf(item) == index;
})

在不需要返回值的時候,建議使用forEach()

array.forEach(function(currentValue, index, arr), thisValue)

表單校驗空格

專案中要求校驗某個欄位是否為空,一般的做法是這樣的

if(this.input == '') {
  this.$message.error('請輸入標籤名稱!');
  return
}

這樣的話,如果使用者輸入空格,則不會觸發這個驗證,可以使用trim()去掉空格

if(this.input.trim() == '') {
  this.input = ''; // 如果使用者輸入空格,那麼就把表單清空
  this.$message.error('請輸入標籤名稱!');
  return
}

使用includes()也可以驗證(不推薦,如果字串中間出現空格,也會觸發這個驗證)

還可以使用正規表示式

/^\S+$/ // 非空無空格
/^\S*$/ // 無空格,可以為空

非同步回撥兩種方法

非同步方法可以通過.then進行回撥,通過.catch捕獲異常

open() {
  this.$confirm('此操作將永久刪除該檔案, 是否繼續?', '提示', {
    confirmButtonText: '確定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(() => {
    this.$message({
      type: 'success',
      message: '刪除成功!'
    });
  }).catch(() => {
    this.$message({
      type: 'info',
      message: '已取消刪除'
    });          
  });
}

也可以使用async/await進行回撥,由於async返回一個Promise物件,如果await後面的語句出錯,等同於Promise被reject,異常將無法被捕獲到

async confirmDelete(tag, index) {
  await this.$confirm(`確認刪除《${tag.name}》?`, '提示', {
      confirmButtonText: '確定',
      cancelButtonText: '取消',
      type: 'warning'
    });
  // 回撥成功執行的方法
  this.deleteTag(tag, index)
},

建議將async放在try…catch…結構中,如果有多個await命令,還可以進行統一的異常處理

async function getUser() {
	try {
		const a1 = await firstStep();
		const a2 = await secondStep(a1);
		const a3 = await finalStep(a1, a2);
		console.log("Final", a3);
	} catch (err) {
		console.error(err);
	}
}

參考:async 函式 - 阮一峰

其他內容

這篇介紹的非常詳細
css3中的變形(transform)、過渡(transtion)、動畫(animation)
如何規範你的Git commit?- 阿里技術
一口氣搞懂「檔案系統」,就靠這 25 張圖了

8月13日內容彙總

slot的用法

通常元件是無法直接巢狀的

<popup-wrap>
	<div>這裡的內容不會被載入</div>
</popup-wrap>

可以通過slot嵌入內容

// 這是popupWrap元件
<template>
  <div class="popup-wrap el-popover" ref="popupWrap" :style="styles">
    <slot name="content">
    
    </slot>
  </div>
</template>
// 引用popupWrap元件,並向裡面嵌入內容
<popup-wrap :visible.sync="show"
            ref="tagRelatePopup">
	<template slot="content">
		// 這裡面是嵌入的內容
		<custom-tag-select
			ref="customTagSelect"
			@showTagEdit="handleOpenEdit"
		</custom-tag-select>
		<tag-edit-popup
			ref="tagEditPopup"
			@reloadTagList="reloadTagList">
		</tag-edit-popup>
	</template>
</popup-wrap>

封裝dialog或者popover後控制顯示與隱藏

將對話方塊或者彈出框封裝後,想通過引用它的父元件控制顯示與隱藏,不推薦使用傳參的方法,因為如果彈窗開啟後,點選旁邊的modal或者右上角的×同樣也可以關閉彈窗,但此時父元件的isShow仍將會是true且不會與元件內部保持同步。即使要用傳參,也應該使用:show.sync="isShow"使外部與內部保持同步

<tag-relate-popup :show="isShow"></tag-relate-popup>

推薦使用$refs直接呼叫元件內部方法開啟彈窗

在 TagRelatedPopup 元件內部定義一個 handleOpen 方法用於開啟彈框:

<template>
  <popup-wrap :visible.sync="show"
  			  :pageEvent="pageEvent"
              ref="tagRelatePopup">
    <template slot="content">
    	// 這裡是彈框內容
    </template>
  </popup-wrap>
</template>

<script>
import PopupWrap from '@/views/common/PopupWrap';
export default {
	components: {
		PopupWrap
	},
	data() {
		return {
			show: false	
		}
	},
	methods: {
		// 在元件內部建一個handleOpen方法用於開啟彈框
		handleOpen(e) {
			this.show = true;
      		this.pageEvent = e;
		}
	}
}
</script>

在父元件中通過$refs呼叫子元件內部的handleOpen方法開啟彈框:

<template>
	<div>
		<span @click.stop="showtagRelateBox($event)">
		</span>
		<tag-relate-popup ref="tagRelateBox"></tag-relate-popup>
	</div>
</template>

<script>
import TagRelatePopup from '@/views/common/TagRelatePopup';
export default {
	components: {
		TagRelatePopup
	},
	data() {
		return {
			
		}
	},
	methods: {
		// 開啟關聯tag 浮窗
		// $event可用於傳入觸發click事件時滑鼠的座標
		// 根據指標座標可以指定彈框的位置
    	showtagRelateBox(e) {
	    	this.$refs.tagRelateBox.handleOpen(e);
	    }
	}
}
</script>

CSS 動畫

transition 新增多個屬性

transition: transform 2s ease, border-radius 3s ease-out;   // 多個屬性逗號隔開

CSS3 transition 屬性 - 菜鳥教程

animation 定義動畫的兩種方式:

@keyframes go {
  from {}
  to {}
}
@keyframes go {
  0% {}
  50%{}
  100%{}
}

CSS3 animation(動畫) 屬性 - 菜鳥教程

CSS — 貝塞爾曲線(cubic-bezier)
css3動畫貝塞爾曲線cubic-bezier,css3動畫的五種情況
css3裡的貝塞爾速度曲線

其他內容

前端簡歷中的專案經歷怎麼突出亮點?- 淘系技術

圖片上傳的問題
Content-Type: multipart/form-data
圖片上傳方式:base64或者file物件
base64圖片比原始檔大1/3,所以只能用於傳一些非常小的圖

Http請求中Content-Type

阿里雲 Hands-on Labs

機器學習演算法(一): 基於邏輯迴歸的分類預測
使用PolarDB和ECS搭建入口網站
基於Redis實現線上遊戲積分排行榜

8月11日內容彙總

ES6 中的Map()和Set()

ES6 提供了新的資料結構Map()和Set()。Map是一組鍵值對的結構,具有極快的查詢速度。Set類似於陣列,但是成員的值都是唯一的,沒有重複的值。

Map的用法:使用Array進行查詢時,陣列越長,就會耗費更多時間。但是通過Map,無論陣列有多長,查詢都非常高效。

// 建立的時候初始化
let mapObj = new Map([
  ['a', 1],
  ['b', 2],
  ['c', 3]
])
// 建立空map,之後新增元素
let mapObj = new Map()
mapObj.set('a', 1)
mapObj.set('b', 2)
mapObj.set('c', 3)
// 基本操作
mapObj.set('a', 1) // 新增元素
mapObj.delete('d') // 刪除指定元素
mapObj.has('a') // true 檢測是否包含某個key對應的元素
mapObj.get('a') // 1
// Map物件的長度不是length,而是size
console.log(mapObj.size) // 3

Set的用法:所有的成員值都是唯一的,可以實現陣列去重,獲取交集、並集、差集等。

// 建立的時候初始化,自動過濾重複的值
let setObj = new Set([1, 2, 3, 3])
// 建立的時候初始化,之後新增元素
let setObj = new Set()
setObj.add(1)
setObj.add(2)
setObj.add(3)
// 或者這樣新增
[2,3,5,4,5,2,2].forEach(x => setObj.add(x));
// 基本操作
let s = new Set([1, 2, 3])
s.add(3) // 由於key重複,新增不進
s.delete(3) // 刪除指定key
console.log(s) // 1 2
// Set物件的長度也是size
console.log(setObj.size)

Set的常用技巧:

// 陣列去重
const arr = [2,2,4,2,3,4];
const unique = [... nw Set(arr)];

// Array.from 方法可以將 Set 結構轉為陣列
function unique(array) {
	return Array.from(new Set(array));
}

// 擴充套件運算子內部使用for of迴圈,也能嫁給你Set轉為陣列
let set = new Set(['red', 'green', 'blue']);
let arr = [...set];

// 實現並集、交集、差集
let a = new Set([1,2,3]);
let b = new Set([4,3,2]);

let union = new Set([...a, ...b]);
console.log(union);

let intersect = new Set([...a].filter(x => b.has(x)));
console.log(intersect);

let difference = new Set([...a].filter(x => !b.has(x)));
console.log(difference);

Set 和 Map 資料結構 - 阮一峰
js中ES6的Set的基本用法
js中的Set和Map簡單使用
JS中集合物件(Array、Map、Set)及類陣列物件的使用與對比

技術熱點

語雀的技術架構演進之路
React + TypeScript/JavaScript + Element + egg.js
egg.js 官方文件
curl 的用法指南 - 阮一峰

Vue 設定動態樣式

// 三元運算子判斷
<div :style="{ 'opacity': !editableCheckNum ? 0.5 : 1 }">555</div>
// 設定動態class
<div :class="activeMachineId"></div>
// 方法判斷
<div :style="handleStyle(item.style)"></div>

div 標籤width根據內容自適應

width: auto;
max-width: 100%; /* 最大寬度為父元素寬度 */

text-overflow: ellipsis 無效的問題

在開發中用了overflow: hidden和text-overflow: ellipsis,結果發現只有英文和數字才有…的效果,中文只有隱藏。查了一下,還需要加一句white-space: nowrap

.the-tag {
	width: 160px;
	overflow: hidden;
	white-space: nowrap;
	text-overflow: ellipsis;
}

8月10日內容彙總

JS 資料型別詳解

JavaScript一共有8種資料型別,其中有7種基本資料型別:Undefined、Null、Boolean、Number、String、Symbol(es6新增,表示獨一無二的值)和BigInt(es10新增);

1種引用資料型別——Object(Object本質上是由一組無序的名值對組成的)。裡面包含 function、Array、Date等。JavaScript不支援任何建立自定義型別的機制,而所有值最終都將是上述 8 種資料型別之一。
「前端料包」可能是最透徹的JavaScript資料型別詳解

JS 面試必備

之前的乾貨再撈一下
由淺入深,66條JavaScript面試知識點

var 和 let,const

除了作用域不同之外,var宣告的變數會掛載在window上,而let和const宣告的變數不會

var a1 = "3242423";
console.log(this.a1); // "3242423"
let a2 = "代表一個沙壁";
console.log(this.a2); // undefined

JS 自動裝箱機制

字串(String)是基本型別,沒有屬性和方法,但是字串卻可以呼叫length

const str = "323425435345";
console.log(str.length); // 12

這是因為 JS 內部自動對這個字串進行了裝箱操作,即將這個字串封裝為例項物件,然後再呼叫例項物件上的length方法輸出結果,最後銷燬這個物件

let Str = new String("323425435345");
console.log(Str.length);
Str = null;

可以看到例項物件Str的__proto__上掛載有length方法,而建構函式String()的prototype上也有length方法。(實際上,例項物件的__proto__ === 建構函式的prototype)
在這裡插入圖片描述

8月7日內容彙總

第一期:前端九條bug分享
第三期:前端九條bug分享
記一次grid佈局實戰應用分享會
前端面試題總結(js、html、小程式、React、ES6、Vue、演算法、全棧熱門視訊資源)

JS基礎總結(4)——this指向及call/apply/bind

防抖:當持續觸發事件時,一定時間段內沒有再觸發事件,事件處理函式才會執行一次,如果設定的時間到來之前,又一次觸發了事件,就重新開始延時。
節流:當持續觸發事件時,保證一定時間段內只呼叫一次事件處理函式。
淺談JavaScript的防抖與節流

8月6日內容彙總

Vue響應式資料原理:資料劫持和資料代理

Object.defineProperty() 和 ES2015 中新增的 Proxy 物件會經常用來做資料劫持

資料劫持:在訪問或者修改物件的某個屬性時,通過一段程式碼攔截這個行為,進行額外的操作或者修改返回結果.資料劫持最典型的應用------雙向的資料繫結

一道面試題:

什麼樣的a可以滿足(a === 1 && a === 2 && a === 3) === true

既然是嚴格相等,型別轉換什麼的基本不考慮了。一個自然的想法就是每次訪問 a 返回的值都不一樣,那麼肯定會想到資料劫持。

多繼承

Javascript 通過原型鏈實現繼承,正常情況一個物件(或者類)只能繼承一個物件(或者類)。但通過這兩個方法都可以實現一種黑科技,允許一個物件繼承兩個物件。下面的例子使用 Proxy 實現。

vue中是如何監聽陣列變化?

Object.defineProperty與Proxy理解整理
【第1423期】資料劫持 OR 資料代理
深入淺出Object.defineProperty()

面經合集

子弈大佬的面經
在阿里我是如何當面試官的

8月5日內容彙總

Vue.set()方法的使用

vue響應式的原理:

當你把一個普通的JS物件傳給vue例項的data選項時,vue將遍歷此物件的所有屬性,並使用 Object.defineProperty把這些屬性全部轉為 getter/setter。Object.defineProperty是ES5中一個無法shim的特性,這也就是為什麼vue不支援IE8以及更低版本的瀏覽器。

因為受現代JS的限制,vue不能檢測到物件屬性的新增或刪除
由於vue會在初始化例項時對屬性執行 getter/setter 轉化過程,所以屬性必須在data物件上存在才能讓vue轉換它,這樣它才能是響應的。

vue不允許在已經建立的例項上動態新增新的根級響應式屬性,不過可以使用Vue.set()方法將響應式屬性新增到巢狀的物件上

也可以使用 this.$set 例項方法,該方法是全域性方法 Vue.set 的一個別名:

Vue.set(vm.items, indexOfItem, newValue)
// vm.items :源資料;indexOfItem : 要修改的資料的鍵;newValue : 要修改的資料
let a = [
    {name:'張三',age:'20',sex:1},
    {name:'李四',age:'21',sex:0},
    {name:'王五',age:'22',sex:1},
]
a[1].age = 19; // 修改李四的age為19
Vue.set(a,1,a[1]); // 這時候 a 是源資料, 1 是鍵, a[1]是修改後的資料
Vue.forceUpdate(); // 也可以用這個方法手動觸發檢視更改

深入響應式原理 - Vue.js官方文件
Vue.set() this.$set()引發的檢視更新思考
說說vue.set() (this.$set) 的用法

邊緣計算架構

邊緣計算是什麼,和雲端計算的區別是什麼?- 知乎
什麼是邊緣計算?- 知乎
什麼是邊緣計算 What Is Edge Computing?
[原創]邊緣計算開源方案對比
邊緣計算的架構、挑戰與應用

塊級格式化上下文(Block formatting context, BFC)

什麼是BFC?看這一篇就夠了
CSS中重要的BFC

switch case的用法。

一般不在case裡面直接return,而是先給變數賦值,到最後再return。

function checkFileType(suffix) {
	let fileTypeIcon;
    switch(suffix) {
      case "jpg":
      case "jpeg":
      case "png":
      case "gif":
        fileTypeIcon = "info_file_pic";
        break;
      case "pdf":
        fileTypeIcon = "info_file_pdf";
        break;
      case "doc":
      case "docx":
        fileTypeIcon = "info_file_word";
        break;
      case "xls":
      case "xlsx":
        fileTypeIcon = "info_file_excel";
        break;
      case "ppt":
      case "pptx":
        fileTypeIcon = "info_file_ppt";
        break;
      case "":
        fileTypeIcon = "info_file_folder";
        break;
    }
    // 如果未能匹配到
    return fileTypeIcon || "info_file_folder"
  },
}

如果case非常多程式碼就會很長,這個時候可以使用物件字面量來實現,語法更簡潔。

// use object literal to find fruits in color
const fruitColor = {
  red: ['apple', 'strawberry'],
  yellow: ['banana', 'pineapple'],
  purple: ['grape', 'plum']
};
 
function test(color) {
  return fruitColor[color] || [];
}

ES6的Map()物件具有極高的查詢效率,可以實現相同的效果。

// use Map to find fruits in color
const fruitColor = new Map()
  .set('red', ['apple', 'strawberry'])
  .set('yellow', ['banana', 'pineapple'])
  .set('purple', ['grape', 'plum']);
 
function test(color) {
  return fruitColor.get(color) || [];
}

8月3日內容彙總

儘量少用if else的技巧:|| 和 && 運算子

專案中經常遇到一個問題,後端返回欄位為空的時候,會出現各種變數型別,例如一個原本是陣列型別 的欄位,用來儲存附件資訊,但是如果沒有附件,這個欄位有時會返回空陣列,有時會返回null,這樣的話,由於null是不可迭代的,因此會報錯Cannot read property map of null。

在這種情況下,可以通過邏輯或 || 來判斷,在其運算元中找到第一個真值表示式並返回它。當第一個變數為 nullundefined0"" 時,就讓他為另一個預設值

demandAttachments = this.demandAttachments || []
demand = {
	description: this.description || "暫無描述"}
function checkFileType(suffix) {
	// do something
	return fileType || "未匹配到檔案"
}

實現一個邏輯,如果陣列中沒有某個元素,就把它push到這個陣列中

!result.includes(item) && result.push(item)

&& 叫邏輯與,在其運算元中找到第一個虛值表示式並返回它,如果沒有找到任何虛值表示式,則返回最後一個真值表示式。它採用短路來防止不必要的工作。
|| 叫邏輯或,在其運算元中找到第一個真值表示式並返回它。這也使用了短路來防止不必要的工作。在支援 ES6 預設函式引數之前,它用於初始化函式中的預設引數值。
!! 運算子可以將右側的值強制轉換為布林值,這也是將值轉換為布林值的一種簡單方法。

使用arguments物件獲取函式引數

function fn(arguments) {
	// arguments = [a1, a2, a3]
}
fn(a1, a2, a3);

8月2日內容彙總

之前的內容再撈一下
基於Vue實現一個簡易MVVM
你真的理解$nextTick麼
Vue原始碼分析 - nextTick

推薦一篇非常好的文章,看完絕對有收穫
Tasks, microtasks, queues and schedules

子弈大佬的GitHub,包含JS學習筆記,CSS學習筆記,資料結構與演算法,react學習筆記等等
https://github.com/ziyi2?tab=repositories

7月31日內容彙總

React + TypeScript + Golang全棧
Go+GraphQL+React+Typescript搭建簡書專案(一)——概覽

Golang Gin web框架
Golang Gin 實戰(一)| 快速安裝入門
Golang Gin 實戰(二)| 簡便的Restful API 實現
Golang Gin 實戰(三)| 路由引數
Golang Gin 實戰(四)| URL查詢引數的獲取和原理分析

專案中遇到很多父子元件巢狀的場景,比如父元件中有一些概覽資訊,子元件中是詳情資料,例如表格。資料由父元件通過xhr請求獲取,然後傳參給子元件,在子元件中通過props接收,然後通過監聽props的變化,將該值傳給data。

在很多業務場景中,子元件的詳情資料都需要支援編輯操作,編輯操作通常是做兩件事,一個是通過介面向後端傳送更新的資料,二是更新元件的data,以更新檢視。但是如果只更新子元件自己的data,那就無法與父元件保持同步,概覽資訊無法更新。為使父子元件之間能夠同步資料,通常的做法包括:子元件向父元件傳遞更新的資料、讓父元件從介面拉一下資料、強制重新整理父元件。這樣的做法很容易產生冗餘資料,同樣的資料在父元件和子元件都做了拷貝,沒有必要,而且程式碼耦合度增加,導致元件複用困難。

本人在實踐中發現,子元件的props傳值給data其實沒有必要。為什麼要傳值給data,因為一般認為,props的值是隻讀的,只有data才可以修改,所以要將props傳給data。但是本人發現,props實際上和es6裡的const很像,並非不能修改。當props的值為引用型別,例如物件,它的屬性值都是可以修改的,因此展示和修改資料都可以用props。而且在子元件中修改props還會直接同步到父元件的data,兩端資料會始終保持同步,不需要再進行額外的傳參。

7月29日內容彙總

由淺入深,66條JavaScript面試知識點
解鎖各種js陣列騷操作,總有你想要的!
最強大的 CSS 佈局 —— Grid 佈局
總結前端效能優化的方法
你也許不知道的javascript高階函式

7月28日內容彙總

this.$nextTick()的用法

在專案中遇到這樣一個問題,需要給一個彈窗裡面的自定義元件傳參。本人實現的流程如下,當彈窗顯示的時候,監聽dialogVisible的變化,如果為true,那麼就給相應的data賦值,用v-bind實現傳參。在實踐過程中發現,當頁面首次載入的時候,即便data已經被賦值,點開彈窗的時候引數仍然沒有傳入元件,重新點開彈窗才會傳參。

watch: {
  dialogVisible: function(val) {
    // 彈窗展開時獲取需求資訊
    if (val == true) {
      // 新建狀態下
      if (this.requireId == '') {
        this.getCurrentDemandClass();
      }
    }
  }
},

與此同事,本人發現另一個xhr方法卻可以給彈窗內的元件正常傳參,由此做出推斷,在元件DOM更新完成之前是無法繫結傳參的,只有當元件DOM更新完成後才能拿到引數。按照這個思路,只要把賦值操作改成非同步方法就可以,用setTimeout()就能模擬非同步方法,試了一下果然成功了,就是檢視更新有點慢,彈窗顯示之後過一會才會出現資料,使用者體驗較差。

watch: {
  dialogVisible: function(val) {
    // 彈窗展開時獲取需求資訊
    if (val == true) {
      // 新建狀態下
      if (this.requireId == '') {
        setTimeout(() => {
          this.getCurrentDemandClass();
        }, 0)
      }
    }
  }
},

本人還看到專案裡面類似的場景下有用到this.$nextTick()方法,拿來試試,發現也可以用,而且資料的顯示基本是與彈窗同步的,不會存在剛才的問題。

watch: {
  dialogVisible: function(val) {
    // 彈窗展開時獲取需求資訊
    if (val == true) {
      // 新建狀態下
      if (this.requireId == '') {
        this.$nextTick(() => {
          this.getCurrentDemandClass();
        })
      }
    }
  }
},

根據上面的示例可以看出,this.$nextTick()的作用大致就是等待DOM更新完畢後,再去執行回撥函式,v-bind給元件傳參是一個場景,另一個場景是用this.$refs執行元件內部的方法。

Vue 在更新 DOM 時是非同步執行的。只要偵聽到資料變化,Vue 將開啟一個佇列,並緩衝在同一事件迴圈中發生的所有資料變更。如果同一個 watcher 被多次觸發,只會被推入到佇列中一次。這種在緩衝時去除重複資料對於避免不必要的計算和 DOM 操作是非常重要的。然後,在下一個的事件迴圈“tick”中,Vue 重新整理佇列並執行實際 (已去重的) 工作。Vue 在內部對非同步佇列嘗試使用原生的 Promise.then、MutationObserver 和 setImmediate,如果執行環境不支援,則會採用 setTimeout(fn, 0) 代替。
例如,當你設定 vm.someData = ‘new value’,該元件不會立即重新渲染。當重新整理佇列時,元件會在下一個事件迴圈“tick”中更新。多數情況我們不需要關心這個過程,但是如果你想基於更新後的 DOM 狀態來做點什麼,這就可能會有些棘手。為了在資料變化之後等待 Vue 完成更新 DOM,可以在資料變化之後立即使用 Vue.nextTick(callback)。這樣回撥函式將在 DOM 更新完成後被呼叫。

深入響應式原理 - Vue.js官方文件

自定義指令v-clickoutside

v-clickoutside可以在元件外部點選的時候執行方法,如收起popover

<template>
	<div>
		<!-- 人時 任務展示 -->
      <el-form-item v-if="detailType == 'task'">
        <span slot="label">
          <svg-icon icon-class="common_type"
                    class-name="svg-demand-class"></svg-icon>
          <span class="label_text">工時</span>
        </span>
        <span v-if="!edit.worktime"
              @click="initWorkTime">
              {{demand.workTime == 0 || demand.workTime == null ? "--" : demand.workTime}}
        </span>
        <el-input-number ref="pickWorktime"
                         v-else
                         v-model="demand.workTime"
                         :step="1"
                         :min="0"
                         v-clickoutside="() => {
            edit.worktime = false;
            changeCommand(demand, demand.workTime, 'workTime')
          }"></el-input-number>人時
      </el-form-item>
	</div>
</template>

<script>
import Clickoutside from "element-ui/src/utils/clickoutside";
export default {
	components: {
		
	},
	directives: {
		Clickoutside
	},
	data() {
		return {
			
		}
	},
	methods: {
		
	}
}
</script>

clickoutside自定義指令原始碼分析

彈性佈局實現兩端對齊

.box {
	display: flex;
	justify-content: space-between; /* 兩端對齊 */
	align-items: center; /* 垂直居中 */
}

效果如下:
在這裡插入圖片描述

CSS box-sizing屬性

box-sizing常用的有兩個值:content-box或border-box

box-sizing: content-box|border-box

content-box(預設值)
這是 CSS2.1 指定的寬度和高度的行為。指定元素的寬度和高度(最小/最大屬性)適用於box的寬度和高度。元素的填充和邊框佈局和繪製指定寬度和高度除外

border-box
指定寬度和高度(最小/最大屬性)確定元素邊框。也就是說,對元素指定寬度和高度包括了 padding 和 border 。通過從已設定的寬度和高度分別減去邊框和內邊距才能得到內容的寬度和高度。

應用場景:響應式Web設計經常需要我們通過百分比設定元件寬度。如果我們不考慮邊框,那麼很容易就可以實現,但如果你給每一列以及總寬度都採用百分比設定,那這個時候固定的邊框大小就會出來搗亂。
css3屬性box-sizing:border-box 用法解析

debounce和throttle

沒時間總結了,先上鍊接
前端效能優化——debounce
函式去抖(debounce)& 函式節流(throttle)總結
Lodash之throttle(節流)與debounce(防抖)總結

7月26日內容彙總

推薦:2019年十佳DevOps工具
Jenkins+Docker 持續整合、部署(CI/CD)專案實踐

7月25日內容彙總

Vue執行機制概述,v-model雙向繫結詳解,面試必備
基於Vue實現一個簡易MVVM

7月24日內容彙總

在插值表示式中使用三元表示式

<span style="padding-left: 10px;">{{ requireId == '' ? '新建' : '編輯'}}需求</span>

在模板字串中使用三元表示式

this.$message.success(`需求${this.requireId == '' ? '建立' : '更新'}成功!`);

使用箭頭函式需要return

this.iterationMap = res.filter((item) => {
  return item.state != '關閉';
})

Vue元件巢狀傳值

7月23日內容彙總

Jenkins - 持續整合引擎
Jenkins入門(一)
前端開發想了解機器學習?用一臺Mac就可以

7月22日內容彙總

// 選中節點
handleNodeClick(data, node){
  this.valueList = []; // 先清空路徑
  this.recursiveParentId(node); // 遞迴獲取當前路徑

  this.valueTitle = this.valueList.join(' / '); // 拼接路徑
  this.valueId = data[this.props.value]
  this.$emit('getValue',this.valueId)
  this.defaultExpandedKey = []

  this.$refs.select.blur(); // 失去焦點,並收起下拉框
},
// 遞迴獲取根節點
recursiveParentId(node) {
  if (node.data.id == -1) {
    this.valueList.unshift("所有分類")
    return
  } else {
    this.valueList.unshift(node.data.text);
    this.recursiveParentId(node.parent);
  }
}
// 這裡定義ref
<el-select style="width: 100%;" :value="valueTitle" ref="select">
</el-select>
// 這裡訪問元件內部的方法
this.$refs.select.blur();

在popover和dialog中巢狀的div,樣式需要定義在最外層,如果巢狀樣式是訪問不到的

popover, dialog如果放在外層的, 看element放在哪

popover-class
你看下這個屬性
控制元件裡面的
就是設定一個class, 然後再這個class 後面跟他下面的選擇器
注意控制範圍就好了

transition實現顏色過渡動畫
在這裡插入圖片描述
在less中不能直接用>>>,需要用/deep/
在這裡插入圖片描述

7月21日內容彙總

通過cssText設定元素內聯樣式

let upload = document.querySelectorAll('.el-upload--picture-card')[0]
upload.style.cssText = 'display: none'

var elmnt = document.getElementsByTagName("h1")[0];
elmnt.style.cssText = "color: blue;";

防抖實現
在這裡插入圖片描述

7月20日內容彙總

通過自定義data-xxx標籤實現動態樣式

在html標籤中定義data-level標籤,其值為陣列下標
在這裡插入圖片描述
在樣式中這樣定義
在這裡插入圖片描述

7月17日內容彙總

父元件訪問子元件方法:通過$refs直接訪問

<template>
    <div>
        <div @click="click">點選父元件</div>
        // 注意:這裡需要加ref屬性
        // 這裡的屬性值需要與下面呼叫的名稱一致
        <tree-select ref="treeSelect"></tree-select>
    </div>
</template>
<script>
import treeSelect from "@/components/require/treeSelect";
export default {
    components: {
        treeSelect,
    },
    methods: {
        click() {
            this.$refs.treeSelect.clearTreeSelect() // 直接呼叫
        },
    }
}
</script>

JS刪除陣列中的元素

// splice() 方法用於新增或刪除陣列中的元素
array.splice(index,howmany,item1,.....,itemX);
// 從下標為2的元素開始刪除1個元素
array.splice(2, 1);

JavaScript Array 物件
利用process.env.NODE_ENV設定不同環境的url

7月15日內容彙總

動態修改元件的樣式

在專案中需要實現一個需求,根據優先順序的不同修改div的顏色。師兄告訴我在標籤內用data-xxx的屬性,我覺得比較麻煩,希望動態修改元件樣式,網上查了下果然可以。在這裡priorityStyle是計算屬性,所有的顏色判斷的邏輯都放在這裡。

<div :style="{'background-color': priorityStyle}">
	{{ form.priority }}
</div>
computed: {
  priorityStyle() {
    let style;
    if (this.form.priority == '低') {
      style = '#5ae6d7';
    }
    if (this.form.priority == '中') {
      style = '#0fbceb';
    }
    if (this.form.priority == '高') {
      style = '#ff426f';
    }
    return style;
  }
},

實踐表明,動態屬性放到methods裡其實也可以

<template>
	<span class="child_state"
	      :class="state_color(child)"
	      @click="stateChange">
	  <svg-icon icon-class="info_ellipsis"
	            class-name="svg-check"
	            v-if="child.state == '規劃中'"></svg-icon>
	  <svg-icon icon-class="info_doing_white"
	            class-name="svg-check"
	            v-else-if="child.state == '實現中'"></svg-icon>
	  <svg-icon icon-class="info_check_white"
	            class-name="svg-check"
	            v-else-if="child.state == '已實現'"></svg-icon>
	  <svg-icon icon-class="info_cross_white"
	            class-name="svg-check"
	            v-else-if="child.state == '已拒絕'"></svg-icon>
	  <span class="state">{{child.state}}</span>
	</span>
</template>

<script>
export default {
	methods: {
		state_color(sonDemand) {
		 let color = "";
		 switch (sonDemand.state) {
		   case "規劃中":
		     color = "willing";
		     break;
		   case "實現中":
		     color = "doing";
		     break;
		   case "已實現":
		     color = "over";
		     break;
		   case "已拒絕":
		     color = "refuse";
		     break;
		 }
		 return color;
		},
	}
}
</script>

<style>
.over {
  background-color: rgb(0, 197, 101);
}
.doing {
  background-color: rgb(255, 162, 0);
}
.willing {
  background-color: rgb(0, 199, 207);
}
.refuse {
  background-color: rgb(80, 93, 124);
}
</style>

子元件獲取父元件資料

在父元件使用子元件的地方繫結一下資料

<template>
<sub-list :submsg="msg"></sub-list>
</tempalte>

<script>
import subList from "@/components/xxxx"

export default {
	components: {
		subList
	},
	data() {
		return {
			msg: "您好,加菲貓!"
		}
	}
}
</script>

在子元件中通過props接收
Vue 實現檔案的上傳
vue中的檔案上傳和下載
基於Element-UI的元件改造的樹形選擇器(樹形下拉框)
Element-UI 實現樹形選擇器

7月14日內容彙總

el-select寬度自適應父元素寬度

在使用餓了麼元件的時候,el-select選擇器的寬度預設是由裡面的文字決定的,如果希望自適應父元素寬度,在el-select的標籤內新增style屬性,設定width: 100%即可。

<el-select v-model="form2.type"
           placeholder="請選擇"
           style="width: 100%;">
  <el-option label="區域一"
             value="shanghai"></el-option>
  <el-option label="區域二"
             value="beijing"></el-option>
</el-select>

元件引入及使用

在vue專案中 @ 符號代表的是根目錄,即 src 目錄。
在專案中,公用的元件放在components目錄下,專案元件放在views目錄下。

  1. 第一種使用方式

    /* 引入 */
    import navs from '@/views/nav/index'
    
    /* 註冊元件 */
    components:{
      'v-nav':navs
    }
    
    /* 在模板中使用 */
    <v-nav></v-nav>
    
  2. 第二種使用方式

    /* 引入 */
    import navs from '@/views/nav/index'
    import indexList from './index-list'
    
    /* 註冊元件 */
    components: { navs,indexList },
    
    /* 在模板中使用 */
    <index-list></index-list>
    <navs></navs>
    
  3. 第三種使用方式

    /* 目錄結構 */
    components/BacktoTop/index.vue
    
    /* 引入 */
    import BackToTop from '@/components/BackToTop'
    
    /* 註冊元件 */
    components: { BackToTop },
    
    /* 在模板中使用 */
    <el-tooltip placement="top" content="tooltip">
      <back-to-top :custom-style="myBackToTopStyle" :visibility-height="300" :back-position="50" transition-name="fade" />
    </el-tooltip>
    

VUE修飾符sync

深入理解vue 修飾符sync【 vue sync修飾符示例】
徹底明白VUE修飾符sync

7月13日內容彙總

在覆蓋餓了麼UI某個控制元件原生樣式的時候發現一直都不生效,使用!important同樣也無效,經師兄指點,用了deep穿透,樣式覆蓋成功,>>>這個是簡寫。

>>> .el-badge .el-badge__content {
  background: rgba(0,0,0,0.08);
  font-family: SegoeUI;
  font-size: 12px;
  color: rgba(0,0,0,0.56);
  letter-spacing: 0;
  line-height: 16px;
}

vue css >>> /deep/ 穿透

全域性覆蓋和區域性覆蓋

/* 這是全域性覆蓋 */
.el-menu-item.is-active {
  border-bottom-color: #00aea6 !important;
  color: rgba(0, 0, 0, 0.88) !important;
}
/* 這是在.main-list下區域性覆蓋 */
.main-list .el-menu-item.is-active {
  border-bottom-color: #00aea6 !important;
  color: rgba(0, 0, 0, 0.88) !important;
}

7月10日內容彙總

Less快速入門
SCSS快速入門
sass/scss 和 less的區別
Minder敏捷開發平臺專案列表已上傳Github

7月8日內容彙總

CSS padding屬性的說明

padding:10px 5px 15px 20px;
上填充是 10px
右填充是 5px
下填充是 15px
左填充是 20px
padding:10px 5px 15px;
上填充是 10px
右填充和左填充是 5px
下填充是 15px
padding:10px 5px;
上填充和下填充是 10px
右填充和左填充是 5px
padding:10px;
所有四個填充都是 10px

CSS line-height屬性

設定行間距,將行高設為父元素高度,可以實現文字在div內的垂直居中

<style>
.default {
	border-bottom: 1px solid;
	height: 40px; /* 這個是父元素高度 */
	line-height: 40px; /* 實現文字垂直居中 */
}
</style>
<body>
<div class="default">
這是一個標準行高的段落。
</div>
<div class="default">
這是一個標準行高的段落。
</div>
<div class="default">
這是一個標準行高的段落。
</div>
</body>

CSS border屬性

在設定div邊框寬度後,還必須指定邊框樣式,否則不顯示

.single-item{
	border:5px solid red;
}

7月7日內容彙總

TortoiseSVN 使用教程

TortoiseSVN下載及安裝地址
根據上面的提示安裝,安裝之後資料夾內點選滑鼠右鍵看到有SVN的選單就算安裝成功
更新操作:滑鼠右鍵update
提交檔案:滑鼠右鍵commit
一般就用updatecommit

7月6日內容彙總

一次弄懂Event Loop(徹底解決此類面試問題)
JS之Event Loop(事件迴圈)
js筆記十二:利用await和async,將回撥函式變成同步的處理的辦法
餓了麼前端元件
CSS命名規範–BEM

7月3日內容彙總

Fetch使用

fetch是一種HTTP資料請求的方式,是XMLHttpRequest的一種替代方案。fetch不是ajax的進一步封裝,而是原生js。Fetch函式就是原生js,沒有使用XMLHttpRequest物件。

fetch(url).then(response => response.json()) // 或者response.text()
  .then(data => console.log(data))
  .catch(e => console.log("Oops, error", e))

fetch API獲取返回值的方式
Js中陣列去重的幾種方法
js除錯技巧(通過debugger除錯)
解析JS如何運用斷點進行除錯

7月2日內容彙總

chrome-extensions-examples
chrome.webRequest
Chrome Extension - How to get HTTP Response Body?
Chrome Extension 獲得RequstBody

7月1日內容彙總

chrome-plugin-demo
Chrome外掛中 popup,background,contantscript訊息傳遞機制
例項解析防抖動(Debouncing)和節流閥(Throttling)
函式去抖(debounce)& 函式節流(throttle)總結

6月29日內容彙總

this.$nextTick用法和意義
本地編輯專案的時候,如果遠端倉庫的內容已被更改,這個時候執行git pull會提示如下錯誤:

error: Your local changes to the following files would be overwritten by merge:

接下來分兩種情況處理:

  1. 保留本地的修改同時又把遠端的合併過來

    git stash  // 將本地快照
    git pull origin master  // 用遠端程式碼覆蓋本地
    git stash pop  // 恢復本地修改
    

    下一步就可以commit和push了

  2. 不保留本地修改

    git reset --hard  // 將本地的狀態恢復到上一個commit id
    git pull origin master  // 用遠端的程式碼直接覆蓋本地
    

【Git】pull遇到錯誤:error: Your local changes to the following files would be overwritten by merge:

6月28日內容彙總

這 10 行比較字串相等的程式碼給我整懵了,不信你也來看看
告別動態規劃,連刷40道動規演算法題,我總結了動規的套路
Vue基礎知識總結(絕對經典)
Vue中this.$router.push(引數) 實現頁面跳轉
vue中返回上一頁go()和back()的區別
Vue.js 路由 - 菜鳥教程
Vue設定路由跳轉的兩種方法: <router-link :to="…"> 和router.push(…)
vue中處理文字不換行問題
Vue插值文字換行問題

6月24日內容彙總

Vue.js系列

一、vue基礎語法
二、vue元件化開發
三、vue前後端互動(輕鬆入門vue)
四、vue前端路由
vue腳手架學習總結,vue引數、基礎指令、宣告周期函式、元件、插槽(持續更新)
Vue3.0來了,一起來看看尤大大說了啥

Vue Router系列

vue-router 基本使用
Vue學習筆記——Vue-router
Vue Router官方文件

Flex彈性佈局

Flex彈性佈局教程-語法篇

Javascript系列

JavaScript Array 物件 - 菜鳥教程
JavaScript ES6 字串、陣列、Map、Set
javaScript教程之JS常用字串API彙總梳理
Airbnb Javascript Style Guide

相關文章