## 框架和庫的區(qū)別?> 框架(framework):一套完整的軟件設(shè)計架構(gòu)和**解決方案**。> > 庫(library):對常用功能性函數(shù)的**封裝**。> > 一般也可以認為框架大而全,庫小而精。一個框架中可以包含或者集成多個庫。 + 框架:是一套完整的解決方案;對項目的侵入性較大,項目如果需要更換框架,則需要重新架構(gòu)整個項目。 + 庫(插件):提供某一個小功能,對項目的侵入性較小,如果某個庫無法完成某些需求,可以很容易切換到其它庫實現(xiàn)需求。## 數(shù)組方法擴展- `Array.prototype.forEach`:替代for循環(huán)對數(shù)組進行循環(huán)遍歷```JavaScriptvar list = [1,2,3,4,5]list.forEach(function(v,i){ // v是當(dāng)前遍歷的這一個元素 i是這個元素的索引 console.log('當(dāng)前元素是' + v,'當(dāng)前元素的索引是' + i)})```- `Array.prototype.map`:對數(shù)組進行遍歷,同時會返回一個新數(shù)組,新數(shù)組中的每一項都是回調(diào)函數(shù)中的返回值```JavaScriptvar list = [1,2,3,4,5]var newArr = list.map(function(v,i){ // v是當(dāng)前遍歷的這一個元素 i是這個元素的索引 console.log('當(dāng)前元素是' + v,'當(dāng)前元素的索引是' + i) return v * 2})console.log(newArr) // [2,4,6,8,10]```- `Array.prototype.findIndex`:對數(shù)組進行遍歷,會返回一個滿足回調(diào)函數(shù)條件的元素的索引```JavaScriptvar list = [1,2,3,4,5]var index = list.findIndex(function(v,i){ // v是當(dāng)前遍歷的這一個元素 i是這個元素的索引 console.log('當(dāng)前元素是' + v,'當(dāng)前元素的索引是' + i) if(v == 4){ // 當(dāng)return true時終止循環(huán) 同時將該元素的索引返回給findIndex函數(shù) return true } // 簡寫成 // return v == 4})console.log(index) // 3```- `Array.prototype.filter`:對數(shù)組進行遍歷,返回一個新數(shù)組,新數(shù)組中的每一項都是滿足回調(diào)函數(shù)中條件的元素,當(dāng)滿足條件時需要`return true````JavaScriptvar list = [1,2,3,4,5]var newArr = list.filter(function(v,i){ // v是當(dāng)前遍歷的這一個元素 i是這個元素的索引 console.log('當(dāng)前元素是' + v,'當(dāng)前元素的索引是' + i) if(v%2 == 0){ return true } // 簡寫成 // return v%2 == 0})console.log(newArr) // [2,4] ```- `Array.prototype.some`:對數(shù)組進行遍歷,返回一個布爾值,判斷當(dāng)前數(shù)組中是否有一個元素符合回調(diào)函數(shù)中的條件(特點:只要一個元素滿足條件,最終返回結(jié)果就是true)```JavaScriptvar list = [1,2,3,4,5]var flag = list.some(function(v,i){ // v是當(dāng)前遍歷的這一個元素 i是這個元素的索引 console.log('當(dāng)前元素是' + v,'當(dāng)前元素的索引是' + i) if(v % 2 == 0){ // return true時則終止繼續(xù)循環(huán) return true }})console.log(flag) // true// 注意: 由于遍歷的數(shù)組第二個元素就滿足了條件 所以循環(huán)到第二個元素時 就停止循環(huán)了```- `Array.prototype.every`:對數(shù)組進行遍歷,返回一個布爾值,判斷當(dāng)前數(shù)組中是否每一個元素都符合回調(diào)函數(shù)中的條件(特點:只要一個元素不滿足條件,最終返回結(jié)果就是false)```JavaScriptvar list = [1,2,4,6,8]var flag = list.every(function(v,i){ // v是當(dāng)前遍歷的這一個元素 i是這個元素的索引 console.log('當(dāng)前元素是' + v,'當(dāng)前元素的索引是' + i) if(v % 2 == 0){ // return true時則終止繼續(xù)循環(huán) return true }})console.log(flag) // false// 注意: 由于遍歷的數(shù)組第一個元素就不滿足條件 實際上循環(huán)一次就停止了```## Vue基礎(chǔ)> MVC:對項目的整體把控,M代表的是數(shù)據(jù)庫中的數(shù)據(jù),V代表的是前端的視圖層,C用于處理M和V之間進行交互的業(yè)務(wù)邏輯(業(yè)務(wù)邏輯需要程序員自己控制,自己編寫)> MVVM:主要用于一些前端的框架,對MVC三層架構(gòu)中的視圖層再次進行層次劃分,M是當(dāng)前一個視圖中需要用到的數(shù)據(jù),V就是當(dāng)前視圖,VM負責(zé)M和V之間的數(shù)據(jù)調(diào)度,內(nèi)部已經(jīng)幫你完成了數(shù)據(jù)的綁定和交互> MVC和MVVM之間的區(qū)別:MVC數(shù)據(jù)流通是單向的,MVVM是雙向數(shù)據(jù)綁定> 雙向數(shù)據(jù)綁定的意思就是模型中的數(shù)據(jù)可以之間更新到視圖上,視圖中的數(shù)據(jù)發(fā)生改變也可以直接更新到模型中能夠做到雙向數(shù)據(jù)綁定(通信)的原因:就是因為有VM的存在,VM內(nèi)部的實現(xiàn)一般是框架已經(jīng)處理完成,不需要程序員進行控制- 雙向數(shù)據(jù)綁定原理: `Object.defineProperty`存取器> 使用`Object.defineProperty`提供的set方法可以在給對象賦值時,觸發(fā)額外操作,即在set函數(shù)內(nèi)部去處理視圖的更新```JavaScript// 使用 Object.defineProperty 可以給對象賦值var obj = {};Object.defineProperty(obj,'name',{ value:'zxx'})console.log(obj.name)var obj = {};var initValue = 'zxx'Object.defineProperty(obj,'name',{ get:function(){ console.log('我被讀取了') return initValue }, set:function(v){ console.log('我被賦值了') initValue = v }})obj.name = 'lxy'console.log(obj.name)```### Vue基本編碼步驟1. 引入vue.js文件2. 定義一個vue的管理范圍
vue1.0里面vue的管理區(qū)域的id可以定義在HTML以及body標簽上? ? ? ? vue2.0里面不允許這樣來做3. 定義一個vue的對象? ? ? ? var vm = new Vue({? ? ? ? ? ? el:'#app',? ? ? ? ? ? // data定義vue實例的所有屬性? ? ? ? ? ? data:{? ? ? ? ? ? ? ? // 定義將來要在vue管理區(qū)域中使用的數(shù)據(jù)? ? ? ? ? ? ? ? name:"zs"? ? ? ? ? ? },? ? ? ? ? ? // methods定義vue實例所有的方法? ? ? ? ? ? methods:{? ? ? ? ? ? ? ? fn:function(){? ? ? ? ? ? ? ? ? ? this.name = 'ls'? ? ? ? ? ? ? ? }? ? ? ? ? ? }? ? ? ? })### Vue系統(tǒng)指令- `{{}}`:插值表達式```? ? 作用:將vue對象中的數(shù)據(jù)以及表達式顯示到vue托管區(qū)域中? ? {{這里書寫vue對象中data里面的數(shù)據(jù)或者表達式}}```- `v-cloak`:解決表達式閃爍問題```1. 定義一個樣式 ? [v-cloak]{
? ? ? display:none
? }
2. 使用
{{name}}
原理:當(dāng)vue.js文件還沒有加載出來時 使用[v-cloak]樣式作用于當(dāng)前指令所在標簽,當(dāng)vue.js能夠起作用時,會自動刪除v-cloak指令```? ? ? ? - `v-text`:輸出文本數(shù)據(jù)``````- `v-html`:輸出HTML結(jié)構(gòu)數(shù)據(jù)```
data:{name:'zs'}```- `v-bind`:動態(tài)給標簽或者組件綁定屬性```
// 使用:簡寫v-bind
// 變量和常量組合跳轉(zhuǎn)data:{cls: 'red blue',id: 1}```? - `v-on`:綁定事件```
// 簡寫
methods: { // 這個 methods屬性中定義了當(dāng)前Vue實例所有可用的方法? ? ? ? show: function () {? ? ? ? ? alert('Hello')? ? ? ? } }```- `v-model`:雙向數(shù)據(jù)綁定```// 可以使用的標簽:input textarea select 組件// name會和表單元素的value進行關(guān)聯(lián) value值變化 name值變化 反過來name值發(fā)生變化 value值也會發(fā)生變化```- `v-for`:循環(huán)輸出HTML元素```
{{item.name}}
```- `v-if`:根據(jù)表達式值的真假決定元素的顯示隱藏```// isShow為true顯示div 為false隱藏div// v-if是直接操作DOM 即隱藏時會將該div從DOM結(jié)構(gòu)中移除
```- `v-show`: 根據(jù)表達式值的真假決定元素的顯示隱藏```// isShow為true顯示div 為false隱藏div// v-show是操作div的樣式 顯示時添加 style = 'display:block'; 隱藏時添加style = 'display:none'
v-if 是刪除DOM元素 效率比較低 會造成頁面的結(jié)構(gòu)重新繪制v-show 是控制樣式 只會改變當(dāng)前這一個元素的樣式 不會造成頁面結(jié)構(gòu)的重新繪制```### 在Vue中使用樣式#### 使用class樣式1. 數(shù)組```
這是一個邪惡的H1
```2. 數(shù)組中使用三元表達式```
這是一個邪惡的H1
```3. 數(shù)組中嵌套對象```
這是一個邪惡的H1
```4. 直接使用對象```
這是一個邪惡的H1
```#### 使用內(nèi)聯(lián)樣式1. 直接在元素上通過 `:style` 的形式,書寫樣式對象```
這是一個善良的H1
```2. 將樣式對象,定義到 `data` 中,并直接引用到 `:style` 中 + 在data上定義樣式:```data: {? ? ? ? h1StyleObj: { color: 'red', 'font-size': '40px', 'font-weight': '200' }}``` + 在元素中,通過屬性綁定的形式,將樣式對象應(yīng)用到元素中:```
這是一個善良的H1
```3. 在 `:style` 中通過數(shù)組,引用多個 `data` 上的樣式對象 + 在data上定義樣式:```data: {? ? ? ? h1StyleObj: { color: 'red', 'font-size': '40px', 'font-weight': '200' },? ? ? ? h1StyleObj2: { fontStyle: 'italic' }}``` + 在元素中,通過屬性綁定的形式,將樣式對象應(yīng)用到元素中:```
這是一個善良的H1
```### 過濾器> `過濾器`:對需要展示的數(shù)據(jù)進行加工處理后再展示到界面,并不會改變原數(shù)據(jù)- 全局過濾器:當(dāng)前頁面所有Vue實例的托管區(qū)域都可以使用```JavaScriptVue.filter('過濾器名稱',function(value,arg){? ? // value就是需要處理的原始數(shù)據(jù) arg是使用過濾器時傳遞的參數(shù)? ? // 對數(shù)據(jù)處理的業(yè)務(wù)邏輯? ? return 處理完畢的數(shù)據(jù)})使用方法:原始數(shù)據(jù) | 過濾器名稱(參數(shù))```- 私有過濾器:只有當(dāng)前定義過濾器的Vue實例所托管的區(qū)域可以使用```JavaScriptnew Vue({? ? el:'#app',? ? // 私有過濾器? ? filters:{? ? ? ? '過濾器的名稱':function(value){? ? ? ? ? ? return 處理完畢的數(shù)據(jù)? ? ? ? }? ? }})```### 自定義指令> `指令`: 其實就是Vue給我們提供的操作DOM元素的一些方法- 全局指令```JavaScriptVue.directive('指令名稱',{? ? // 指令第一次綁定到元素身上時執(zhí)行(在內(nèi)存中綁定到了DOM對象上邊)? ? bind:function(el,binding,VNode){? ? ? ? // el: 指令所在的DOM元素對象? ? ? ? // binging.value 指令等號右邊表達式的值? ? ? ? // binging.expression 指令等號右邊表達式? ? ? ? // VNode.context 當(dāng)前指令所在托管區(qū)域?qū)τ诘腣ue實例對象? ? },? ? // 當(dāng)前指令所在元素插入到父節(jié)點時調(diào)用(不保證DOM已經(jīng)渲染完畢)? ? inserted:function(){},? ? // 指令綁定的值發(fā)生變化時會去執(zhí)行? ? update:function(){},? ? // 指令所在的組件值更新完畢時調(diào)用? ? componentUpdated:function(){},? ? // 自定義指令從當(dāng)前元素解綁時調(diào)用? ? unbind:function(){}})```- 私有指令```JavaScriptnew Vue({? ? el:'#app',? ? // 私有指令? ? directives:{? ? ? ? '指令名稱':{? ? ? ? ? ? bind:function(el,binding){? ? ? ? ? ? }? ? ? ? }? ? },? ? // 私有過濾器? ? filters:{? ? ? ? '過濾器的名稱':function(value){? ? ? ? ? ? return 處理完畢的數(shù)據(jù)? ? ? ? }? ? }})```## 生命周期鉤子函數(shù)> 回調(diào)函數(shù):一個函數(shù)被當(dāng)做參數(shù)進行傳遞的時候,稱作這個函數(shù)為回調(diào)函數(shù)> 構(gòu)造函數(shù):一個函數(shù)被new 關(guān)鍵字引導(dǎo)執(zhí)行的時候,稱作這個函數(shù)為構(gòu)造函數(shù)> 鉤子函數(shù): 一個應(yīng)用程序或者框架內(nèi)部提前定義好的一批函數(shù),這些函數(shù)會在特定的時間段自動執(zhí)行>> 生命周期: 一個程序會存在初始化 - 運行 - 銷毀等階段,這些階段統(tǒng)稱為該程序的生命周期```new Vue({? ? el:'#app',? ? data:{},? ? methods:{},? ? beforeCreated(){},? ? // data中的數(shù)據(jù)和methods中的方法已經(jīng)初始化完畢會去自動執(zhí)行created方法? ? created(){? ? ? ? // 用于發(fā)生數(shù)據(jù)請求,也可以初始化一些數(shù)據(jù)? ? },? ? beforeMount(){},? ? // 真實DOM已經(jīng)渲染完畢會執(zhí)行mounted函數(shù)? ? mounted(){? ? ? ? // 操作真實DOM? ? }? ? beforeUpdate(){},? ? // data中的發(fā)生了變化而且被重新渲染到了界面上時才會執(zhí)行? ? updated(){? ? ? ? // 數(shù)據(jù)更新后重新操作DOM? ? },? ? // 實例銷毀之前,實例上面的各種屬性和方法都還可以正常訪問,通??梢栽谶@里手動回收一些頁面沒有被釋放的變量,比如清楚定時器的操作。? ? beforeDestroy(){},? ? // 實例已經(jīng)從內(nèi)存中被銷毀? ? destroyed(){}})```## vue-resource發(fā)生ajax請求> vue.studyit.io```javascript// get請求this.$http.get('url').then(function(res){? ? // res.body 里面就是請求回來的數(shù)據(jù)})// post 請求 application/x-www-form-urlencode -> name=zs&age=18// application/json => {'name':'zs','age':18}this.$http.post('url',{name:'zs',age:18},{emulateJSON:true}).then(function(res){? ? // res.body})// jsonp請求this.$http.jsonp('url').then(function(res){? ? // res.body})```- **JSONP**:JSON數(shù)據(jù)格式的一種使用方式,用于解決跨域問題- **跨域**: 由于瀏覽器同源策略的限制,不同源的URL不能互相通信,這種現(xiàn)象叫做跨域- **同源策略**: 兩個域名只有 **協(xié)議** **主機地址** **端口號**完全一致時才能相互通信訪問- **JSONP實現(xiàn)原理**:利用script標簽的src屬性發(fā)送請求不受同源策略的限制這個機制去實現(xiàn)跨域資源共享(script標簽?zāi)軌蚩缬蛟L問是歷史遺留問題,并不安全)? ? 1. 動態(tài)創(chuàng)建一個script標簽,并且將需要請求的URL地址設(shè)置給script標簽的src屬性,同時在URL地址后面拼接上一個回調(diào)函數(shù)名稱```? ? ? ? function getJson(data){? ? ? ? ? ? console.log(data)? ? ? ? }// getJson就是在前端本地定義好的一個方法的方法名 ```? ? ? 2. 后臺接收到該請求后,先根據(jù)參數(shù)判斷是否是JSONP請求,如果是,則將客戶端請求的數(shù)據(jù)整理好,和前端發(fā)送過來的方法名一起拼接成一個函數(shù)調(diào)用的字符串,客戶端需要的數(shù)據(jù)就是這個函數(shù)調(diào)用時傳的參數(shù)```? ? ? ? // 假設(shè)要發(fā)送給前端的數(shù)據(jù)是 'ok'? ? ? ? 'getJson('ok')'? ? ? ? // 響應(yīng)給前端? ? ? ? res.end('getJson('ok')') ```? ? ? 3. 由于后臺響應(yīng)回來的數(shù)據(jù)是一個字符串,而且是函數(shù)調(diào)用,所以前端拿到響應(yīng)回來的數(shù)據(jù)相當(dāng)于調(diào)用了該方法,那么前端定義好的方法會自動執(zhí)行,而且方法內(nèi)的形參可以接收到實參值,也就是后臺拼接的數(shù)據(jù)```? ? ? ? function getJson(data){? ? ? ? ? ? console.log(data) // ok? ? ? ? }```? ? 4. 數(shù)據(jù)拿到之后,一般這個動態(tài)創(chuàng)建的script標簽會被刪除掉## vue過渡動畫### 原生css類實現(xiàn)```JavaScript// 1. 將需要實現(xiàn)動畫的元素使用transition標簽包裹起來? ?
我是p元素
? ? ? ? 我是span元素? ?我是一個組件中的元素
我也是組件中的元素我是p元素
? ? ? ? 我是span元素? ?"export default{",
"? ? $2? ? ? ? ",
"}",
"","",
"$3? ? ? ? ? ? ",
""],"description": "create a vue template"}```## yarn的使用```// 1. 使用npm全局安裝yarnnpm i yarn -g// 2. 初始化命令yarn init -y// 3. 安裝包yarn add package-name // 會將安裝的包記錄到dependencies節(jié)點里面yarn add package-name --dev // 會將安裝的包記錄到devDependencies節(jié)點里面yarn global add package-name // 安裝全局包// 4. 刪除包yarn remove package-name// 5. 執(zhí)行命令yarn run devyarn global bin 查看全局包安裝的路徑```## vue-cli腳手架的使用```// 1. 安裝vue-cli腳手架npm i vue-cli -g// 2. 初始化項目模板vue init webpack 項目名稱eslint(語法規(guī)范化插件) 不要安裝? 當(dāng)安裝之后只能按照ESLint中規(guī)定的語法格式去書寫代碼e2e(測試框架) 不要安裝unit test(單元測試框架) 不要安裝// 3. 進入項目安裝所有依賴npm i// 4. 運行npm run devconfig/index.js中 17/18行改端口號和自動打開瀏覽器```## 將項目提交到碼云```// 1. 在項目文件夾初始化gitgit init// 2. 將代碼提交到暫存區(qū)git add .// 3. 提交代碼git commit -m '描述信息'// 4. 關(guān)聯(lián)遠程分支git remote add origin https://gitee.com/UniverseKing/tes.git// 5. 推送到遠程分支git push -u origin master// 6. 查看文件信息git status// 7. 查看loggit log --oenline// 8. 切換版本記錄git reset --hard 版本號```## vue-loader深度作用選擇器> 如果希望在父組件中去改變子組件中的樣式,有時候通過普通子類選擇器無法實現(xiàn),主要是由于添加了`scoped`屬性導(dǎo)致,`vue-loader`中提供了[深度作用選擇器](https://vue-loader.vuejs.org/zh-cn/features/scoped-css.html)可以實現(xiàn)> 這種問題主要出現(xiàn)在使用第三方組件時,需要改第三方組件的樣式時```CSS/*假設(shè).content是父組件中的類 img是子組件中的標簽*//*css中使用>>>*/.content >>> img {}/*scss或者less中使用/deep/*/.content /deep/ img {}```## Promise> `Promise` 是異步編程的一種解決方案.簡單說就是一個容器,里面保存著某個未來才會結(jié)束的事件(通常是一個異步操作)的結(jié)果。從語法上說,`Promise` 是一個對象,可以從該對象獲取異步操作的消息。```Promise有幾種狀態(tài)?Promise有三種狀態(tài)promsie實例一被創(chuàng)建? 默認就是pending狀態(tài)(表示異步操作進行中)如果異步操作成功 狀態(tài)會從 pending 變成 fulfilled(表示異步操作成功)如果異步操作失敗 狀態(tài)會從 pending 變成 rejected(表示異步操作失敗)```### 基本用法```js// 1. 創(chuàng)建promise實例,在實例中執(zhí)行異步操作(比如發(fā)送網(wǎng)絡(luò)請求)// 2. 異步操作成功時,調(diào)用reslove函數(shù)傳遞數(shù)據(jù)// 3. 異步操作失敗時,調(diào)用reject函數(shù)傳遞錯誤信息const promise = new Promise(function(resolve, reject) {// 異步操作// ... if (/* 異步操作成功 */){resolve(value);} else {reject(error);}});// 4. 使用promise實例then方法接收reslove或reject返回的數(shù)據(jù)promise.then(function(value) {// 此處數(shù)據(jù)即為reslove回來的數(shù)據(jù)? // success}, function(error) {// 此處數(shù)據(jù)即為reject回來的數(shù)據(jù)// failure});```### 網(wǎng)絡(luò)請求案例```js// 1. 定義一個使用promise封裝的請求函數(shù),函數(shù)內(nèi)部返回一個promise實例function fetch(){// 函數(shù)內(nèi)部返回一個promise實例return new Promise(function(reslove,reject){// 發(fā)送異步請求axios.get('http://www.lovegf.cn:8090/api/getlunbo').then(function(res){// 請求正常if(res.status == 1){reslove(res.data)}else{reject(res.error)}})})}// 2. 調(diào)用函數(shù)發(fā)送請求,通過Promise.prototype.then方法獲取resolve或reject出來的數(shù)據(jù)fetch().then(function(res){// res為reslove函數(shù)傳出的數(shù)據(jù)},function(err){// err為reject函數(shù)傳出的錯誤})```### 解決回調(diào)地獄> 假設(shè)有三個請求A、B、C,B請求需要依賴A請求的數(shù)據(jù),C請求需要依賴B請求的數(shù)據(jù).> > 傳統(tǒng)回調(diào)函數(shù)式寫法如下:```jsfunction dependices_fetch(){// A請求axios.get('A').then(function(res){if(res.status == 1){// B請求axios.get('B').then(function(res){if(res.status == 1){// C請求axios.get('C').then(function(res){// 請求完畢,執(zhí)行后續(xù)邏輯})}})}})}```> 這種代碼雖然能夠滿足業(yè)務(wù),但是代碼組織結(jié)構(gòu)非常不便于閱讀> > 通過Promise可以封裝代碼,使用鏈式方式解決這種多個異步依賴的回調(diào)> > 如下:```jsfunction fetch(url){return new Promise(function(reslove,reject){axios.get(url).then(function(res){if(res.status == 1){reslove(res.data)}else{reject(res.error)}})})}//then方法內(nèi)部返回的promise實例reslove或reject出來的對象會在下一個then方法內(nèi)部得到fetch('A').then(function(res){// A 請求正常return fetch('B')// 這里返回一個新的promise實例,在后面的then中可以得到該實例reslove或reject出來的對象}).then(function(res){// B 請求正常return fetch('C')}).then(function(res){// C 請求正常// 請求完畢})```### 多個異步請求結(jié)果組合問題> 假設(shè)有A、B、C三個異步請求,需要三個請求的數(shù)據(jù)都回來之后,將數(shù)據(jù)整合后再渲染頁面,這種需求可以使用`Promise.all()`> > Promise.all方法用于將多個 Promise 實例,包裝成一個新的 Promise 實例。```jsfunction fetch(url){return new Promise(function(reslove,reject){axios.get(url).then(function(res){if(res.status == 1){reslove(res.data)}else{reject(res.error)}})})}const p1 = fetch('A')const p2 = fetch('B')const p3 = fetch('C')const p = Promise.all([p1, p2, p3]);p.then(function(res){// res是一個數(shù)組,存放著p1,p2,p3的返回值})```## async 和 await 的使用> async 和 await 是ES7中新提供的兩個操作異步函數(shù)的關(guān)鍵字,本質(zhì)是對Promise進一步的封裝> await 只能用在 async 定義的函數(shù)內(nèi)部,await 可以等待異步操作,并同步的得到異步操作的返回值```JavaScript// 1. 基于Promise的異步操作函數(shù)const fs = require('fs')function getFileByPath(fpath) {? ? return new Promise(function (resolve, reject) {? ? ? ? fs.readFile(fpath, 'utf-8', (err, dataStr) => {? ? ? ? ? ? if (err) return reject(err)? ? ? ? ? ? resolve(dataStr)? ? ? ? })? ? })}// 2. 基于 await 的異步依賴問題(異步操作3依賴異步操作2,異步操作2依賴異步操作1)// 2.1 先使用async定義異步操作const start = async function(){// 2.2 在async內(nèi)部使用await 同步操作? ? ? ? const n1 = await getFileByPath('./1.txt')? ? const n2 = await getFileByPath('./2.txt')? ? const n3 = await getFileByPath('./3.txt')? ? // n3會等待n2 n2 會等待n1}```## axios 使用```JavaScript1. 安裝axiosnpm i axios qs --save2. 在main.js中導(dǎo)入axios,并將axios 掛載到Vue的原型中improt axios from 'axios'Vue.prototype.$axios = axios 3. get請求this.$axios.get('url').then(function(res){? ? // 注意:? ? // 1. 響應(yīng)的數(shù)據(jù)在res.data中? ? // 2. 在回調(diào)函數(shù)內(nèi)部的this 不是Vue實例(通常會將這個回調(diào)函數(shù)改成箭頭函數(shù))})4. post 請求// 注意:當(dāng)后臺要求傳遞的參數(shù)數(shù)據(jù)格式是 application/x-www-form-urlencode// 需要對參數(shù)進行序列化// 使用qs模塊序列化qs.stringify({name:'zs',age:18})// 如果后臺要求的參數(shù)格式 是json格式 appliction/json 不需要序列化this.$axios.post('url',qs.stringify({name:'zs',age:18})).then(res=>{})5. 全局配置// 5.1 設(shè)置全局的請求根域名axios.defaults.baseURL = 'http://vue.studyit.io/';// 5.2 通過設(shè)置請求攔截器 配置post參數(shù)序列化axios.interceptors.request.use(function (config) {? ? // 統(tǒng)一處理post請求的參數(shù) 為application/x-www-form-urlencode? ? if (config.method == 'post') {? ? ? ? config.data = qs.stringify(config.data)? ? }? ? return config;});```## Vue插件開發(fā)```JavaScript1. 單獨新建一個JS文件,在這個文件中導(dǎo)入需要制作成Vue插件的模塊import axios from 'axios'2. 在該模塊身上定義一個install函數(shù),可以接受兩個參數(shù),第一個用于接收Vue構(gòu)造函數(shù)第二個用于配置插件的一些選項axios.install = function(Vue,config){? ? // 1. 注冊全局組件? ? // 2. 將屬性掛載到原型中}3. 導(dǎo)出制作好的Vue插件模塊export default axios4. 使用插件// 能夠使用Vue.use的前提就是傳入的對象一定要有install方法// 調(diào)用Vue.use()的時候 會自動去調(diào)用 傳入對象的 install方法import axios from '插件路徑'Vue.use(axios) // 會自動調(diào)用axios的install方法```## 去除webpack打包后的嚴格模式> 在使用babel-loader的時候,會將所有轉(zhuǎn)換的代碼加上嚴格模式```JavaScript// 方法一: .babelrc文件中忽略不需要使用嚴格模式轉(zhuǎn)換的文件路徑 "ignore": [? ? "./src/js/mui/mui.min.js"? ]// 方法二: babel-loader配置中排除掉不需要嚴格模式轉(zhuǎn)換的文件{? ? test: /\.js$/,? ? use: 'babel-loader',? ? exclude: /mui\.min\.js/}// 方法三: babel-plugin-transform-remove-strict-mode 移除整個項目打包編譯時的嚴格模式// https://www.npmjs.com/package/babel-plugin-transform-remove-strict-mode1. 安裝babel-plugin-transform-remove-strict-modenpm install babel-plugin-transform-remove-strict-mode --save-dev2. babelrc中添加{? "plugins": ["transform-remove-strict-mode"]}```## 路由模式> 通過給`vue-router`配置`mode`屬性,可以指定URL路徑的顯示方式> `mode`屬性默認值是`hash`,此時URL中有#,如:`http://localhost:8888/#/home`,實現(xiàn)方式即`window.location.hash`> 如果`mode`設(shè)置成`history`,此時URL路徑?jīng)]有#,如:`http://localhost:8888/home`,實現(xiàn)方式為`window.history`,這種方式同一個URL不能再其他頁面打開,需要服務(wù)端配置```JavaScriptnew VueRouter({? ? mode:'hash',? ? routes:[? ? ]})```## Vuex的使用> Vuex是一個狀態(tài)管理庫,或者說是專為Vue應(yīng)用程序開發(fā)設(shè)計的狀態(tài)管理模式,它采用集中式存儲管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測的方式發(fā)生變化。> 注:所謂狀態(tài),可以理解成項目中各個組件需要用到的數(shù)據(jù)。> Demo:https://gitee.com/UniverseKing/vuex-study### 初始化公共狀態(tài)``` JavaScript1. 安裝vuexnpm i vuex --save2. 入口文件中實例化Storeimport Vuex from 'vuex'Vue.use(Vuex)var store = new Vuex.Store({? // 1. 用于定義狀態(tài)(公共數(shù)據(jù)),類似于Vue實例中的data方法? state:{? ? ? msg:'初始化的數(shù)據(jù)'? },? // 2. 用于修改狀態(tài),類似于Vue實例中methods? mutations:{? ? ? change(state,arg){? ? ? ? ? // 更改狀態(tài)? ? ? ? ? state.msg = arg? ? ? }? },? // 3. 用于獲取數(shù)據(jù)(獲取數(shù)據(jù)之前可以進行一些操作),類似于Vue實例中的過濾器和計算屬性? // getters 主要會用在跨組件傳值? // getters 中定義的方法內(nèi)部依賴的數(shù)據(jù)發(fā)生變化會自動重新調(diào)用函數(shù)計算返回值? getters:{? ? ? fixmsg(state){? ? ? ? ? return `${state.msg}----處理后的數(shù)據(jù)`? ? ? }? },? // 4. actions和mutations都是定義對數(shù)據(jù)進行操作的方法,mutations中都是同步方法,mutations中定義異步方法? // Action 提交的是 mutation,而不是直接變更狀態(tài)。所以需要修改狀態(tài)還是需要使用mutations中定義的方法? // 從網(wǎng)絡(luò)請求回來的數(shù)據(jù)需要保存到store? // 發(fā)送網(wǎng)絡(luò)請求的方法可以定義到actions中? // actions主要用于處理異步方法? actions:{? ? ? asyncchange(context,arg){? ? ? ? ? // 異步方法? ? ? ? ? setTimeout(() => {? ? ? ? ? ? ? context.commit('change',arg)? ? ? ? ? }, 3000)? ? ? }? }})3. 注入到Vue實例中new Vue({? ? el:'#app',? ? store})```### 使用狀態(tài)``` JavaScript1. 使用state中的數(shù)據(jù)JavaScript: this.$store.state.msgHTML: $store.state.msg2. 使用getters中的數(shù)據(jù)JavaScript: this.$store.getters.fixmsgHTML: $store.getters.msg```### 變更狀態(tài)(修改數(shù)據(jù))> 狀態(tài)的變更必須使用mutations中提供的方法進行修改``` JavaScript1. 提交mutations中的變更方法this.$store.commit('change','我是被修改的數(shù)據(jù)')2. 異步提交actions中的變更方法this.$store.dispatch('asyncchange','我是被異步修改的數(shù)據(jù)')```### 使用輔助函數(shù)> 輔助函數(shù)可以直接將`state`,`getters`中的數(shù)據(jù)映射到Vue組件中的計算屬性上,可以將`mutations`,`actions`中的方法映射到組件中的`methods`中``` JavaScriptimport { mapState } from 'vuex'import { mapGetters } from 'vuex' import { mapMutations } from 'vuex'import { mapActions } from 'vuex'new Vue({? ? computed:mapGetters([? ? ? ? 'count'? ? ])})// ==>等價于new Vue({? ? computed:{? ? ? ? count(){? ? ? ? ? ? return this.$store.state['count']? ? ? ? }})```## vue-cli配置代理解決開發(fā)階段跨域問題```JavaScript// webpack.config.js配置文件導(dǎo)出對象中加入 devServer:{? ? // 代理跨域? ? proxy: {? ? ? '/api': {? ? ? ? target: 'http://vue.studyit.io/api', // 需要被代理的api根域名? ? ? ? changeOrigin: true, // 是否跨域? ? ? ? pathRewrite: {? ? ? ? ? '^/api': '' // 重寫(target中只有根域名時不需要配置此選項)? ? ? ? }? ? ? }? ? }? }---------------------------// vue-cli中config/index.js中proxyTable: {? ? '/api': {? ? ? ? target: 'http://vue.studyit.io/api',? ? ? ? changeOrigin: true,? ? ? ? pathRewrite: {? ? ? ? ? '^/api': ''? ? ? ? }? ? }},```## webpack打包優(yōu)化> 目前項目中所有資源都會被打包到最終生成的一個build.js中,而build.js又被引用到index.html中,當(dāng)打開index.html時,首先需要從互聯(lián)網(wǎng)下載build.js,只有build.js全部下載完畢,瀏覽器的解析引擎才會開始執(zhí)行該js代碼進行代碼解析,當(dāng)解析引擎將代碼解析完畢后再交給渲染引擎開始進行渲染,所有工作幾乎都是同步執(zhí)行,當(dāng)build.js體積非常大時,往往應(yīng)用的首頁加載速度比較慢,而且會看到白屏效果.可以從以下三方面進行優(yōu)化首頁加載速度過慢問題:1. 下載文件速度慢2. 解析JS比較慢3. 渲染比較慢### 服務(wù)端渲染(SSR)> SEO優(yōu)化> 在服務(wù)端先將JS進行解析,解析完成之后生成HTML片段,再將HTML返回給前端,前端直接執(zhí)行渲染界面### 抽取CSS> 將項目中所有CSS抽取到單獨的文件中進行加載,減小了build.js的體積,只要build.js下載完成即可開始解析代碼> https://github.com/webpack-contrib/extract-text-webpack-plugin```JavaScript1. 安裝插件npm install extract-text-webpack-plugin --save-dev2. webpack.config.js中引入插件var ExtractTextPlugin = require('extract-text-webpack-plugin');3. 修改css-loader配置{? ? test: /\.css$/,? ? use: ExtractTextPlugin.extract({? ? ? ? fallback: "style-loader",? ? ? ? use: "css-loader"? ? })},{? ? test: /\.less$/,? ? use: ExtractTextPlugin.extract({? ? ? ? fallback: 'style-loader',? ? ? ? use: ['css-loader', 'sass-loader']? ? })}, // 處理 less 文件的 loader{? ? test: /\.scss$/,? ? use: ExtractTextPlugin.extract({? ? ? ? fallback: 'style-loader',? ? ? ? use: ['css-loader', 'sass-loader']? ? })}4. plugin配置中使用插件new ExtractTextPlugin('app.css')```### 分離第三方包> 將項目中引用的第三方JS代碼抽取到一個單獨的文件,也可以減少build.js的體積,還是只需要build.js下載完畢瀏覽器解析引擎即可開始進行解析,然后瀏覽器同時再去下載其他JS和CSS> 一般將發(fā)布階段所需要依賴的包全部進行分離,即`package.json`中`dependencies`中的所有包進行分離```JavaScript 1. 引入webpack和路徑處理模塊var webpack = require('webpack');var path = require('path');2. 修改入口文件entry: {? ? app: path.resolve(__dirname, 'src/main.js'),? ? // 需要分離的第三方包名寫在數(shù)組中? ? vendors: ['vue', 'vue-resource', 'vue-router', 'vuex', 'mint-ui', 'moment', 'vue-preview']},3. plugin中配置插件// 分離第三方包插件new webpack.optimize.CommonsChunkPlugin({? ? name: 'vendors',? ? filename: 'vendors.js' // 分離出來的js文件的名稱})```### 組件按需加載> vue-router提供的路由懶加載可以按需加載組件。> 特點: 當(dāng)沒有訪問到某個頁面路由時,不去加載對應(yīng)的組件代碼,節(jié)約數(shù)據(jù)請求量,加快首頁DOM渲染速度```將import home from './components/Home.vue' 這種導(dǎo)入方式換成const home = () => import('../components/Home.vue');```## 路由導(dǎo)航鉤子函數(shù)> 在跳轉(zhuǎn)路由時,進行攔截,一般用于權(quán)限驗證或登錄等操作> https://router.vuejs.org/zh-cn/advanced/navigation-guards.html### 路由獨享守衛(wèi)```JavaScriptconst router = new VueRouter({? routes: [? ? {? ? ? path: '/home',? ? ? component: HomeContainer,? ? ? // 進入路由之前進行攔截? ? ? beforeEnter: (to, from, next) => {? ? ? ? // from 從哪個路由來? ? ? ? // to 到哪個路由去? ? ? ? // 釋放守衛(wèi) 進入下一個環(huán)節(jié)? ? ? }? ? }? ]})```### 全局守衛(wèi)```JavaScriptrouter.beforeEach((to, from, next) => {? })```## Cmder使用> window系統(tǒng)下增強型命令行工具,免安裝,解壓即用```JavaScript// 1. 將cmder.exe加入環(huán)境變量1. window + R 輸入 sysdm.cpl2. 選中 高級 - 環(huán)境變量 - 系統(tǒng)變量 - Path3. 將cmder.exe所在目錄添加到Path中// 2. 天假右鍵菜單在cmder.exe所在目錄打開命令行窗口 輸入 Cmder.exe /REGISTER ALL```## HBuilder打包> HBuilder打包 是將前端開發(fā)的HTML/CSS/JS文件進行打包,打包成可以直接安裝在手機上面的App,不借助瀏覽器就可以直接運行```JavaScript1. 使用webpack將項目進行打包,打包好的文件會在dist目錄webpack -p2. 打開Hbuilder,新建移動App項目,然后刪掉css/js/imgs文件夾和index.html文件3. 將使用webpack打包的dist目錄里面的文件全部拷貝到新建的移動項目目錄中4. 選中HTML文件,點擊HBuilder導(dǎo)航上面的`發(fā)行`-`打原生安裝包`,直接下一步,選安卓公共證書-`打包`5. 在項目的`unpackage\release`中可以得到打包完畢的apk文件```## cordova打包> 直接在本地進行打包> 需要電腦配置Java環(huán)境和Android環(huán)境 `gradle````JavaScript// 1. 安裝全局cordovanpm i cordova -g// 2. 創(chuàng)建cordova項目cordova create cordova_project// 3. 添加需要打包的平臺cordova platform add android// 4. 運行或者打包cordova run androidcordova build android```## vue-cli打包完成后1. 錯誤信息:`postcss-svgo: Error in parsing SVG: Unquoted attribute value`? ? - 需要修改mui.css中的 **圖片引用** 單引號全部改成雙引號2. 提示必須使用服務(wù)器的方式打開,即使用localhost方式打開? ? ? ? // 1. 安裝http-server? ? ? ? npm i http-server -g? ? ? ? // 2. 使用hs -o命令打開index.html文件? ? ? ? hs -o3. 如果打包完成后希望直接用file協(xié)議打開,需要修改config/index.js 中的build下的`assetsPublicPath: '/'`換成`assetsPublicPath: './'`## Parcel使用```JavaScriptnpm i parcel-bundler -gparcel index.html```----> 項目地址:https://gitee.com/UniverseKing/vue_cms> [Vue組件](https://github.com/UniverseKing/awesome-github-vue#%E5%BA%94%E7%94%A8%E5%AE%9E%E4%BE%8B)## MVC 和 MVVM 區(qū)別> MVC從后臺業(yè)務(wù)邏輯對項目進行分層開發(fā) 數(shù)據(jù)流通是單向的,所有的數(shù)據(jù)流通都需要C進行控制> MVVM是前端框架的一種設(shè)計模式,核心是雙向數(shù)據(jù)綁定,M和V可以直接進行通信,VM只負責(zé)數(shù)據(jù)的綁定## 你平時開發(fā)項目,有沒有遇到比較難的問題,是怎么解決的?- vue-loader 深度作用選擇器(父組件中不能給v-html渲染出來的標簽添加樣式)- babel-loader在編譯代碼時,會給所有的代碼加上嚴格模式,不能使用call,callee,arguments..## 項目接口:> http://www.escook.cn:3000/> http://www.lovegf.cn:8899/## 真機調(diào)試```1. 手機開一個WiFi熱點2. 使用電腦連接手機的WiFi熱點3. 在電腦上打開CMD命令行 輸入ipconfig命令 查看的IP地址是 無線局域網(wǎng)下面的ipv4地址4. 在項目中使用--host IP地址 重啟項目5. 在手機中訪問項目的IP地址```