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