一赤惊、概念介紹
Vue.js和React.js分別是目前國內(nèi)和國外最火的前端框架吼旧,框架跟類庫/插件不同,框架是一套完整的解決方案未舟,對項目的侵入性較大圈暗,當項目需要更換框架時,需要重構(gòu)整個項目裕膀,類庫/插件則是提供某一個小功能员串,對項目的侵入性較小,當使用某個類庫/插件無法完成某些需求時昼扛,可以很容易切換到其它類庫/插件來實現(xiàn)需求寸齐,例如從jQuery.js切換到zepto.js,從IScroll.js切換到ScrollMagic.js抄谐,只需要將所用到的代碼替換一下即可渺鹦,框架和類庫可以提高開發(fā)效率,web前端的發(fā)展歷程是原生JS蛹含、類似jQuery.js的類庫毅厚、前端模板引擎、Vue.js/React.js/Angular.js框架浦箱,而且Vue+Weex和React Native都可以進行手機app的開發(fā)吸耿,阿里系用Vue+Weex比較多,Vue.js酷窥、Angular.js咽安、和React.js并稱為前端三大主流框架,它們?nèi)齻€都是一套構(gòu)建用戶界面的框架(MVVM框架)竖幔,即只關注視圖層(UI)板乙,但是Angular.js和React.js是老外所編寫的,所以全部資料都是英文的拳氢,而Vue.js是國人(尤雨溪募逞,華裔,前Google工程師)所編寫的馋评,所以全部資料都是中文的放接,Vue.js是一個漸進式框架,可以動態(tài)構(gòu)建用戶界面留特,編碼簡潔纠脾,體積小玛瘸,運行效率高,適合移動/PC端開發(fā)苟蹈,并且Vue.js中整合了Angular.js和React.js中的眾多優(yōu)點糊渊,比如參考了React.js的組件化和虛擬DOM技術,借鑒了Angular.js的模板和數(shù)據(jù)綁定技術慧脱,不僅易于上手渺绒,而且生態(tài)比較好,比如有著豐富的菱鸥、便于跟已有項目和第三方類庫/插件(比如Swiper.js宗兼、IScroll.js、...)相整合的第三方類庫氮采,以及可以輕松引入基于Vue.js的插件來進行大型項目的開發(fā)殷绍,英文官網(wǎng)是vuejs.org,中文官網(wǎng)是cn.vuejs.org鹊漠,打開之后主到,點擊GitHub-releases(發(fā)布版),然后就可以下載最新版本的壓縮包了贸呢,解壓縮之后打開dist文件夾镰烧,然后找到Vue.js就可以了拢军,Vue.js的核心優(yōu)勢一楞陷,是無需操作DOM,直接通過數(shù)據(jù)來驅(qū)動界面更新茉唉,所以我們只需要關心如何獲取數(shù)據(jù)固蛾、處理數(shù)據(jù)、以及編寫業(yè)務邏輯代碼度陆,將處理好的數(shù)據(jù)交給Vue.js就可以了艾凯,然后Vue.js就會自動將數(shù)據(jù)渲染到模板(界面)上,Vue.js的核心優(yōu)勢二懂傀,是組件化開發(fā)趾诗,當把一個很大的界面拆分成多個小的界面時,每一個小的界面就叫做一個組件蹬蚁,將大界面拆分成一個個組件恃泪,然后再通過封裝好的組件拼接成一個完整的網(wǎng)頁,這個過程就叫做組件化犀斋,好處是可以簡化Vue實例對象中的代碼贝乎,并且可以提高復用性
[if !supportLists]二、[endif]Vue.js的基本使用
創(chuàng)建一個Vue實例對象的格式為“<div id=“app”><p>{{name}}</p></div> ?let vue = new Vue?({el: “#app”,?data: {name: “李南江”}?});(//也可以通過“new Vue?().$mount (“#app”);”的形式掛載到某個HTML標簽上叽粹,“#app”也可以換成一個DOM元素)”览效,{{}}叫做插值語法却舀,MVVM設計模式中的M(Model)指的是數(shù)據(jù)模型,用來保存數(shù)據(jù)锤灿,處理數(shù)據(jù)業(yè)務邏輯挽拔,V(View)指的是視圖,用來展示數(shù)據(jù)但校,與用戶交互篱昔,VM(View Model)指的是數(shù)據(jù)模型和視圖之間的橋梁,當把M比作中國人始腾,V比作美國人時州刽,VM就是翻譯,MVVM設計模式最大的特點就是支持數(shù)據(jù)的雙向傳遞浪箭,數(shù)據(jù)可以從M經(jīng)由VM傳向V穗椅,也可以從V經(jīng)由VM傳向M,Vue.js就是基于MVVM設計模式的JS框架奶栖,頁面上被控制的區(qū)域就是V匹表,Vue實例對象就是VM,實例對象配置對象中的data/methods/computed對象等就是M宣鄙,雖然Vue.js在默認情況下只支持數(shù)據(jù)的單向傳遞袍镀,即從M經(jīng)由VM傳向V,但是也提供了雙向傳遞的能力冻晤,在Vue.js內(nèi)部封裝好的一些具有特定功能的自定義HTML屬性/給HTML屬性添加特定功能的操作符就叫做指令苇羡,在HTML標簽上直接添加這些指令就可以了,使用v-model指令可以在<input>/<textarea>/<select>上創(chuàng)建value/checked/selected屬性值的雙向傳遞鼻弧,并且v-model指令會忽略此<input>/<textarea>/<select>的初始value/checked/selected屬性值设江,而總是將M作為數(shù)據(jù)來源(從V傳向M的數(shù)據(jù)會自動加上引號),例如“<input type=“text”v-model=“msg”> ?data: {msg: “知播漁”}”攘轩,“<select id=“app”v-model=“msg”><option value=“奔馳”>奔馳</option> ?<option value=“寶馬”>寶馬</option> ?<option value=“奧迪”>奧迪</option></select> ?data: {msg: “奧迪”}”叉存,使用v-once指令可以讓此HTML標簽內(nèi)部被傳遞的值永遠是M中初始化的值,不隨著M的變化而變化度帮,例如“<p id= “app”v-once>{{msg}}</p> ?data: {msg: “hello”}”歼捏,由于Vue.js數(shù)據(jù)傳遞的過程是先將未傳遞數(shù)據(jù)的界面(V)展示給用戶,然后再將模型(M)中的數(shù)據(jù)傳遞給界面(V)笨篷,傳完值之后先將新界面(V)放到web瀏覽器的緩存中瞳秽,最后再將新界面(V)替換掉舊界面(V)并渲染出來,所以當用戶網(wǎng)絡比較慢或者網(wǎng)頁性能比較差時冕屯,用戶就會看到{{}}寂诱,使用v-cloak指令可以讓此HTML標簽在被傳完值之后再顯示,但必須配合CSS代碼“[v-cloak] {display: none;}”一起使用安聘,即先隱藏未被傳值的界面痰洒,等到被傳完值之后再重新顯示瓢棒,使用v-text/v-html指令可以相當于原生JS里的innerText/innerHTML屬性,例如“<p v-html=“msg”></p> ?data: {msg: “<span>我是span</span>”}”丘喻,使用v-if指令可以決定此HTML標簽的創(chuàng)建/刪除脯宿,當v-if值是true時,就創(chuàng)建泉粉,反之就刪除连霉,v-if的等于號后面的一對引號就類似于插值語法,在里邊可以書寫任何合法的JS表達式嗡靡,v-if=“true”/v-if=“false”這種格式也是正確的(不用管在vscode編輯器中它的顯示顏色如何)跺撼,v-if、v-else-if讨彼、和v-else指令可以配合使用歉井,并且中間不能被斷開,當v-if值是false時哈误,就依次判斷后續(xù)的v-else-if值哩至,哪個是true就創(chuàng)建哪個,v-else-if和v-else指令不能單獨使用蜜自,使用v-show指令可以決定此HTML標簽行內(nèi)樣式display值是默認/none菩貌,當v-show值是true時,就是默認重荠,反之就是none箭阶,當需要頻繁切換HTML標簽的顯示/隱藏時,由于使用v-show指令無需頻繁的創(chuàng)建/刪除HTML標簽晚缩,性能比較好尾膊,所以推薦使用v-show指令媳危,否則使用v-if指令荞彼,使用v-for指令可以根據(jù)某個對象/數(shù)組/字符串/數(shù)字被for in循環(huán)遍歷所執(zhí)行的次數(shù)來多次創(chuàng)建此HTML標簽,例如“<li v-for=“(value, key) in obj”>{{key}}---{{value}}</li>(//value必須有待笑,而key可有可無鸣皂,當不寫key時,小括號就不用寫了暮蹂,key也可以換成index寞缝,obj也可以換成arr,value和key/index這兩個變量只能在此HTML標簽/此HTML標簽的后代HTML標簽中使用) ?data: {obj: {name: “l(fā)nj”, age: 33, gender: “man”, class: “知播漁”} }”仰泻,v-for指令在創(chuàng)建HTML標簽時荆陆,會先查看web瀏覽器的緩存中有沒有此HTML標簽,當有此HTML標簽時集侯,為了提升性能被啼,就不會新建此HTML標簽帜消,而是采取就地復用的策略,當沒有此HTML標簽時浓体,就會新建一個HTML標簽泡挺,新建完之后先放到web瀏覽器的緩存中,然后再從web瀏覽器的緩存中將此HTML標簽渲染到界面上(每個HTML標簽只能被渲染一次)命浴,在Vue.js中娄猫,只要配置對象中的數(shù)據(jù)發(fā)生了更新,就會自動重新渲染界面生闲,當在一個<ul>的開頭處新增了一個<li>時媳溺,由于就地復用的策略,就會造成數(shù)據(jù)的對應關系發(fā)生混亂碍讯,為了解決這個問題褂删,我們可以在創(chuàng)建HTML標簽時,給每一個HTML標簽v-bind上一個獨一無二的key值(不能使用索引值充當key值冲茸,因為當<ul>的<li>被新增/刪除時屯阀,索引值都會發(fā)生變化),這樣一來轴术,當v-for指令由于新增<li>而重新渲染界面時难衰,會先判斷<li>的key值是否跟web瀏覽器緩存中的匹配,匹配就復用逗栽,不匹配就新建<li>盖袭,使用v-bind指令可以給此HTML標簽的HTML屬性直接賦值(即字面量)/從配置對象/v-for指令的value和key中傳遞取值(即變量),當所作用的是class/style屬性時彼宠,也可以使用數(shù)組/對象的形式賦值鳄虱,例如“<input type=“text”v-bind:value=“age + 1”>(//冒號前的v-bind也可以省略,直接使用冒號就可以) ?data: {age: 18}”凭峡,“<input type=“text”:value=“‘hello world’”>”拙已,“:class=“從配置對象中傳遞的類名1, 從配置對象中傳遞的類名2, ...””,“:class=“[‘直接添加的類名1’, ‘直接添加的類名2’, ...]”(//當數(shù)組中的類名不加引號時摧冀,也會去M中查找數(shù)據(jù))”倍踪,“:class=“[flag?‘直接添加的類名1’:‘直接添加的類名2’, ...]”(//數(shù)組中的每一個元素都可以是一個三目運算表達式)”,“:class=“[‘size’, ‘color’, {‘a(chǎn)ctive’: true}]”(//也可以使用對象來代替三目運算表達式索昂,當取值是true時建车,就代表此HTML標簽擁有此類名,當取值是false時椒惨,就代表此HTML標簽不擁有此類名)”缤至,“<p :class=“obj”>我是段落</p> ?data: {obj: {‘size’: false, ‘color’: false, ‘a(chǎn)ctive’: true} }(//當所添加的類名太多時,可以從配置對象中傳遞一個對象)”康谆,“:style=“{color: ‘red’, ‘font-size’: ‘50px’}”(//當CSS屬性名稱包含中劃線時领斥,必須加引號错洁,或者改用駝峰)”,“<p :style=“obj”>我是段落</p> ?data: {obj: {color: ‘red’, ‘font-size’: ‘50px’} }(//從配置對象中傳遞一個對象)”戒突,“<p :style=“[obj1, obj2]”>我是段落</p>(//當想要從配置對象中傳遞多個對象時屯碴,可以放到數(shù)組中)”,使用v-on指令可以給此HTML標簽綁定事件膊存,取值既可以是從methods對象中所傳遞的回調(diào)函數(shù)导而,也可以直接在一對雙引號中寫回調(diào)函數(shù),還可以直接在一對雙引號中書寫合法的JS語句隔崎,但后兩種方式不支持原生JS自帶的方法今艺,比如console.log或者alert,會報錯爵卒,說你未定義虚缎,格式為“v-on:去掉on的事件名稱.修飾符1.修飾符2...=“回調(diào)函數(shù)名稱()”(//“v-on:”也可以換成“@”,修飾符可有可無钓株,回調(diào)函數(shù)名稱后面的小括號可寫可不寫实牡,但傳參的時候必須寫,傳入$event就代表原生JS中的事件對象轴合,但是當我們在<template>的HTML標簽中正常調(diào)用methods對象中所定義的方法時创坞,函數(shù)名稱后面必須加小括號,否則無效)”受葛,例如“<button v-on:click=“myFn ($event)”>我是按鈕</button> ?data: {gender: “man”}, methods: {myFn (e) {alert (e, this.gender);} }(//methods對象是專門用于存儲函數(shù)的题涨,當想要在組件配置對象的函數(shù)作用域中訪問/調(diào)用自己配置對象中的屬性/方法時,前面必須加上this总滩,根實例組件配置對象的函數(shù)作用域中的this指針指代的是Vue實例對象纲堵,自定義組件配置對象的函數(shù)作用域中的this指針指代的是VueComponent實例對象)”婆廊,使用once修飾符可以讓此HTML標簽只觸發(fā)一次事件的回調(diào)函數(shù)揩抡,使用prevent修飾符可以移除此HTML標簽的默認事件(相當于event.preventDefault ();)黍图,使用stop修飾符可以阻止此HTML標簽的事件冒泡(相當于event.stopPropagation ();)痹兜,使用self修飾符可以讓此HTML標簽所綁定的事件只有此HTML標簽自己才可以觸發(fā)(冒泡和捕獲都觸發(fā)不了),使用capture修飾符可以讓此HTML標簽捕獲到相應事件嫉你,監(jiān)聽鍵盤上特定按鍵所觸發(fā)事件的修飾符就叫做按鍵修飾符剑令,分為系統(tǒng)自帶的和自定義的,格式為“@keyup.按鍵修飾符=“myFn””炕舵,系統(tǒng)自帶的按鍵修飾符包括enter、tab跟畅、delete咽筋、esc、space徊件、up奸攻、down蒜危、left、和right修飾符睹耐,自定義的按鍵修飾符就是鍵盤上某個按鍵的鍵碼值辐赞,例如F2這個按鍵就是113,也可以通過一行代碼給113起一個別名f2硝训,例如“Vue.config.keyCodes.f2 = 113;”响委,在Vue.js中除了可以直接使用一些系統(tǒng)自帶的全局指令以外,還可以自己注冊一些自定義全局指令窖梁,在任何一個Vue實例對象控制的區(qū)域內(nèi)都可以使用的自定義指令就叫做自定義全局指令赘风,Vue類對象調(diào)用它的directive方法可以返回/注冊一個自定義全局指令,注冊一個自定義全局指令的格式為“Vue.directive (‘去掉v-的自定義指令名稱’, {鉤子函數(shù)名稱: function (el, obj) {指令業(yè)務邏輯代碼;} });(//形參el接收到的是使用此指令的DOM元素纵刘,形參obj接收到的是一個對象邀窃,即{name: 去掉v-的指令名, value: 使用此指令時所賦的值})”,bind鉤子函數(shù)是當我們將此指令添加到HTML標簽上時所執(zhí)行的回調(diào)函數(shù)假哎,inserted鉤子函數(shù)是當添加此指令的HTML標簽被添加到其父標簽內(nèi)部時所執(zhí)行的回調(diào)函數(shù)瞬捕,例如“<input type=“text”v-focus> ?Vue.directive (“focus”, {inserted: function (el) {el.focus ();} });(//當將inserted換成bind時,會在還沒渲染HTML標簽時就過早的執(zhí)行了回調(diào)函數(shù)舵抹,也就是會導致所執(zhí)行的回調(diào)函數(shù)無效山析,所以必須使用inserted鉤子函數(shù))”,“<p v-color=“‘blue’”>我是段落</p> ?Vue.directive (“color”, {bind: function (el, obj) {el.style.color = obj.value;} });”掏父,在某一個特定Vue實例對象控制的區(qū)域內(nèi)才可以使用的自定義指令就叫做自定義局部指令笋轨,注冊一個自定義局部指令的格式為“<div id=“app2”><p v-color=“‘red’”>我是段落</p></div> ?let vue = new Vue?({el: “#app2”,directives: {color: {bind: function (el, obj) {el.style.color = obj.value;} } } });”,在Vue.js中赊淑,可以在插值語法{{}}中編寫合法的JS表達式爵政,例如“<p>{{msg.split (“”).reverse ().join (“”)}}</p> ?data: {msg: “abcdefg”}”,但是其缺點是沒有代碼提示陶缺,并且當語句過于復雜時不利于維護钾挟,所以需要在配置對象的computed對象中定義計算屬性,雖然計算屬性的取值是一個函數(shù)饱岸,但是在Vue.js中規(guī)定它就是屬性掺出,不是方法,所以在使用的時候一定不能在計算屬性的名稱后面加小括號苫费,否則會報錯汤锨,例如“<p>{{msg}}</p> ?computed: {msg: function () {let res = “abcdef”.split (“”).reverse ().join (“”); ?return res;} }”,使用computed對象中的計算屬性和methods對象中的函數(shù)都可以獲取到返回值百框,但是computed對象中的計算屬性會將返回值緩存起來闲礼,只要數(shù)據(jù)沒有發(fā)生變化,就不會重新執(zhí)行函數(shù)來求值,而methods對象中的函數(shù)不會將返回值緩存起來柬泽,每一次調(diào)用都會重新執(zhí)行函數(shù)來求值慎菲,所以當返回值不經(jīng)常發(fā)生變化時,使用計算屬性的性能更好锨并,過濾器跟methods對象中的函數(shù)以及computed對象中的計算屬性一樣露该,都是用來處理數(shù)據(jù)的,但是過濾器一般用于格式化HTML標簽中所插入的文本數(shù)據(jù)第煮,Vue類對象調(diào)用它的filter方法可以返回/注冊一個自定義全局過濾器解幼,注冊一個自定義全局過濾器的格式為“<p>{{msg | 過濾器名稱 (123)}}</p> ?Vue.filter (“過濾器名稱”, function (value, data) {value = value.replace (/學院/g, “大學”); ?return value;});(//“|”叫做管道符號,過濾器名稱后面加不加小括號均可空盼,加的話可以傳參书幕,形參value接收到的是msg,形參data接收到的是123揽趾,原HTML標簽中的數(shù)據(jù)msg經(jīng)過指定過濾器處理之后台汇,再插入到原HTML標簽中)”,過濾器只能在插值語法/v-bind指令中使用篱瞎,并且是可以連續(xù)使用的苟呐,例如“<p>{{name | formartStr1 | formartStr2}}</p>(//<el-input>的:value起到的是雙向綁定的作用,不可以使用filters過濾器進行格式化)”俐筋,注冊一個自定義局部過濾器的格式為“<div id=“app2”><p>{{name | formartStr}}</p></div> ?let vue = new Vue?({el: “#app2”,filters: {formartStr: function (value) {value = value.replace (/學院/g, “大學”); ?return value;} } });(//this在filters中是不可使用的牵素,因為filters過濾器注冊在vue實例之前,所以this指向了window澄者,但是因為是嚴格模式笆呆,this指向undefined,解決方式詳見www.cnblogs.com/qinyuanchun/p/16337594.html)”粱挡,使用<transition>可以給其單個子標簽的顯示/隱藏/創(chuàng)建/刪除設置transition(可以搭配v-show/v-if指令使用)赠幕,當從隱藏變?yōu)轱@示以及顯示變?yōu)殡[藏時,會按照“.v-enter(//顯示前)”询筏、“.v-enter-active(//顯示中榕堰,transition屬性設置在此)”、“.v-enter-to(//顯示后)”嫌套、“.v-leave(//隱藏前)”逆屡、“.v-leave-active(//隱藏中,transition屬性設置在此)”踱讨、和“.v-leave-to(//隱藏后)”這六個系統(tǒng)自帶的過渡類名所設置的CSS屬性來執(zhí)行樣式魏蔗,當想要讓一個顯示狀態(tài)/新建的HTML標簽剛一進入頁面/渲染出來就有transition時,給此<transition>添加一個appear屬性就可以了勇蝙,當想要讓不同的子標簽執(zhí)行不同的transition時沫勿,可以給不同的<transition>的name屬性設置不同的取值挨约,并將不同的name值替換類名中的字母v作為前綴味混,再分別設置CSS屬性就可以了产雹,無論顯示還是隱藏,在執(zhí)行完transition之后翁锡,就會給被嵌套的子標簽刪除所綁定的類名蔓挖,所以“.v-enter-to(//顯示后)”所設置的CSS樣式執(zhí)行完之后就會失效,當不想讓其失效時馆衔,可以改用Vue.js提供的JS鉤子函數(shù)來實現(xiàn)transition瘟判,即給<transition>綁定其@before-enter值(顯示前)、@enter值(顯示中)角溃、@after-enter值(顯示后)拷获、@enter-cancelled值(顯示中途被取消)、@before-leave值(隱藏前)减细、@leave值(隱藏中)匆瓜、@after-leave值(隱藏后)、和@leave-cancelled值(隱藏中途被取消)所指代的鉤子函數(shù)未蝌,例如“<div id=“app”><button @click=“toggle”>我是按鈕</button> ?<transition appear v-bind:css=“false”(//這句可以跳過CSS的檢測驮吱,避免被CSS代碼所影響) @before-enter=“beforeEnter”@enter=“enter”@after-enter=“afterEnter”><div class=“box”v-show=“isShow”></div></transition></div> ?el: “#app”,data: {isShow: true}, methods: {toggle () {this.isShow = !this.isShow;}, beforeEnter (el) {el.style.opacity = 0;}, enter (el, done) {el.offsetHeight; ?el.style.transition = “all 3s”; ?done ();}(//形參el接收到的是被嵌套的子標簽所對應的DOM元素,顯示/隱藏中的鉤子函數(shù)作用域中必須加上一句“el.offsetWidth;”/“el.offsetHeight;”萧吠,否則沒有transition左冬,并且最后必須“done ();”,否則顯示/隱藏后的鉤子函數(shù)不會執(zhí)行纸型,當想要讓一個顯示狀態(tài)的HTML標簽剛一進入頁面就有transition時拇砰,必須把“done ();”放到一個setTimeout中執(zhí)行,延遲時間設置為0就可以了), afterEnter (el) {el.style.opacity = 1; ?el.style.marginLeft = “500px”;}”狰腌,JS鉤子函數(shù)還可以配合第三方velocity.js動畫庫來實現(xiàn)transition除破,引入完Vue.js之后,再引入velocity.js癌别,例如“<script src=“https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js”></script> ?enter (el, done) {Velocity (el, {opacity: 1, marginLeft: “500px”}, 3000); ?done ();}(//也可以將3000換成{duration: 3000})”皂岔,除了使用系統(tǒng)自帶的過渡類名以外,還可以自定義過渡類名展姐,即利用<transition>的enter-class值(顯示前)躁垛、enter-active-class值(顯示中)、enter-to-class值(顯示后)圾笨、leave-class值(隱藏前)教馆、leave-active-class值(隱藏中)、和leave-to-class值(隱藏后)來充當過渡類名擂达,然后再通過此過渡類名來給被嵌套的子標簽設置CSS屬性土铺,這些自定義HTML屬性也可以配合第三方Animate.css動畫庫來實現(xiàn)transition(特效),官網(wǎng)是“animate.style”,例如“<link href=“https://cdn.jsdelivr.net/npm/animate.css@3.5.1”rel=“stylesheet”type=“text/css”> ?<transition appear enter-class=“”enter-active-class=“animated bounceInRight”enter-to-class=“”><div class=“box”v-show=“isShow”></div></transition>(//只需給顯示/隱藏中的HTML屬性綁定上所需要的特效名稱即可悲敷,其中bounceInRight也可以換成其他的特效究恤,詳見官網(wǎng))”,使用<transition-group>可以給其多個子標簽的顯示/隱藏/創(chuàng)建/刪除設置transition后德,跟<transition>的用法一致部宿,<transition-group>有一個tag屬性,默認值是“span”瓢湃,代表將其所有的子標簽都嵌套在一對<span>內(nèi)理张,也可以給tag屬性自定義取值,當tag值是“ul”绵患,其所有子標簽又都是<li>時雾叭,<ul>就可以不用寫了,其實使用<transition>/<transition-group>也可以給其內(nèi)部所嵌套的單/多個<自定義組件>的顯示/隱藏/創(chuàng)建/刪除設置transition落蝙,但是不同<自定義組件>的顯示和隱藏transition默認是同時執(zhí)行的织狐,除非給<transition>/<transition-group>添加一個mode屬性,取值可以是out-in(當前<自定義組件>執(zhí)行完隱藏的transition之后掘殴,另一個<自定義組件>再執(zhí)行顯示的transition)/in-out(另一個<自定義組件>執(zhí)行完顯示的transition之后赚瘦,當前<自定義組件>再執(zhí)行隱藏的transition),在Vue.js中注冊自定義組件的流程是奏寨,首先創(chuàng)建(返回)一個組件構(gòu)造器起意,然后利用此組件構(gòu)造器再注冊一個自定義組件,Vue類對象調(diào)用它的extend方法可以返回一個組件構(gòu)造器(即一個叫做VueComponent的構(gòu)造函數(shù)/類)病瞳,格式為“l(fā)et Profile = Vue.extend ({template: `<div><img src=“images/fm.jpg”> ?<p>我是描述信息</p></div>`});(//template值有且只有一個根標簽揽咕,否則會報錯,全都嵌套在一對<div>中就可以了套菜,在模板字符串``內(nèi)編寫HTML代碼的弊端是沒有提示亲善,嚴重影響開發(fā)效率,所以可以將HTML代碼寫到“<script id=“info”type=“text/html”></script>”/“<template id=“info”></template>(//推薦)”中逗柴,然后把“#id值”賦值給template屬性就可以了)”蛹头,new組件構(gòu)造器所生成的VueComponent實例對象可以掛載到界面上任意一個HTML標簽上,既可以免注冊進行自我渲染戏溺,還可以將被掛載的HTML標簽覆蓋掉渣蜗,例如“l(fā)et LoadingContructor = Vue.extend (Loading); ?let LoadingInstance = new LoadingContructor (); ?LoadingInstance.$mount (oDiv);(//oDiv是一個DOM元素,也可以將其換成一個選擇器字符串)”旷祸,利用VueComponent實例對象還可以動態(tài)的添加/修改自己配置對象中的屬性耕拷,例如“LoadingInstance.isShow = true;”,Vue類對象調(diào)用它的component方法既可以注冊一個自定義全局組件(可以在任意一個根實例/全局/局部組件的根標簽中渲染)托享,還可以返回傳入全局組件名稱的組件構(gòu)造器骚烧,注冊一個自定義全局組件的格式為“Vue.component (“abc”, Profile);(//參數(shù)1是組件名稱浸赫,參數(shù)2是組件構(gòu)造器,可以免調(diào)用extend方法赃绊,直接將參數(shù)2換成extend方法的實參即配置對象就可以了既峡,系統(tǒng)會自動調(diào)用extend方法的,在注冊自定義組件時凭戴,當此自定義組件名稱使用了駝峰命名時涧狮,在渲染此<自定義組件>時必須轉(zhuǎn)成短橫線分隔命名)”炕矮,注冊一個自定義局部組件的格式為“<div id=“app2”><abc></abc></div> ?let vue2?= new Vue?({el: “#app2”,components: {abc: {template: “#info”} }});(//規(guī)律就是么夫,先將方法名稱變成對象名稱,結(jié)尾加s肤视,再將參數(shù)1和參數(shù)2即組件名稱和配置對象組合成此對象內(nèi)部的一個鍵值對就可以了档痪,也就是將子組件通過components對象掛載到其父組件的配置對象中,<自定義局部組件>只能在其父組件的根標簽中渲染邢滑,可以是根標簽中的任意位置)”腐螟,Vue實例對象就是一個根實例組件,由于在根實例組件的配置對象中我們可以添加data和methods對象困后,所以在自定義全局/局部組件的配置對象中我們也可以添加data和methods對象乐纸,但是在自定義全局/局部組件的配置對象中data值是一個工廠函數(shù),data對象以此工廠函數(shù)返回值的形式來添加摇予,例如“data: function () {return {abcMsg: “學院”} }(//這種設計思路源自于組件的復用性汽绢,每當使用此組件創(chuàng)建一個新的區(qū)塊時,都會調(diào)用一次data方法侧戴,所以每次返回的data對象就會跟當前所創(chuàng)建的區(qū)塊綁定在一起宁昭,這樣就有效的避免了數(shù)據(jù)混亂)”,不同的普通HTML標簽可以使用v-if和v-else指令來實現(xiàn)創(chuàng)建/刪除的切換酗宋,由于組件的本質(zhì)就是一個自定義HTML標簽积仗,所以不同的<自定義組件>也可以使用v-if和v-else指令來實現(xiàn)創(chuàng)建/刪除的切換,還可以使用<component>(動態(tài)組件)來實現(xiàn)不同<自定義組件>創(chuàng)建/刪除的切換蜕猫,格式為“<component v-bind:is=“需要創(chuàng)建的<自定義組件>名稱”></component>(//推薦)”寂曹,<component>最好嵌套在<keep-alive>中使用,因為可以將被刪除的<自定義組件>保存在web瀏覽器的緩存中回右,當再次創(chuàng)建時隆圆,直接從web瀏覽器的緩存中渲染,好處是可以保存被刪除的<自定義組件>的狀態(tài)楣黍,<router-view>也可以嵌套在<keep-alive>中使用匾灶,還可以給<keep-alive>添加一個include/exclude屬性,取值是自定義組件的名稱租漂,意思是只有名稱匹配的<自定義組件>才會/不會被緩存阶女,詳見cn.vuejs.org/v2/api/#keep-alive颊糜,任意一個父組件和在其配置對象的components對象中所注冊的子組件,或任意一個組件和在其根標簽中所渲染的全局組件秃踩,都叫做父子組件衬鱼,例如“<template id=“father”><div><p>我是父組件</p> ?<son></son></div></template>”,當想要將父組件配置對象中的某個值傳遞給其子組件時憔杨,首先第一步鸟赫,在渲染<子組件>時通過v-bind指令配合自定義接收名稱來接收傳遞過來的某個值,然后第二步消别,將“自定義接收名稱”通過props數(shù)組/對象掛載到子組件的配置對象中(通過props對象的掛載方式詳見cn.vuejs.org/v2/api/#props抛蚤,其實v-bind指令配合props數(shù)組/對象也可以接收并掛載一個字面量數(shù)值,例如“:title=“‘專輯列表’”(//或者不使用v-bind指令寻狂,直接寫成title=“專輯列表”)”)岁经,最后第三步,在子組件的根標簽內(nèi)部使用插值語法{{}}訪問自定義接收名稱就可以了(當子組件配置對象的函數(shù)作用域中需要訪問props數(shù)組/對象中的值時蛇券,前面必須加上this)缀壤,例如“<son v-bind:parentname=“name”v-bind:parentage=“age”></son> ?son: {template: “#son”, props: [“parentname”, “parentage”]}(//parentname和parentage是自定義的接收名稱,當?shù)谝徊绞褂民劮迕麜r纠亚,第二步和第三步必須轉(zhuǎn)成短橫線分隔命名塘慕,name和age是其父組件配置對象中的值)”,當想要將父組件methods對象中的某個方法傳遞給其子組件時蒂胞,首先第一步图呢,在渲染<子組件>時通過v-on指令配合自定義接收名稱來接收傳遞過來的某個方法,然后第二步啤誊,在子組件的methods對象中再自定義一個方法岳瞭,并在此方法的函數(shù)作用域中寫上一句“this.$emit (“自定義接收名稱”, 123, 456, ...);(//后續(xù)的實參可以傳入其父組件所傳遞的方法中,使用形參接收一下就可以了蚊锹,非必須瞳筏,其實這種方式也可以實現(xiàn)將子組件配置對象中的某個值傳遞給其父組件)”,最后第三步牡昆,在子組件的根標簽內(nèi)部直接調(diào)用此自定義的方法就可以了姚炕,例如“<son @parentsay=“say”></son> ?son: {template: “#son”, methods: {sonFn () {this.$emit (“parentsay”);} } }(//parentsay是自定義接收名稱,允許使用短橫線分隔命名丢烘,不允許使用駝峰命名柱宦,sonFn是自定義的方法名稱)”,當想要將爺爺組件配置對象中的某個值/方法傳遞給其孫子組件時播瞳,只能一層一層逐級向下傳遞(非常麻煩)掸刊,由于在渲染某個<自定義組件>時,在其開始和結(jié)束標簽中所動態(tài)追加的任何內(nèi)容都不會被渲染赢乓,所以當其部分內(nèi)容是需要后期動態(tài)追加時忧侧,就必須使用插槽石窑,自定義組件根標簽內(nèi)部的<slot>就叫做插槽,插槽不能直接設置CSS樣式蚓炬,當想要設置CSS樣式時松逊,必須先將其嵌套在一個HTML標簽中,然后給此HTML標簽設置CSS樣式就可以了肯夏,插槽是可以設置默認數(shù)據(jù)的经宏,例如“<slot>我是默認數(shù)據(jù)</slot>”,沒有設置name屬性的<slot>就叫做匿名插槽驯击,后期所動態(tài)追加的任何內(nèi)容都會替換掉整個匿名插槽烁兰,有幾個匿名插槽,后期所動態(tài)追加的內(nèi)容就會復制多少份余耽,并將每一個匿名插槽都替換掉缚柏,但建議只寫一個匿名插槽,設置了name屬性的<slot>就叫做具名插槽碟贾,此具名插槽的name值就是它的名稱,此時必須給所動態(tài)追加的HTML標簽設置一個slot屬性轨域,當slot值跟哪個具名插槽的name值相同時袱耽,就會替換掉哪個具名插槽,在Vue2.6.0中干发,新增了v-slot指令朱巨,使用v-slot指令可以替代slot屬性(推薦),但v-slot指令只能用在<template>上枉长,所以將所動態(tài)追加的內(nèi)容嵌套在一對<template>內(nèi)就可以了冀续,例如“<template v-slot:one><div>我是追加的內(nèi)容1</div> ?<div>我是追加的內(nèi)容2</div></template>(//v-slot:可以用#代替)”,在后期動態(tài)追加內(nèi)容時必峰,當想要訪問此自定義組件配置對象中的某個值時洪唐,就需要將此自定義組件根標簽內(nèi)部的插槽轉(zhuǎn)成作用域插槽,接收了配置對象中某個值的插槽就叫做作用域插槽吼蚁,首先第一步凭需,在設置作用域插槽時通過v-bind指令配合自定義接收名稱來接收傳遞過來的某個值,然后第二步肝匆,通過<template>的slot-scope/v-slot/v-slot:default值來設置作用域插槽的作用域名稱(數(shù)據(jù)類型是對象類型,可以對其解構(gòu)賦值,當使用slot-scope時承绸,也可以使用普通的<div>來代替<template>充當根標簽蜕琴,v-slot等價于v-slot:default,適用于匿名作用域插槽能曾,v-slot:default中的default也可以換成具名作用域插槽的name值)度硝,最后第三步设捐,在所動態(tài)追加的內(nèi)容中直接通過“作用域名稱.自定義接收名稱”的形式訪問就可以了,例如“<template slot-scope=“prop”><div>我是填充的內(nèi)容-{{prop.myname}}</div></template> ?<slot v-bind:myname=“names”>我是默認內(nèi)容 {{names}}</slot>(//myname是自定義接收名稱塘淑,prop是作用域名稱萝招,當此作用域插槽是匿名插槽時,slot-scope/v-slot/v-slot:default也可以換成#default存捺,推薦槐沼,當此作用域插槽是具名插槽時,就將#default中的default換成具名插槽的name值捌治,需要注意一點的是岗钩,使用#時根標簽只能使用<template>,不能使用<div>肖油,或者我們干脆不使用#兼吓,直接給根標簽配置兩個鍵值對,例如“slot=“插槽的name值”slot-scope=“prop””)”森枪,當想要將一個組件配置對象中的某個值傳遞給其兄弟組件時视搏,首先第一步,讓其父組件將一個可以修改自己data對象中某個值的方法(需帶有形參)傳遞給此組件县袱,然后第二步浑娜,讓此組件調(diào)用所傳遞過來的方法并將自己配置對象中的某個值傳入,這樣一來式散,就成功的將此值保存到其父組件的data對象中了筋遭,最后第三步,讓其父組件再將此值傳遞給其兄弟組件就可以了(非常麻煩)暴拄,vuex.js是Vue.js配套的公共數(shù)據(jù)管理工具漓滔,我們可以將共享的數(shù)據(jù)保存到Vuex對象配置對象的state對象中,方便整個程序中的任何組件都可以訪問和修改state對象中所保存的公共數(shù)據(jù)乖篷,必須先引入Vue.js响驴,再引入vuex.js(基于Vue.js的插件),創(chuàng)建Vuex對象的格式為“const store = new Vuex.Store ({state: {msg: “知播漁”} });”那伐,然后將Vuex對象通過store屬性掛載到祖先組件的配置對象中(當屬性和取值相同時踏施,只寫一個就可以了),這樣一來罕邀,在此祖先組件和其所有后代組件的根標簽內(nèi)部就都可以訪問state對象中所保存的共享數(shù)據(jù)了畅形,格式為“{{this.$store.state.msg}}”,不推薦直接修改Vuex對象中的共享數(shù)據(jù)诉探,因為在多個組件都直接修改了共享數(shù)據(jù)的情況下日熬,當后期數(shù)據(jù)一旦發(fā)生錯誤時,調(diào)試錯誤就需要把每一個修改了共享數(shù)據(jù)的組件都檢查一遍肾胯,這樣非常低效竖席,非常的不利于維護耘纱,所以我們需要給Vuex對象的配置對象中添加一個mutations對象,專門用于保存修改共享數(shù)據(jù)的方法毕荐,例如“mutations: {mAdd (state, msg) {state.count = state.count + 1;} }(//參數(shù)1接收到的是state對象)”束析,在各組件配置對象的函數(shù)作用域中調(diào)用mAdd方法的格式為“this.$store.commit (“mAdd”, 123);(//123可以傳入mutations對象中mAdd方法的參數(shù)2,非必須)”憎亚,還可以借助mapMutations輔助函數(shù)將mutations對象中所定義的方法映射到各組件的methods對象中员寇,即將它映射為自己的方法,格式為“import {mapMutations} from ‘vuex’; ?methods: {...mapMutations ([‘mAdd’]) }”第美,這樣一來蝶锋,就可以直接通過this來調(diào)用了,格式為“this.mAdd (123);”什往,Vuex對象配置對象中的actions對象是專門用于保存觸發(fā)mutations對象中所定義方法的方法扳缕,例如“actions: {setAdd ({commit}, msg) {commit (“mAdd”, msg);} }(//形參msg所接收到的值會傳入mAdd方法的參數(shù)2)”,在各組件配置對象的函數(shù)作用域中調(diào)用setAdd方法的格式為“this.$store.dispatch (“setAdd”, 123);(//123可以傳入actions對象中的setAdd方法的參數(shù)2别威,非必須)”躯舔,還可以借助mapActions輔助函數(shù)將actions對象中所定義的方法映射到各組件的methods對象中,即將它映射為自己的方法兔港,格式為“import {mapActions} from ‘vuex’; ?methods: {...mapActions ([‘setAdd’]) }”庸毫,這樣一來,就可以直接通過this來調(diào)用了衫樊,格式為“this.setAdd (123);”,Vuex對象配置對象中的getters對象是專門用于定義計算屬性的利花,跟組件配置對象中的computed對象一樣科侈,在其中所定義的計算屬性在執(zhí)行時會將返回值緩存起來,只有返回值發(fā)生變化才會重新執(zhí)行炒事,在執(zhí)行getters對象中所定義的計算屬性時臀栈,參數(shù)1接收到的是state對象,調(diào)用計算屬性的格式為“{{this.$store.getters.formart}}(//調(diào)用的時候后面一定不能添加小括號挠乳,否則會報錯)”权薯,還可以借助mapGetters輔助函數(shù)將getters對象中的計算屬性映射到各組件的computed對象中,即將它映射為自己的計算屬性睡扬,格式為“import {mapGetters} from ‘vuex’; ?computed: {...mapGetters ([‘formart’]) }”盟蚣,這樣一來,就可以直接通過this來調(diào)用了卖怜,格式為“{{this.formart}}”屎开,Vue-Router(路由)跟v-if/v-show指令一樣,是用來切換不同組件的顯示/隱藏的马靠,但v-if/v-show是用標記(true/false)來實現(xiàn)切換奄抽,并且所切換的組件必須經(jīng)過注冊蔼两,而Vue-Router是用哈希(#/某一個組件的id值)來實現(xiàn)切換,并且所切換的組件可以不用經(jīng)過注冊逞度,還能夠在切換的時候給所匹配的組件傳值(各種鍵值對)额划,必須先引入Vue.js,再引入Vue-Router.js(基于Vue.js的插件)档泽,首先第一步俊戳,定義路由規(guī)則列表(路由配置),格式為“const routes = [{path: “/組件1的<template>id值”, component: 組件1的配置對象}, {path: “/組件2的<template>id值”, component: 組件2的配置對象}, ...];(//數(shù)組中的每一個對象就是一條規(guī)則茁瘦,其實path值可以任意擬定品抽,但建議用<template>的id值,比較好辨認)”甜熔,然后第二步圆恤,根據(jù)所定義的路由規(guī)則列表routes創(chuàng)建路由對象,例如“const router = new VueRouter ({routes: routes});(//將路由規(guī)則列表routes通過routes屬性掛載到路由對象router的配置對象中腔稀,在配置對象中還可以添加一個mode屬性盆昙,取值可以是“hash”,默認值焊虏,使用URL的哈希來模擬一個完整的URL淡喜,當URL改變時,頁面不會重新加載诵闭,取值可以是“history”炼团,在URL中取消了#號,充分利用了history.pushState()來完成URL的跳轉(zhuǎn)疏尿,而無須重新加載頁面)”瘟芝,另外,路由對象router調(diào)用它的push方法(實例方法)可以修改當前的路由地址(即URL的哈希值)褥琐,格式為“router.push ({path: “/one”});”锌俱,然后第三步,將路由對象router通過router屬性掛載到任意一個組件的配置對象中敌呈,格式為“router: router”贸宏,最后第四步,當路由地址被修改成path值時磕洪,再通過此被掛載組件的根標簽內(nèi)部的<router-view>(即路由出口)來渲染所匹配的組件吭练,我們可以通過<a>修改當前URL的哈希值即路由地址(不專業(yè)),在Vue-Router.js中提供了一個<router-link>褐鸥,它是專門用于修改路由地址的线脚,例如“<router-link to=“/one”tag=“button”>切換到第一個界面</router-link>(//<router-link>只有被點擊時才會生效,通過to值來設置路由地址,不用寫#浑侥,<router-link>默認會被渲染成<a>姊舵,但是可以通過它的tag值來將其渲染成指定的標簽)”,在路由地址被修改成功時寓落,當想要將此路由地址所對應的<router-link>修改成指定的CSS樣式時括丁,第一種方法是給它的router-link-active類名設置指定的CSS樣式就可以了,也就是說系統(tǒng)會自動給此路由地址所對應的<router-link>添加一個router-link-active類名伶选,當路由地址被再次修改時史飞,就會自動去掉,并將router-link-active類名添加給別的<router-link>仰税,第二種方法是將一個自定義類名通過linkActiveClass屬性掛載到路由對象router的配置對象中构资,例如“l(fā)inkActiveClass: “nj-active””,再給此自定義類名nj-active設置指定的CSS樣式就可以了陨簇,其實當<router-link>被點擊時吐绵,就相當于利用路由對象router調(diào)用了它的push方法,所以說點擊<router-link>和“router.push ({path: “/one”});(//在路由規(guī)則列表routes中所包含組件的配置對象中河绽,等同于“this.$router.push ({path: “/one”});(//this.$router返回的就是路由對象router)”)”所起的作用是等同的己单,當想要設置此頁面默認的路由地址時,可以重定向此路由耙饰,也就是給所定義的路由規(guī)則列表routes中添加一條規(guī)則就可以了纹笼,例如“{path: “/”, redirect: “/two”}(//path值是被重定向的值,redirect值是重定向之后的值)”苟跪,當點擊<router-link>修改當前的路由地址時廷痘,有兩種給所匹配的組件傳值(各種鍵值對)的方法,第一種方法是件已,當想要給所匹配的組件傳值時牍疏,在待修改的路由地址后面附加各種鍵值對的字符串,例如“<router-link to=“/one?name=lnj&age=33”>切換到第一個界面</router-link>”拨齐,當所匹配的組件想要訪問所傳過來的值時,在所匹配組件的配置對象中可以通過“this.$route;”的方式先返回當前路由信息對象route昨寞,只要能獲取到當前路由信息對象route瞻惋,就可以通過當前路由信息對象route獲取到所傳的值,比如我們可以先在所切換到組件的配置對象中添加一個created方法(一種生命周期方法)援岩,然后直接從created方法中訪問就可以了歼狼,格式為“created: function () {console.log (this.$route); ?console.log (this.$route.query.name); ?console.log (this.$route.query.age);}”,第二種方法是享怀,當想要給所匹配的組件傳值時羽峰,鍵和值分開設置,首先在定義路由規(guī)則列表routes時,在path值中設置“鍵”梅屉,然后在待修改的路由地址中設置“值”值纱,例如“<router-link to=“/one/zs/66”>切換到第一個界面</router-link> ?{path: “/one/:name/:age”, component: one}”,當所匹配的組件想要訪問所傳過來的值時坯汤,格式為“created: function () {console.log (this.$route); ?console.log (this.$route.params.name); ?console.log (this.$route.params.age);}”虐唠,在一級路由的某個組件中所嵌套的子路由就叫做嵌套/二級路由,第一步將二級路由的路由規(guī)則列表routes通過children數(shù)組掛載到一級路由某個組件的那條路由規(guī)則中惰聂,例如“{path: “/one”, component: one, children: [{path: “onesub1”, component: onesub1}, {path: “onesub2”, component: onesub2}] }(//二級路由的路由規(guī)則列表routes中的path值既不用寫完整的路徑疆偿,也不用寫“/”,因為“/”代表從當前URL的根部開始搓幌,但通過<router-link>的to值所修改的路由地址必須寫完整的路徑)”杆故,第二步在此被掛載的一級路由組件根標簽中通過<router-link>和<router-view>正常切換和渲染就可以了,例如“<template id=“one”><div class=“onepage”><p>我是第一個界面</p> ?<router-link to=“/one/onesub1”tag=“button”>切換到第一個界面的子界面1</router-link> ?<router-link to=“/one/onesub2”tag=“button”>切換到第一個界面的子界面2</router-link> ?<router-view></router-view></div></template>”溉愁,無論是一級路由還是二級路由处铛,總之記住一句話,掛載到哪個組件的配置對象/路由規(guī)則列表中叉钥,就在哪個組件的根標簽中<router-view>罢缸,在添加了多個匿名的路由出口<router-view>時,一旦路由地址跟path值相匹配投队,所有的路由出口<router-view>中所顯示的內(nèi)容都是一樣的枫疆,當想要讓不同的路由出口<router-view>顯示不同的內(nèi)容時,就需要給不同的路由出口<router-view>分別設置一個不同的name值敷鸦,被設置了name值的路由出口<router-view>就叫做命名視圖息楔,例如“<router-view name=“name1”></router-view> ?<router-view name=“name2”></router-view> ?{path: “/”, components: {name1: one, name2: two} }(//在路由規(guī)則列表routes中,將component屬性變成components對象扒披,結(jié)尾多了一個s值依,然后在此components對象中自定義不同的屬性,取值分別是不同子組件的配置對象碟案,然后給不同的路由出口<router-view>分別設置name值為不同的自定義屬性名稱就可以了)”愿险,在組件的配置對象中可以添加一個watch對象,在其中可以定義一些監(jiān)聽數(shù)據(jù)變化的方法价说,方法名稱跟data/props/computed對象/數(shù)組中的屬性/計算屬性名稱是對應的關系辆亏,當data/props/computed對象/數(shù)組中的某個屬性/計算屬性的取值/返回值發(fā)生變化時,就自動執(zhí)行watch對象中的同名方法鳖目,除此之外還可以定義監(jiān)聽路由地址變化的“$route.path”方法扮叨,格式為“watch: {“$route.path”: function (newValue, oldValue) {console.log (newValue, oldValue);} }(//參數(shù)1和2分別接收到的是變化之后和之前的路由地址字符串,“$route.path”方法經(jīng)常用于判斷當前界面是從哪個界面跳轉(zhuǎn)過來的)”领迈,跟webpack的生命周期方法一樣彻磁,在Vue/VueComponent實例對象的創(chuàng)建碍沐、運行、和銷毀階段所自動執(zhí)行的方法就叫做Vue的生命周期方法/鉤子/函數(shù)/事件衷蜓,創(chuàng)建階段會自動執(zhí)行beforeCreate累提、created、beforeMount恍箭、和mounted方法刻恭,當Vue/VueComponent實例對象剛剛被創(chuàng)建出來但data和methods等對象還沒有初始化時,會自動執(zhí)行beforeCreate方法扯夭,例如“beforeCreate: function () {console.log (this.msg);(//undefined) ?console.log (this.say);(//undefined)}, data: {msg: “知播漁”}, methods: {say () {console.log (“say”);} }”鳍贾,當data和methods等對象已經(jīng)初始化完成但還沒有向根標簽中傳值時,會自動執(zhí)行created方法交洗,當已經(jīng)向根標簽中傳完值但還沒有將舊的根標簽替換掉時骑科,會自動執(zhí)行beforeMount方法(beforeMount就是掛載之前的意思,此時Vue實例還是虛擬的DOM節(jié)點构拳,還沒有掛載到真實的DOM節(jié)點)咆爽,當已經(jīng)將舊的根標簽替換掉時,會自動執(zhí)行mounted方法(mounted就是掛載完畢的意思置森,此時Vue實例已經(jīng)掛載到真實的DOM節(jié)點上了斗埂,可以獲取到DOM元素了),運行階段會自動執(zhí)行beforeUpdate和updated方法凫海,當配置對象中的值被修改了但界面還沒有更新時呛凶,會自動執(zhí)行beforeUpdate方法,當配置對象中的值被修改了并且界面也發(fā)生更新時行贪,會自動執(zhí)行updated方法漾稀,銷毀階段會自動執(zhí)行beforeDestroy和destroyed方法,當組件即將被銷毀時建瘫,會自動執(zhí)行beforeDestroy方法崭捍,只要組件不被銷毀,beforeDestroy方法就不會自動執(zhí)行啰脚,并且通過beforeDestroy方法我們可以最后訪問/調(diào)用到data/methods對象中的屬性/方法殷蛇,當組件已經(jīng)被銷毀時,會自動執(zhí)行destroyed方法橄浓,只要組件不被銷毀晾咪,destroyed方法就不會自動執(zhí)行,無論通過destroyed方法可不可以訪問/調(diào)用到data/methods對象中的屬性/方法贮配,都不要在此方法中再去這樣操作了,一個完整的父子組件生命周期的執(zhí)行順序是塞赂,父組件的初始化(即父beforeCreate->父created->父beforeMount)->父render->子組件的初始化(即子beforeCreate->子created->子beforeMount)->子render->子mounted->父mounted->父beforeUpdate->子beforeUpdate->子updated->父updated->父beforeDestroy->子beforeDestroy->子destroyed->父destroyed泪勒,由于Vue.js的特點是無需操作DOM元素,直接使用數(shù)據(jù)來驅(qū)動界面更新,當使用原生JS的語法來獲取DOM元素時圆存,無論是系統(tǒng)自帶的HTML標簽還是<自定義組件>叼旋,我們只能獲取到其所對應的DOM元素,無法獲取到<自定義組件>的VueComponent實例對象沦辙,也就是說Vue.js官方不推薦我們使用原生JS的語法來獲取DOM元素夫植,所以我們可以通過添加ref屬性來獲取系統(tǒng)自帶的HTML標簽/<自定義組件>所對應的DOM元素/VueComponent實例對象,在此界面渲染完畢時油讯,當ref屬性添加給系統(tǒng)自帶的HTML標簽時(比如<p ref=“myppp”>我是原生的DOM</p>)详民,在其所屬組件的配置對象中可以獲取(返回)其所對應的DOM元素陌兑,格式為“console.log (this.$refs.myppp);(//當此HTML標簽使用了v-for指令時沈跨,返回值是所有DOM元素所組成的數(shù)組)”,當ref屬性添加給<自定義組件>時(比如<one ref=“myOne”></one>)兔综,在其父組件的配置對象中可以獲榷隽荨(返回)其所對應的VueComponent實例對象,格式為“console.log (this.$refs.myOne); ?console.log (this.$refs.myOne.msg); ?this.$refs.myOne.say ();(//msg和say分別是其data和methods對象中的屬性和方法软驰,當想要通過this.$refs.myOne的形式來獲取其根標簽所對應的DOM元素時涧窒,格式為“console.log (this.$refs.myOne.$el);”)”,無論ref屬性添加給系統(tǒng)自帶的HTML標簽還是<自定義組件>锭亏,給同一個界面的不同標簽所添加的ref值一定不要出現(xiàn)雷同纠吴,否則所獲取到的只是此界面上的最后一個DOM元素/VueComponent實例對象,Vue.js渲染自定義組件有兩種方式贰镣,第一種方式被渲染的自定義組件必須經(jīng)過全局/局部注冊呜象,即在父組件的根標簽中,把所注冊的自定義組件當做自定義HTML標簽來使用碑隆,但不會將父組件的根標簽整體覆蓋掉恭陡,第二種方式被渲染的自定義組件可以不用經(jīng)過全局/局部注冊,使用其父組件配置對象中的render方法來渲染就可以了上煤,當我們使用render方法并且配置對象中存在el/template字段時休玩,則el/template字段所指定的DOM元素就會被覆蓋掉,例如“render: function (createElement) {return createElement (“one”);}(//render值也可以換成“c => c (“one”)”劫狠,推薦拴疤,“one”是一個組件的名稱,當我們不想全局/局部注冊此組件時独泞,也可以將“one”換成此組件的配置對象呐矾,推薦)”,“render() {return (<div><h1>父親</h1> ?<Child></div>);}(//這種JSX寫法也是可以的懦砂,此時<Child>必須經(jīng)過全局/局部注冊)”蜒犯,給Vue類對象的prototype對象動態(tài)的添加方法(也可以看做是實例方法)的格式為“Vue.prototype.$abc = function () {alert (123);};(//$abc是方法的名稱组橄,在任意一個自定義組件配置對象的函數(shù)作用域中都可以通過“this.方法名稱 ();”的形式來調(diào)用)”,Vue/VueComponent實例對象調(diào)用它的$nextTick方法可以在此界面渲染完畢時執(zhí)行所傳入的回調(diào)函數(shù)罚随,例如“this.$nextTick (function () {});”
三玉工、Vue-CLI
Vue-CLI(Command Line Interface)是Vue.js官方提供的命令行腳手架工具,此工具已經(jīng)幫我們搭建好了一套利用webpack管理的vue項目結(jié)構(gòu)淘菩,全局安裝Vue-CLI的流程是首先下載并安裝NodeJS遵班,網(wǎng)址是nodejs.org/zh-cn,NodeJS不是一個.js文件潮改,而是JS的一種運行環(huán)境狭郑,即用Google V8引擎封裝成的一個web服務器端的JS解釋器,可以運行特定編程語言所編寫的應用程序的平臺就叫做運行環(huán)境进陡,Windows愿阐、Linux、MacOS趾疚、iOS缨历、Android這些都是運行環(huán)境,比如可以在Windows/Linux運行環(huán)境中運行通過C/C++所開發(fā)的應用程序糙麦,可以在MacOS/iOS運行環(huán)境中運行通過Object-C/Swift所開發(fā)的應用程序辛孵,安裝了NodeJS之后,JS的運行就可以不用依賴web瀏覽器了赡磅,而NodeJS中包含npm(NodeJS Package Manager)魄缚,即NodeJS的包管理工具,是專門用來管理遠程代碼倉庫中的js文件的焚廊,每個js文件都有自己的唯一標識冶匹,當用戶想要使用某個js文件時,只需引用對應的標識(命令)咆瘟,npm就會將其下載下來嚼隘,安裝完NodeJS之后,可以輸入命令“node -v”敲回車來查看已安裝的NodeJS的版本號袒餐,可以輸入命令“npm -v”敲回車來查看其所包含的npm的版本號飞蛹,由于npm下載插件是從國外服務器下載敷待,受網(wǎng)絡影響比較大席镀,可能出現(xiàn)網(wǎng)絡異常,所以淘寶團隊就做了一個完整的npmjs.org鏡像忱辅,叫做cnpm焰宣,同步頻率目前為十分鐘一次霉囚,以保證盡量與官方服務同步,我們可以用cnpm來代替npm匕积,我們可以在node的16.13.0版本下輸入命令“npm install -g cnpm --registry=https://registry.npm.taobao.org(//或者將cnpm換成cnpm@7.1.0來指定具體版本)”敲回車來全局安裝一個cnpm佛嬉,然后輸入命令“npm i -g @vue/cli(//把i改成uninstall就代表卸載)”敲回車來全局安裝Vue-CLI逻澳,耐心等待一會,比較耗時暖呕,安裝完成后,可以輸入命令“vue -V”/“vue --version”敲回車來查看所全局安裝的Vue-CLI的版本號(另外苞氮,可以輸入命令“npm list -g --depth 0(//--depth 0是用來限制層數(shù)的湾揽,否則會將模塊依賴的模塊也一并輸出出來)”敲回車來查看都通過npm全局安裝了什么插件,還可以輸入命令“npm list 插件名字 -g”敲回車來查看某個全局安裝插件的具體信息)笼吟,然后輸入命令“npm config get prefix”敲回車來查看npm配置文件的路徑库物,比如路徑是“C:\Users\劉遠舟\AppData\Roaming\npm”,將其復制贷帮,然后右擊“此電腦”戚揭,點擊屬性->高級系統(tǒng)設置->高級->環(huán)境變量->系統(tǒng)變量,雙擊“Path”撵枢,點擊“新建”民晒,然后將所復制的路徑粘貼上,點擊確定即可锄禽,然后打開Windows Powershell(管理員)潜必,輸入命令“set-ExecutionPolicy RemoteSigned”敲回車,再輸入y敲回車即可沃但,然后打開vscode磁滚,點擊終端->新終端->當前目標文件夾,輸入命令“vue create 項目文件夾名稱”敲回車來創(chuàng)建vue項目宵晚,這時會問你“您到默認npm注冊表的連接似乎很慢垂攘,是否使用https://registry.npm.taobao.org更快的安裝?”,輸入y敲回車即可淤刃,然后會彈出幾個選項晒他,“Manually select features”代表手動配置,其余選項代表默認配置钝凶,比如我們選擇了手動配置仪芒,會彈出一個選項列表,其中“Babel”和“Linter/Formatter”是系統(tǒng)默認選中的耕陷,還需要配置哪一項就按上下箭頭鍵調(diào)整光標位置掂名,然后按空格鍵就可以將其選中了,比方說我們又選擇了Router哟沫、Vuex饺蔑、和CSS Pre-processors,選好了之后敲一下回車就進入到了下一步嗜诀,然后會問你“路由器是否使用歷史記錄模式猾警?”孔祸,輸入y敲回車,然后會讓你選擇一種CSS預處理器发皿,Sass/SCSS(with dart-sass)和Sass/SCSS(with node-sass)就是性能上的差異崔慧,前者會快一些,選擇前者就可以了穴墅,然后會問你選擇“Linter/Formatter”的哪種規(guī)范惶室,選項分別是“ESLint + Airbnb config”、“ESLint + Standard config”玄货、和“ESLint + Prettier”皇钞,選擇“ESLint + Standard config(//標準的規(guī)范)”就可以了,然后會讓你“挑選lint的額外功能”松捉,第一個選項是“Lint on save”夹界,第二個選項是“Lint and fix on commit(requires Git)”,兩個都選中就可以了隘世,然后敲一下回車進入下一步可柿,它會問你“以上這些配置信息是分別放到專用的配置文件中還是直接放到package.json中?”以舒,為了方便后續(xù)管理趾痘,選擇前者就可以了,最后它會問你“為了將來更方便的創(chuàng)建項目蔓钟,是否將以上我們所選擇的配置保存為默認永票?”,可以輸入n滥沫,敲一下回車侣集,然后就可以根據(jù)我們前面所選擇的配置使用Vue-CLI去創(chuàng)建vue項目結(jié)構(gòu)了,耐心等待一會兰绣,比較耗時世分,當出現(xiàn)了“Successfully created project...”時,就代表已經(jīng)創(chuàng)建好了缀辩,這時在我們的目標文件夾中就可以看到我們所創(chuàng)建的vue項目文件夾了臭埋,雙擊打開它,會看到很多文件夾臀玄,node_modules文件夾中存儲的是此vue項目所依賴的各種庫(插件)瓢阴,public文件夾中存儲的是當前的網(wǎng)頁(index.html)及網(wǎng)頁的圖標,還可以放置永遠不會改變的靜態(tài)的資源/webpack所不支持的第三方庫健无,當以后npm run build時荣恐,會將它們直接復制到dist文件夾中,而不會經(jīng)過webpack的處理,我們需要通過絕對路徑來引用它們叠穆,src文件夾中存儲的是此項目的源碼少漆,assets子文件夾用來存儲經(jīng)過webpack處理的靜態(tài)資源(圖片/字體圖標等),比如會對它進行壓縮等硼被,components子文件夾用來存儲一些自定義的小/公共vue組件(xxx.vue)示损,views子文件夾用來存儲一些自定義的大/頁面級/路由級vue組件(xxx.vue),router子文件夾用來存儲路由相關的代碼文件嚷硫,首先創(chuàng)建一個index.js文件屎媳,然后在此文件的開頭寫上例如“import Vue from ‘vue’; ?import Router from ‘vue-router’; ?import One from ‘../components/One.vue’;(//常量One是One.vue組件的配置對象,此種加載方式屬于完整加載论巍,即在訪問網(wǎng)頁時,無論此vue組件有沒有被用到风响,都會被加載進來嘉汰,所以性能不是很好,容易引發(fā)白屏問題状勤,當想要按需加載(懶加載)時鞋怀,格式為“const One = resolve => {import (‘../views/One’).then (module => {resolve (module);} );};”) ?import Two from ‘../components/Two.vue’; ?Vue.use (Router);”,中間跟過去的書寫格式一樣持搜,當路由對象router的配置對象中mode值是“history”時密似,npm run build之后初次運行沒有問題,但是網(wǎng)頁不能刷新葫盼,一旦刷新頁面上就會報一個404的錯誤残腌,除非在web服務器上面進行一些額外的配置(詳見Vue Router官方文檔->HTML5 History 模式->后端配置例子),結(jié)尾寫上“export default router;(//常量router是所創(chuàng)建的路由對象贫导,意思是export此路由對象router抛猫,也就是將此路由對象router暴露出去)”,store子文件夾用來存儲Vuex相關的代碼文件孩灯,首先創(chuàng)建一個index.js文件闺金,然后在此文件的開頭寫上“import Vue from ‘vue’; ?import Vuex from ‘vuex’; ?Vue.use (Vuex);”,中間跟過去的書寫格式一樣峰档,結(jié)尾寫上“export default store;(//常量store是所創(chuàng)建的Vuex對象败匹,意思是export此Vuex對象store,也就是將此Vuex對象store暴露出去)”讥巡,或者寫完開頭之后直接寫上“export default new Vuex.Store ({配置對象});”即可掀亩,當index.js上的代碼過于多時,非常不利于維護尚卫,所以我們可以化整為零归榕,根據(jù)單一原則將配置對象中的每一項內(nèi)容都寫到一個單獨的js文件上,可以在store文件夾下再新建一些比如state.js吱涉、mutations.js刹泄、actions.js外里、和getters.js等,在這些文件內(nèi)的書寫格式為“export default {key: value, ...};”特石,然后再分別import到index.js中并賦值給配置對象里的state盅蝗、mutations、actions姆蘸、和getters等屬性就可以了墩莫,由于我們需要在actions.js中所定義方法的函數(shù)作用域中觸發(fā)mutations.js中所定義的方法,而且在觸發(fā)時需要填入方法名稱的字符串逞敷,由于字符串的特點是寫錯不會提示狂秦,非常不利于我們?nèi)ゾS護,所以我們一般將mutations.js中的方法名稱const成一個常量(當想要使用常量的名稱來充當方法的名稱時推捐,必須加上中括號裂问,否則是會報錯的,會說你只定義未使用牛柒,但是在“this.$store.commit (‘xxx’);”/借助mapMutations輔助函數(shù)做映射的時候堪簿,正常寫就可以,不用加中括號)皮壁,可以在store文件夾下再新建一個mutations-type.js文件椭更,在此文件中書寫的格式為“export const SET_FULL_SCREEN = ‘SET_FULL_SCREEN’;”,然后再分別import到mutations.js和actions.js中并使用就可以了蛾魄,格式為“import {SET_FULL_SCREEN} from ‘./mutations-type’;”虑瀑,App.vue是render在根實例組件的根標簽內(nèi)部的一個vue組件,書寫格式為“export default {name: ‘App’};(//大括號中為配置對象畏腕,意思是export此配置對象缴川,也就是將此配置對象暴露出去)”,其根標簽的id值必須與根實例組件根標簽的id值相同描馅,這樣一來把夸,通過render方法將根實例組件的根標簽整體覆蓋掉之后,自己就成為真正的根組件了铭污,給vue文件中的<style>添加一個scoped屬性恋日,不用設置取值,可以使此CSS樣式代碼只適用于當前的這個vue文件(即局部樣式)嘹狞,添加一個“l(fā)ang=“scss””可以在這對<style>中書寫sass代碼岂膳,main.js是整個項目的JS入口,我們首先在main.js中import“Vue類對象”磅网、“App.vue的配置對象”谈截、“Vuex對象store”、和“路由對象router”,格式為“import Vue from ‘vue’;(//常量Vue是Vue這個類對象) ?import App from ‘./App.vue’;(//常量App是App.vue的配置對象) ?import store from ‘./store/index.js’; ?import router from ‘./router/index.js’;”簸喂,然后創(chuàng)建Vue實例對象(即根實例組件)毙死,然后將store和router通過store和router屬性掛載到其配置對象中,并render“App.vue”喻鳄,即“render: c => c(App)”扼倘,當new出來一個實例對象卻并沒有使用它時,根據(jù)eslint的標準規(guī)范會報錯除呵,只需要在根實例組件上方添加一句“/*eslint-disable no-new*/”就可以了再菊,當Vue-CLI的版本是1.x/2.x時,還會生成build和config文件夾颜曾,這兩個文件夾中存儲了webpack相關的配置纠拔,我們可以針對項目需求修改webpack配置,當Vue-CLI的版本是3.0及3.0以后時泛豪,就不會生成build和config文件夾绿语,Vue.js官方這么做的目的是為了化繁為簡,讓初學者不用關心webpack候址,因為Vue-CLI已經(jīng)幫你配置好了,并把webpack的配置文件隱藏起來了种柑,所以只需要關心如何使用Vue.js就可以了岗仑,但是有時候默認的配置可能無法滿足我們的需求,這時我們可以在項目的根目錄下新建一個“vue.config.js”文件來修改webpack配置聚请,Vue-CLI為了方便起見對webpack原生的屬性進行了一層封裝荠雕,可以查詢網(wǎng)址“cli.vuejs.org/zh/config”來查看封裝之后的屬性是否能夠滿足我們的需求,當封裝之后的屬性可以滿足我們的需求時驶赏,就使用封裝之后的屬性來修改webpack的配置炸卑,比如我們想要修改npm run build之后的目錄名稱,使之從dist變?yōu)閎undle煤傍,我們可以在vue.config.js的配置對象中添加一句“outputDir: ‘bundle’”盖文,當封裝之后的屬性不可以滿足我們的需求時,就在vue.config.js的配置對象中添加一個configureWebpack對象蚯姆,并在其中編寫原生的webpack配置就可以了五续,比如我們想要添加一個展示版權(quán)的插件(內(nèi)置插件,即在打包之后的文件中添加一句注釋龄恋,告訴外界此代碼是誰寫的疙驾,參考網(wǎng)址是www.webpackjs.com/plugins/banner-plugin),我們可以首先在vue.config.js中導入webpack郭毕,格式為“const webpack = require (‘webpack’);”它碎,然后在configureWebpack對象中添加一個plugins數(shù)組,在plugins數(shù)組中寫上比如“new webpack.BannerPlugin ({banner: ‘知播漁教育-www.it666.com’})”就可以了,當我們的編輯器是vscode時扳肛,首先進入vscode的應用商店傻挂,給我們的編輯器安裝一個eslint插件,然后進入vscode的終端敞峭,必須在此vue項目的根目錄下踊谋,輸入命令“npm i eslint --save-dev(//--save-dev可以用-D代替,代表此插件是在開發(fā)環(huán)境中所要用到的旋讹,而--save可以用-S代替殖蚕,代表此插件是在生產(chǎn)環(huán)境中所要用到的,在package.json的devDependencies對象中所顯示的依賴包是只會在開發(fā)環(huán)境下依賴的模塊沉迹,生產(chǎn)環(huán)境不會被打入包內(nèi)睦疫,而dependencies對象中所顯示的依賴包不僅開發(fā)環(huán)境能使用,生產(chǎn)環(huán)境也能使用鞭呕,當想要安裝特定的版本時蛤育,格式為“npm i eslint@8.16.0 --save-dev”)”敲回車來給我們的vue項目局部安裝一個eslint插件(另外,在我們vue項目的根目錄下可以輸入命令“npm list --depth 0”敲回車來查看都給此vue項目局部安裝了什么插件葫松,還可以輸入命令“npm list 插件名字”敲回車來查看所局部安裝的某個插件的具體信息)瓦糕,切記一定不能全局安裝eslint插件,因為此vue項目中包含很多跟eslint相關的插件腋么,比如eslint-plugin-html咕娄、eslint-plugin-vue、和.eslintrc.js等等珊擂,并且全都是局部安裝的圣勒,必須保持統(tǒng)一才能好使,并且一旦全局安裝摧扇,就將eslint插件安裝到了其它路徑了圣贸,然后我們進入vscode的settings.json,在里面加上一句““eslint.autoFixOnSave”: true”扛稽,這樣一來吁峻,在書寫項目源代碼時,當出現(xiàn)了不符合規(guī)范的格式時在张,一保存就自動修復了锡搜,當我們的編輯器是webstorm時,進入文件->設置瞧掺,在左上角搜索eslint耕餐,找到之后點擊一下,然后在右側(cè)點擊“Manual ESLint configuration”辟狈,然后看這一項“ESLint package”的路徑是否是“我們vue項目文件夾\node_modules\eslint”肠缔,是的話就不用管它夏跷,然后點擊確定即可,這時在編寫代碼的區(qū)域點擊鼠標右鍵明未,就會看到有一項叫做“Fix ESLint Problems”槽华,只要一點它,就自動修復了趟妥,當想要讓此vue項目在運存中打包運行時猫态,在我們項目的根目錄下輸入命令“npm run serve(//這里的serve指的就是使用webpack-dev-server(一個小型的NodeJS Express服務器)來打包運行)”敲回車(另外,可以使用命令“cd 項目文件夾名稱(//cd是change directory的簡寫披摄,改變目錄)”將路徑改成我們項目的根目錄亲雪,另外,“cd ..”代表返回上一級目錄疚膊,另外义辕,按Ctrl+C并輸入y敲回車代表取消/終止當前的操作,另外寓盗,cls代表清除屏幕上的所有顯示灌砖,光標置于屏幕左上角,即CLear Screen)傀蚌,然后等待一會基显,出現(xiàn)了Local和Network網(wǎng)址就代表已經(jīng)打包好了,我們可以點擊一下local網(wǎng)址善炫,就可以運行此打包好的vue項目了(在同一WiFi下的手機web瀏覽器同樣可以訪問此網(wǎng)址)续镇,由于是打包到了運存中,所以在我們的項目中就找不到dist文件夾销部,當想要讓此vue項目在硬盤中打包運行時,首先需要在項目的根目錄下新建一個vue.config.js文件制跟,然后在里面寫上“module.exports = {publicPath: ‘./’(//部署應用包的基本URL舅桩,不設置可能會出現(xiàn)打包后項目找不到資源的問題)};”,然后在我們項目的根目錄下輸入命令“npm run build(//這里的build指的就是使用webpack-dev-build來打包運行)”敲回車雨膨,然后等待一會擂涛,出現(xiàn)了DONE和INFO就代表已經(jīng)打包好了,這時在我們的項目文件夾中就可以看到dist文件夾了聊记,里面所有的文件都已經(jīng)壓縮過并進行了代碼分割撒妈,ElementUI是餓了么前端團隊推出的一款基于Vue.js的PC端UI框架,跟bootstrap一樣排监,對原生的HTML標簽進行了封裝和美化狰右,使用ElementUI可以讓我們能夠?qū)W⒂跇I(yè)務邏輯而不是UI界面,官網(wǎng)是element.eleme.cn/#/zh-CN舆床,進入官網(wǎng)棋蚌,點“組件”嫁佳,然后就看到安裝方法了,首先在我們vue項目的根目錄下輸入命令“npm i element-ui -S”敲回車來局部安裝ElementUI谷暮,當想要完整import時蒿往,需要在main.js文件中寫上“import ElementUI from ‘element-ui’; ?import ‘element-ui/lib/theme-chalk/index.css’; ?Vue.use (ElementUI);”,然后就可以在官方文檔中查看具體使用方法了湿弦,完整import的弊端是瓤漏,無論我們有沒有使用到某個組件,在npm run build時都會將elementUI中所有的組件都打包到dist文件夾中颊埃,這樣就導致了dist文件夾的體積比較大蔬充,用戶訪問比較慢,為了解決這個問題竟秫,elementUI推出了按需import娃惯,使用什么組件就import什么組件就可以了,這樣一來肥败,在npm run build時只會將我們所import的組件打包到dist文件夾中趾浅,沒有import的組件則不會被打包,這樣dist文件夾的體積就減小很多了馒稍,當想要按需import時皿哨,首先需要在我們vue項目的根目錄下輸入命令“npm install babel-plugin-component -D”敲回車來局部安裝babel-plugin-component插件,然后通過vscode編輯器打開我們vue項目根目錄下的babel.config.js文件纽谒,將配置對象中的presets數(shù)組改成二維數(shù)組证膨,然后在其內(nèi)部的一維數(shù)組中再添加上一個{‘modules’: false}元素,然后在配置對象中再添加一個plugins數(shù)組(詳見ElementUI官網(wǎng)->組件->快速上手)鼓黔,然后在main.js文件中寫上例如“import {Row, Slider, Button} from ‘element-ui’; ?Vue.use (Row); ?Vue.use (Slider); ?Vue.use (Button);”央勒,另外,在main.js中可以加上一句“Vue.config.productionTip = false;(//阻止顯示生產(chǎn)模式的消息)”澳化,這樣一來崔步,在控制臺就不會顯示“You are running Vue in development mode.Make sure to turn on production mode when deploying for production.”了,MintUI是餓了么前端團隊推出的一款基于Vue.js的移動端UI框架缎谷,跟bootstrap一樣井濒,對原生的HTML標簽進行了封裝和美化,使用MintUI可以讓我們能夠?qū)W⒂跇I(yè)務邏輯而不是UI界面列林,官網(wǎng)是mint-ui.github.io/#!/zh-cn瑞你,進入官網(wǎng),點擊“開始使用”->中文(Vue2.0版)希痴,然后就看到安裝方法了者甲,首先在我們vue項目的根目錄下輸入命令“npm i mint-ui -S”敲回車來局部安裝MintUI,當想要完整import時砌创,需要在main.js文件中寫上“import MintUI from ‘mint-ui’; ?import ‘mint-ui/lib/style.css’; ?Vue.use (MintUI);”过牙,當想要按需import時甥厦,首先需要在我們vue項目的根目錄下輸入命令“npm install babel-plugin-component -D”敲回車來局部安裝babel-plugin-component插件,然后通過vscode編輯器打開我們項目根目錄下的babel.config.js文件寇钉,將配置對象中的presets數(shù)組改成二維數(shù)組刀疙,然后在其內(nèi)部的一維數(shù)組中再添加上一個{‘modules’: false}元素,然后在配置對象中再添加一個plugins數(shù)組扫倡,詳見MintUI官網(wǎng)->開始使用->中文(Vue2.0版)->Quickstart谦秧,但是要將plugins數(shù)組去掉一層,從三維數(shù)組變成二維數(shù)組撵溃,然后在main.js文件中寫上例如“import {Button, Switch} from ‘mint-ui’; ?import ‘mint-ui/lib/style.css’; ?Vue.component (Button.name, Button); ?Vue.component (Switch.name, Switch);(//當按需import時疚鲤,也要import style.css文件,并且只能用Vue.component這樣的格式)”缘挑,Vant是有贊前端團隊推出的一款基于Vue.js的移動端UI框架集歇,跟bootstrap一樣,對原生的HTML標簽進行了封裝和美化语淘,使用Vant可以讓我們能夠?qū)W⒂跇I(yè)務邏輯而不是UI界面诲宇,官網(wǎng)是youzan.github.io/vant/#/zh-CN,進入官網(wǎng)惶翻,點擊“快速上手”姑蓝,然后就看到安裝方法了,首先在我們vue項目的根目錄下輸入命令“npm i vant -S”敲回車來局部安裝Vant吕粗,當想要按需import時纺荧,首先需要在我們vue項目的根目錄下輸入命令“npm i babel-plugin-import -D”敲回車來局部安裝babel-plugin-import插件榔至,然后通過vscode編輯器打開我們項目根目錄下的babel.config.js文件誓沸,然后在配置對象中再添加一個plugins數(shù)組(詳見Vant官網(wǎng)->快速上手->“對于使用 babel7 的用戶沸手,可以在babel.config.js中配置”)柱恤,然后在main.js文件中寫上例如“import {NavBar, Card, SubmitBar} from ‘vant’; ?Vue.use (NavBar); ?Vue.use (Card); ?Vue.use (SubmitBar);”,當某一個vue組件/功能經(jīng)常需要用到時狼速,我們就可以將此vue組件/功能定義成一個基于Vue.js的插件(xxx.js)侈净,比如網(wǎng)絡加載指示器疯坤,首先在src文件夾下創(chuàng)建一個plugin子文件夾肢簿,然后在此plugin子文件夾下再創(chuàng)建一個名稱自定義的插件文件夾,此插件文件夾中可以放置一些vue文件蜻拨,然后在此插件文件夾下再創(chuàng)建一個index.js文件用來書寫此插件的JS代碼池充,例如“import Loading from ‘./Loading.vue’; ?export default {install: function (Vue, Options) {Vue.component (Loading.name, Loading);};(//參數(shù)1接收到的是Vue這個類對象,參數(shù)2接收到的是use方法的參數(shù)2)”缎讼,Vue類對象調(diào)用它的use方法可以在參數(shù)1插件是一個對象/函數(shù)時給此vue項目的源代碼中添加一個基于Vue.js的插件收夸,當參數(shù)1插件是一個函數(shù)時,它會被作為install方法血崭,詳見v2.cn.vuejs.org/v2/guide/plugins.html和v2.cn.vuejs.org/v2/api/#Vue-use卧惜,例如“import Loading from ‘./plugin/loading/index.js’;(//常量Loading是此插件的配置對象) ?Vue.use (Loading, {title: ‘皇帝不急太監(jiān)急’});(//use方法需要在new Vue之前調(diào)用厘灼,在調(diào)用的時候會自動執(zhí)行參數(shù)1插件配置對象里的install方法,并且參數(shù)2會傳給install方法的參數(shù)2)”
四咽瓷、實戰(zhàn)項目--利用網(wǎng)易云音樂NodeJS版API來寫一個音樂應用
當所有的人都通過it666的web服務器(即遠程web服務器)向網(wǎng)易云音樂的web服務器發(fā)送數(shù)據(jù)請求時设凹,就一定會產(chǎn)生請求過頻的問題,這時網(wǎng)易云音樂的web服務器就會認為是在竊取它的數(shù)據(jù)茅姜,所以它就會短時間的禁封it666的web服務器(即遠程web服務器)的ip闪朱,這時就會返回一個460的錯誤,解決的辦法就是將it666的web服務器部署到本地钻洒,這樣一來奋姿,我們請求數(shù)據(jù)就可以通過本地web服務器來發(fā)送請求了,由于本地web服務器只能我們自己使用素标,所以向網(wǎng)易云音樂的web服務器發(fā)送請求的頻率就變低了称诗,這樣一來就能大大降低網(wǎng)易云音樂的web服務器禁封我們ip的概率了,由于it666的web服務器端的程序是使用NodeJS編寫的头遭,所以就必須在本地安裝NodeJS寓免,安裝完之后進入“網(wǎng)易云音樂NodeJS版API”官網(wǎng),網(wǎng)址是musicapi.leanapp.cn任岸,然后點擊查看文檔->右上角的小貓再榄,進入GitHub,然后將壓縮包下載下來享潜,解壓縮之后雙擊打開此文件夾困鸥,將此窗口的地址欄中的地址改成cmd,然后敲回車剑按,輸入命令“npm install”敲回車來將此NodeJS項目所依賴的插件和包都安裝到此文件夾疾就,然后輸入命令“node app.js”敲回車,當看到server running時艺蝴,就代表這個本地web服務器已經(jīng)部署好了猬腰,然后我們可以嘗試著登錄一下server running后面跟的網(wǎng)址,可以將網(wǎng)址中的localhost換成127.0.0.1猜敢,然后進入我們自己的vue項目中姑荷,找到我們自己封裝好的網(wǎng)絡工具類api.js,將地址換一下缩擂,例如“axios.defaults.baseURL = “http://127.0.0.1:3000”;(//設置全局的URL根地址)”鼠冕,然后初始化index.html文件中的代碼,比如設置國產(chǎn)web瀏覽器和IE瀏覽器的兼容胯盯、添加搜索優(yōu)化的三大標簽懈费、和設置在蘋果設備的safari瀏覽器下的一些快捷圖標(詳見public文件夾中的index.html文件),然后通過JS代碼利用“rem+視口縮放”的方式來動態(tài)的適配當前移動端設備(無論此手機的屏幕是幾倍屏博脑,都以強制更改此手機屏幕虛擬像素的方式憎乙,來使此手機屏幕的虛擬像素和它真實的物理像素保持一一對應的關系票罐,這就叫做視口縮放,其實我感覺移動端開發(fā)轉(zhuǎn)rem是必須的泞边,視口縮放不是必須的该押,因為都已經(jīng)轉(zhuǎn)rem了,已經(jīng)達到自適應的目的了繁堡,視口縮不縮放都無所謂了)沈善,格式為“<script>let scale = 1.0 / window.devicePixelRatio;(//計算縮放的大小,window對象訪問它的devicePixelRatio屬性可以返回當前設備的像素密度比椭蹄,像素密度比是幾就叫做幾倍屏) ?let text = `<meta name=“viewport”content=“width=device-width, initial-scale=${scale}, maximum-scale=${scale}, minimum-scale=${scale}, user-scalable=no”>`;(//通過JS代碼動態(tài)的設置視口闻牡,initial-scale、maximum绳矩、和minimum-scale分別代表初始罩润、最大、和最小縮放比) ?document.write (text); ?document.documentElement.style.fontSize = window.innerWidth / 7.5 + “px”;(//通過JS代碼動態(tài)的設置根標簽即<html>的font-size值翼馆,其實割以,“window.innerWidth / 7.5”可以理解為“100 * window.innerWidth / 750”,750就是設計稿的寬度) ?document.documentElement.setAttribute (‘data-dpr’, window.devicePixelRatio + ‘’); ?document.documentElement.setAttribute (‘data-theme’, ‘theme’);</script>”应媚,由于npm run build時會借助html-plugin插件將.html文件中的代碼拷貝到dist目錄严沥,但是當.html文件的模板字符串中出現(xiàn)了變量時,html-plugin插件就無法處理了中姜,所以打包時就會報錯消玄,這時就需要局部安裝一個html-loader插件,登錄npmjs官網(wǎng)丢胚,網(wǎng)址是“npmjs.com”翩瓜,然后搜索html-loader,就看到安裝命令了携龟,可以輸入命令“npm?install?-D?html-loader”敲回車來給我們的vue項目局部安裝一個html-loader插件兔跌,然后還需要進入vue.config.js文件配置一下html-loader插件(詳見vue.config.js文件),由于適配移動端需要將px轉(zhuǎn)成rem(數(shù)值除以100)峡蟋,所以需要借助postcss-pxtorem插件將px自動轉(zhuǎn)成rem坟桅,可以輸入命令“npm i -D postcss-pxtorem”敲回車來給我們的vue項目局部安裝一個postcss-pxtorem插件,然后在vue項目的根目錄下新建一個postcss.config.js文件蕊蝗,配置一下postcss-pxtorem插件就可以了(詳見postcss.config.js文件)仅乓,使用Vue-CLI創(chuàng)建的vue項目已經(jīng)自動幫我們實現(xiàn)了CSS3和ES678語法webkit內(nèi)核的兼容,就不用再借助webpack實現(xiàn)了匿又,但是我們可以在vue項目的根目錄下的.browserslistrc文件中再配置一下各種web瀏覽器的兼容(詳見.browserslistrc文件)方灾,然后需要安裝fastclick插件來解決移動端100~300ms的點擊事件延遲問題建蹄,可以輸入命令“npm install fastclick”敲回車來給我們的vue項目安裝一個fastclick插件碌更,然后在main.js中import并配置此插件裕偿,格式為“import fastclick from ‘fastclick’; ?fastclick.attach (document.body);”,然后設置默認的全局樣式痛单,在assets文件夾下新建一個css文件夾嘿棘,然后將base.scss、mixin.scss旭绒、reset.scss鸟妙、和variable.scss(定義了一些常用的變量)文件放入其中,在base.scss中@import reset.scss挥吵、variable.scss重父、和mixin.scss,然后在main.js中import base.scss忽匈,格式為“import ‘./assets/css/base.scss’;”房午,在移動端開發(fā)中,一般情況下我們需要讓字體大小在任何屏幕尺寸和像素密度比下都保持不變丹允,但由于我們是通過“rem+視口縮放”來適配移動端的郭厌,所以當我們將font-size值寫死時,屏幕大小和字體大小是正相關的雕蔽,解決的方式是首先讓postcss-pxtorem插件只轉(zhuǎn)換width和height屬性折柠,也就是打開postcss.config.js文件,將propList數(shù)組由[‘*’]修改成[‘width’, ‘height’]批狐,其實這樣比較麻煩扇售,因為當以后我們再想轉(zhuǎn)換其它CSS屬性時,就得一個一個手動向里添加贾陷,所以我們可以不用做任何修改缘眶,當某個CSS屬性值不想被轉(zhuǎn)換時,就將單位名稱px的首字母大寫就可以了髓废,然后當像素密度比是2時巷懈,就讓font-size值放大兩倍,當像素密度比是3時慌洪,就讓font-size值放大三倍顶燕,也就是調(diào)用mixin.scss文件中封裝好的font_size混合,再賦值給font-size屬性就可以了冈爹,當我們需要向web服務器請求數(shù)據(jù)時涌攻,可以使用axios插件,所以可以輸入命令“npm install axios”敲回車來給我們的vue項目安裝一個axios插件频伤,安裝好之后我們可以將axios.get恳谎、axios.post、和axios.all封裝到一個所export的對象中,在src文件夾下新建一個api文件夾因痛,在api文件夾下新建一個network.js文件并打開它婚苹,首先需要import axios類對象,格式為“import axios from ‘a(chǎn)xios’;”鸵膏,然后需要進行一些全局的配置膊升,例如“axios.defaults.baseURL = “http://127.0.0.1:3000”;(//設置全局的URL根地址) ?axios.defaults.timeout = 3000;”,然后利用axios類對象在所export的對象中封裝自己的get谭企、post廓译、和all方法(詳見network.js文件),然后為了方便我們后續(xù)管理债查,在api文件夾下再新建一個index.js文件用于定義向web服務器數(shù)據(jù)接口的URL來get/post/all請求各種數(shù)據(jù)的函數(shù)非区,方便后期直接調(diào)用(各種數(shù)據(jù)接口的URL請詳見網(wǎng)易云音樂api的官方文檔binaryify.github.io/NeteaseCloudMusicApi/#),打開index.js文件后盹廷,首先import network.js文件中所export的自己封裝的對象院仿,格式為“import network from ‘./network.js’;”,然后將所定義的一些具名函數(shù)export出去(即暴露出去)速和,例如“export const getBanner = () => Network.get (‘banner?type=2’);(//向web服務器請求<banner>的數(shù)據(jù))”歹垫,然后找到相應的vue組件,例如<Recommend>颠放,然后在<Recommend>的一對<script>中import相應的具名函數(shù)排惨,格式為“import getBanner from ‘../api/index.js’;”,然后在<Recommend>的配置對象中的created方法的函數(shù)作用域中調(diào)用一下相應的具名函數(shù)碰凶,格式為“created () {getBanner ().then (data => console.log (data) ).catch (err => console.log (err) )}”暮芭,向web服務器所請求到的<banner>數(shù)據(jù)可以使用Swiper插件(一款觸摸滑動插件)來展示(輪播),首先進入Swiper的官網(wǎng)www.swiper.com.cn欲低,中文教程->在Vue中使用Swiper辕宏,然后找到Install,就看到安裝方法了砾莱,可以輸入命令“npm install swiper vue-awesome-swiper --save”敲回車來給我們的vue項目局部安裝一個Swiper插件瑞筐,找到Global Registration和Local Registration就看到如何全局import(即在main.js中import,此vue項目的所有vue組件就都可以使用了)和局部import(即在某個vue組件中import腊瑟,只有某個vue組件可以使用)了聚假,然后找到Component就看到如何搭建它的HTML結(jié)構(gòu)了,然后在<Banner>中按照教程局部import Swiper插件闰非,格式為“import ‘swiper/dist/css/swiper.css’; ?import {swiper, swiperSlide} from ‘vue-awesome-swiper’;”膘格,并將所import的<swiper>和<swiperSlide>的配置對象注冊為<Banner>的局部組件,然后在data對象中配置一下swiperOption(詳見Banner.vue文件)财松,然后按照教程及自己的需求搭建一下HTML的三層結(jié)構(gòu)瘪贱,Swiper插件有一個bug,那就是當數(shù)據(jù)是從網(wǎng)絡獲取的時,自動輪播到最后一頁就不輪播了菜秦,解決方式是在渲染<swiper>時其徙,給它添加一個“v-if=“數(shù)據(jù).length > 0””就可以了,當想要覆蓋掉swiper.css中所設置的某個CSS樣式時喷户,<style>一定不能設置scoped屬性,當原有的<style>設置了scoped屬性時访锻,可以在下面添加一對新的沒有設置scoped屬性的<style>(即全局樣式)褪尝,然后書寫CSS樣式代碼就可以了,比如我們修改了分頁器內(nèi)部小圓點的CSS樣式期犬,當在<PlayerMiddle>中再次復用Swiper插件時河哑,就沒法再次使用相同的類名修改分頁器內(nèi)部小圓點的CSS樣式了,這時只能使用自定義類名的方式龟虎,詳見www.swiper.com.cn/api/pagination/79.html(分頁器內(nèi)部默認狀態(tài)小圓點的類名設置)璃谨、www.swiper.com.cn/api/pagination/80.html(分頁器內(nèi)部激活狀態(tài)小圓點的類名設置)、和PlayerMiddle.vue文件中的具體配置鲤妥,然后在頁面級的vue組件<Recommend>中的一對<script>內(nèi)import<Banner>這個小vue組件并將它注冊為自己的局部組件佳吞,當想要實現(xiàn)圖片的懶加載(即漸進式加載圖片,比較節(jié)省流量和性能)時棉安,需要安裝一個vue-lazyload插件底扳,可以輸入命令“npm?i?vue-lazyload?-S”敲回車來給我們的vue項目局部安裝一個vue-lazyload插件,使用教程詳見“www.npmjs.com/package/vue-lazyload”的“Usage”贡耽,首先需要在main.js中import并use此插件衷模,格式為“import?VueLazyload?from ‘vue-lazyload’; ?Vue.use (VueLazyload, {loading: require (‘./assets/images/loading.png’) } );(//可以通過配置loading屬性來設置圖片還未加載好之前的占位圖片)”,然后將各個vue組件中的<img>的src屬性連同v-bind指令整體換成v-lazy屬性就可以了蒲赂,當想要僅讓指定的區(qū)域可以滾動時阱冶,需要安裝一個iscroll插件,可以輸入命令“npm install iscroll”敲回車來給我們的vue項目局部安裝一個iscroll插件滥嘴,我們可以將iscroll封裝成一個vue組件(比如就叫做<ScrollView>木蹬,編寫此vue組件時別忘了寫上一個<slot>即插槽),將來什么內(nèi)容需要滾動若皱,就把什么內(nèi)容嵌套在一對<ScrollView>中就可以了(使用的時候需滿足三層結(jié)構(gòu)届囚,即任意一對根標簽(即iscroll容器)內(nèi)部嵌套一對<ScrollView>,然后一對<ScrollView>內(nèi)部再嵌套需要滾動的內(nèi)容就可以了)是尖,我們可以在components文件夾中新建一個ScrollView.vue組件意系,然后在此vue組件中import IScroll這個類,格式為“import IScroll from ‘iscroll/build/iscroll-probe’;(//iscroll的專業(yè)版本饺汹,可以監(jiān)聽滾動的位置和細節(jié)蛔添,擴展性更好)”,然后按照教程“caibaojian.com/iscroll-5”搭建HTML結(jié)構(gòu)并配置就可以了(詳見ScrollView.vue文件),當想要讓iscroll容器中的內(nèi)容可以滾動時迎瞧,iscroll容器(總之是包裹里邊內(nèi)容的上級HTML標簽)的height值必須小于里邊內(nèi)容的height值夸溶,當iscroll容器中的數(shù)據(jù)是從本地/遠程web服務器上獲取的時,渲染完畢之后必須刷新一下凶硅,否則無法滾動缝裁,格式為“this.iscroll.refresh ();(//iscroll是IScroll實例對象)”,當想要監(jiān)聽iscroll容器中的內(nèi)容是否全都渲染完畢時足绅,可以使用MutationObserver實例對象捷绑,即觀察者對象,網(wǎng)址是developer.mozilla.org/zh-CN/docs/Web/API/MutationObserver氢妈,觀察者對象可以監(jiān)聽某個DOM元素的子/后代節(jié)點對象及其屬性的變化粹污,所以我們可以使用觀察者對象來監(jiān)聽<ScrollView>所對應DOM元素(只需要給<ScrollView>的根標簽設置一下ref屬性就可以獲取到了)的子節(jié)點對象等的變化,只要發(fā)生了變化首量,就refresh一下就可以了壮吩,首先第一步,new一個觀察者對象加缘,格式為“l(fā)et observer = new MutationObserver ((mutationList, observer) => {this.iscroll.refresh ();} );(//形參mutationList接收到的是所有發(fā)生變化的子/后代節(jié)點對象所組成的數(shù)組鸭叙,形參observer接收到的是此觀察者對象,只要被監(jiān)聽的內(nèi)容發(fā)生了變化拣宏,就會自動執(zhí)行所傳入的回調(diào)函數(shù))”递雀,然后第二步,創(chuàng)建一個所監(jiān)聽內(nèi)容的配置對象蚀浆,格式為“l(fā)et config = {childList: true(//監(jiān)聽子節(jié)點對象的變化), subtree: true(//監(jiān)聽后代節(jié)點對象的變化), attributeFilter: [‘height’, ‘offsetHeight’](//監(jiān)聽指定JS屬性的變化)};”缀程,最后第三步,告訴第一步所創(chuàng)建的觀察者對象到底監(jiān)聽哪一個DOM元素市俊,觀察者對象調(diào)用它的observe方法可以監(jiān)聽參數(shù)1DOM元素的參數(shù)2配置對象杨凑,格式為“observer.observe (this.$refs.wrapper, config);”,完事之后滾動起來可能會非嘲诿粒卡頓撩满,因為系統(tǒng)默認監(jiān)聽了拖拽事件,而iscroll插件也監(jiān)聽了拖拽事件绅你,這樣就會導致發(fā)生沖突伺帘,此時需要將系統(tǒng)默認的拖拽事件禁用掉,在base.scss中添加上一句“html, body {touch-action: none;}”就可以了忌锯,完事之后可能還是會有一丟丟的卡頓伪嫁,只需要再給<ScrollView>增加一些配置就可以了(詳見ScrollView.vue文件),這時就沒有卡頓的問題了偶垮,但是一滾動就會將頭部內(nèi)容(<Header>和<Tabbar>)蓋住张咳,只需要給<ScrollView>的父標簽(即iscroll容器)設置一個“overflow: hidden;”就可以了帝洪,當想要監(jiān)聽iscroll容器中內(nèi)容滾動的距離值時,需要利用IScroll實例對象調(diào)用它的on方法(可以參考caibaojian.com/iscroll-5/customevents.html)脚猾,詳見<ScrollView>中的配置信息及on方法的使用葱峡,在很多界面上(比如歌單詳情界面、專輯詳情界面龙助、最新歌曲列表砰奕、歌手詳情界面、和歌曲搜索結(jié)果界面等)都需要控制默認播放器界面<NormalPlayer>的顯示/隱藏提鸟,所以我們應該在一個全局共享變量中去控制军援,即使用Vuex對象來共享數(shù)據(jù),當想要實現(xiàn)transition時沽一,可以使用<transition>并配合velocity.js和velocity.ui.js插件,可以輸入命令“npm install velocity-animate”敲回車來給我們的vue項目局部安裝velocity.js和velocity.ui.js插件漓糙,import的格式為“import Velocity from ‘velocity-animate’; ?import ‘velocity-animate/velocity.ui’;”铣缠,velocity.ui.js插件的使用方式可以參考官網(wǎng)“shouce.jb51.net/velocity/feature.html”->Plugins插件,然后找到“1-2內(nèi)置特效”就可以看到了昆禽,使用的格式為“enter (el, done) {Velocity (el, ‘transition.shrinkIn’, {duration: 500}, function () {done ();} );}, leave (el, done) {Velocity(el, ‘transition.shrinkOut’, {duration: 500}, function () {done ();} );}(//切記蝗蛙,在enter鉤子函數(shù)中,當transition執(zhí)行完畢后醉鳖,一定要“done ();”一下捡硅,否則leave鉤子函數(shù)的transition不會生效,‘transition.shrinkIn’和‘transition.shrinkOut’特效可以換成任意特效盗棵,詳見官網(wǎng))”壮韭,當想要在手機真機上查看網(wǎng)頁的控制臺時,需要安裝一個vconsole插件纹因,可以輸入命令“npm install vconsole”敲回車來給我們的vue項目安裝一個vconsole插件喷屋,然后在main.js中import并use此插件,格式為“import VConsole from ‘vconsole’; ?const vconsole = new VConsole (); ?Vue.use (vconsole);”瞭恰,然后在網(wǎng)頁的右下角就會看到一個叫做vConsole的綠色按鈕了屯曹,當整個vue項目都寫完之后,就該將我們的vue項目打包上架了惊畏,首先輸入命令“npm run build”敲回車來將我們的vue項目在硬盤中打包恶耽,打包完成之后,將dist文件夾中的所有文件都上傳到web服務器的www文件夾中就可以了(上架)颜启,我們可以模擬一下上架偷俭,首先雙擊打開wamp軟件,然后找到它的安裝目錄缰盏,進入www文件夾社搅,然后將dist文件夾中的所有文件復制粘貼到www文件夾中就可以了驻债,只有一個html文件的web應用就叫做單頁web/SPA應用(Single Page web Application),所有的內(nèi)容都在此html文件中呈現(xiàn)形葬,并且此html文件只會加載一次合呐,當用戶與應用程序交互時,會動態(tài)更新頁面來呈現(xiàn)不同的內(nèi)容笙以,我們通過Vue-CLI開發(fā)的項目其實就是典型的SPA應用淌实,SPA應用的優(yōu)點是具有良好的交互體驗,不會重新加載整個html網(wǎng)頁猖腕,只是局部更新拆祈,可以實現(xiàn)前后端分離開發(fā),web瀏覽器負責頁面的呈現(xiàn)與交互倘感,而web服務器只需要負責輸出數(shù)據(jù)放坏,不需要負責填充數(shù)據(jù),這樣一來老玛,既可以減輕web服務器的壓力淤年,也可以使多套前端程序共用一套后端程序,提升后端程序的復用性蜡豹,SPA應用的缺點是SEO難度較高麸粮,因為只有一個html頁面,無法針對不同的界面編寫不同的SEO信息镜廉,當所有組件都采用完整加載的方式時弄诲,初次加載耗時較多,三種常見的網(wǎng)頁渲染方式是客戶端渲染娇唯、服務端渲染齐遵、和預渲染,web服務器只負責輸出數(shù)據(jù)塔插,web瀏覽器來負責填充數(shù)據(jù)的渲染方式就叫做客戶端渲染(即CSR洛搀,Client Side Render),SPA應用就是典型的客戶端渲染佑淀,客戶端渲染的完整流程是留美,首先第一步,web瀏覽器逐行渲染向web服務器所請求到的html文件并找到所依賴的css和js文件伸刃,然后第二步谎砾,web瀏覽器再次向web服務器請求所依賴的css和js文件,此js文件中包括向web服務器請求數(shù)據(jù)的JS代碼捧颅,加載完畢之后繼續(xù)渲染此html文件景图,最后第三步,web瀏覽器根據(jù)所請求到的數(shù)據(jù)來填充html網(wǎng)頁碉哑,客戶端渲染最大的優(yōu)點是交互體驗好可以做局部的更新挚币,最大的缺點是首屏加載慢亮蒋,因為要等到請求完html文件才會去請求css和js文件,并且要等到所請求到的css和js文件加載完畢之后妆毕,才會根據(jù)JS代碼的執(zhí)行結(jié)果向web服務器請求數(shù)據(jù)并填充html網(wǎng)頁慎玖,不是很注重SEO的強交互頁面,建議采用客戶端渲染笛粘,web服務器既負責輸出數(shù)據(jù)又負責填充數(shù)據(jù)的渲染方式就叫做服務端渲染(即SSR趁怔,Server Side Render),服務端渲染的完整流程是薪前,首先第一步润努,web服務器查找web瀏覽器所請求的html文件并填充數(shù)據(jù),然后第二步示括,web瀏覽器渲染所請求到的包含數(shù)據(jù)的html文件铺浇,并找到所依賴的css和js文件,最后第三步垛膝,web瀏覽器再次向web服務器請求所依賴的css和js文件鳍侣,加載完畢之后渲染此html網(wǎng)頁,服務端渲染最大的優(yōu)點是首屏加載快繁涂,因為web瀏覽器所請求到的html文件已經(jīng)包含數(shù)據(jù)拱她,所以只需要再次請求css和js文件就可以直接渲染二驰,由于每次所請求到的都是一個獨立完整的html文件扔罪,所以更利于SEO,最大的缺點是網(wǎng)絡傳輸?shù)臄?shù)據(jù)量比較大桶雀,因為請求的是包含數(shù)據(jù)的完整html文件矿酵,比較注重SEO的新聞和電商類網(wǎng)站,建議采用服務端渲染矗积,無需web服務器實時動態(tài)編譯全肮,在npm run build時針對特定的路由界面簡單的生成靜態(tài)的html文件的渲染方式就叫做預渲染,本質(zhì)就是客戶端渲染棘捣,只不過跟SPA應用不同的是預渲染可以生成多個html頁面辜腺,最大的優(yōu)點是由于有多個html頁面,所以更利于SEO乍恐,最大的缺點是預編譯慢评疗,首屏加載也慢,當只需改善少數(shù)界面的SEO時茵烈,建議采用預渲染百匆,由于我們這個vue項目就屬于一個SPA應用,是存在SEO問題的呜投,所以我們可以采用預渲染的方式來解決這個問題加匈,首先輸入命令“vue?add?prerender-spa”敲回車來給我們的vue項目安裝一個vue-cli-plugin-prerender-spa插件存璃,參考網(wǎng)址是www.npmjs.com/package/vue-cli-plugin-prerender-spa,安裝過程中會問你“當前存儲庫中有未提交的更改雕拼,建議先提交保存它們纵东?”,輸入y敲回車就可以了悲没,然后會問你“你需要將哪些路由對應的界面生成一個單獨的html頁面篮迎?”,我們可以先跳過示姿,一會兒在后面再配置甜橱,直接敲回車就可以了厨钻,然后還會問你很多問題进肯,讓你輸入y/n,全程輸入y敲回車就可以了友存,安裝完成之后子檀,系統(tǒng)會在兩個地方自動添加代碼镊掖,第一個地方是在main.js文件中Vue實例對象的配置對象中,會自動添加上一個鍵值對“mounted: () => document.dispatchEvent (new Event (‘x-app-rendered’) )”褂痰,第二個地方是在vue.config.js的配置對象中亩进,會自動添加上一個pluginOptions對象,在其內(nèi)部的renderRoutes數(shù)組中缩歪,我們就可以將需要生成單獨html頁面的路由地址添加到其中了(詳見vue.config.js文件)归薛,當我們配置完renderRoutes數(shù)組之后,系統(tǒng)就會修改renderRoutes數(shù)組中所對應的所有vue文件的代碼格式匪蝙,使之不符合eslint的編碼規(guī)范主籍,這樣就會使打包失敗,所以我們只需要將這些vue文件的代碼格式都自動修復一下就可以了逛球,當給我們的vue項目安裝了vue-cli-plugin-prerender-spa插件時千元,路由對象router的配置對象中的mode值就必須是“history”,否則打包會失敗颤绕,由于預渲染的本質(zhì)就是在npm run build時模擬一個web瀏覽器(即PhantomJS瀏覽器幸海,一款無界面web瀏覽器)來提前訪問所有生成的html頁面,并將所生成的網(wǎng)頁源代碼寫入到一個個html文件中奥务,所以系統(tǒng)就獲取到了一個虛假的像素密度比(即window.devicePixelRatio)物独,進而通過JS代碼就動態(tài)生成了一個錯誤的<meta>,所以當我們打包完畢之后真正運行網(wǎng)頁時汗洒,只要一刷新網(wǎng)頁议纯,就會通過JS代碼在原位置又動態(tài)生成一個正確的<meta>,而那個錯誤的<meta>在正確的之后溢谤,所以優(yōu)先級更高瞻凤,這樣一來憨攒,網(wǎng)頁的縮放比就出錯了,網(wǎng)頁就走形了阀参,解決的方式是在預渲染的過程中就借助正則表達式匹配到那個錯誤的<meta>字符串并將其replace成‘’肝集,也就是將其扼殺在搖籃里(參考網(wǎng)址是www.npmjs.com/package/vue-cli-plugin-prerender-spa的“User post processing function”部分,詳見vue.config.js文件)蛛壳,當我們給此vue項目的源代碼中添加了一個“正在載入...”的插件時杏瞻,也是由于預渲染的緣故,此插件的HTML結(jié)構(gòu)代碼也會提前寫入html文件中衙荐,也是同樣的道理捞挥,當打包之后運行此網(wǎng)頁時,只要一刷新忧吟,頁面上就會一直顯示這個“正在載入...”的圖像砌函,所以我們就需要想辦法在預渲染的過程中就將提前生成的此插件HTML元素removeChild掉,但使用正則表達式來匹配一個帶內(nèi)容的HTML標簽字符串比較困難溜族,所以我們可以使用選擇器來查找讹俊,但vue.config.js中的代碼都是NodeJS代碼,會在NodeJS的環(huán)境中執(zhí)行煌抒,所以我們無法直接操作DOM仍劈,只能借助jsdom插件,此插件可以將網(wǎng)頁源代碼字符串轉(zhuǎn)成document對象寡壮,然后就可以像以前一樣操作DOM了(參考網(wǎng)址是www.npmjs.com/package/jsdom)贩疙,可以輸入命令“npm install jsdom --save-d”敲回車來給我們的vue項目安裝一個jsdom插件,首先在vue.config.js中寫上“const?jsdom?=?require (‘jsdom’); ?const {JSDOM}?=?jsdom;”诬像,然后在postProcess方法中配置一下就可以了(詳見vue.config.js文件)屋群,由于給每個html頁面都單獨編寫SEO信息非常麻煩闸婴,也非常不方便我們?nèi)ス芾砘的樱跃托枰惭b一個vue-meta-info插件來統(tǒng)一編寫與管理SEO信息,網(wǎng)址是www.npmjs.com/package/vue-meta-info邪乍,可以輸入命令“npm?install?vue-meta-info?--save”敲回車來給我們的vue項目安裝一個vue-meta-info插件降狠,首先在main.js中import并use此插件,格式為“import?MetaInfo?from ‘vue-meta-info’; ?Vue.use (MetaInfo);”庇楞,然后在我們vue項目的根目錄下新建一個vue-meta-info.js文件榜配,在此文件所export的配置對象中我們就可以編寫所有需要生成html頁面的vue文件的SEO信息了(詳見vue-meta-info.js文件),然后在相應的vue文件中吕晌,我們就可以import vue-meta-info.js的配置對象蛋褥,并將相應的SEO信息通過metaInfo屬性掛載到此vue文件的配置對象中了,然后我們需要將public文件夾中的index.html中的SEO三大標簽注釋掉睛驳,因為系統(tǒng)會自動添加烙心,所以我們就不需要手動添加了膜廊,否則系統(tǒng)就有可能添加不上去了,當一切都處理完畢之后淫茵,我們就可以通過npm run build來打包了爪瓜,這時可能會比較慢,比較耗時匙瘪,這是因為系統(tǒng)會去查找renderRoutes數(shù)組中所對應的所有vue文件都依賴哪些文件铆铆,然后將所依賴的文件都組合在一起生成一個新的html文件,所以查找和組合的過程是非常耗時的丹喻,當打包完成之后薄货,在dist文件夾中我們會發(fā)現(xiàn)有很多的html文件,數(shù)量跟renderRoutes數(shù)組中元素的個數(shù)相同碍论,然后我們需要將app.html重命名成index.html菲驴,然后就可以正常的上架了 ?????????????????