vue總結

 
一、庫和框架的區別

庫:jquery javascript

本質上就是一些列函數的集合,將一些函數封裝到一個獨立的就是文件中php

在使用的jquery的時候,是由開發人員說了算的,也就是說開發人員起到了主導做用,而jquery是輔助完成相應的功能的css

框架:vuehtml

框架是一套完整的解決方案,項目中用到的一些功能在框架內部都已經提供好了前端

在使用框架的時候,只要將咱們本身寫的代碼,放到框架合適的地方去,框架會在合適的時機主動調用咱們寫好的代碼,框架指定好了一套規則,咱們開發人員,按照這套規則寫代碼就能夠了vue

也就是說:在使用vue的時候,是由框架說了算的,也就是框架起到了主導做用java

 

庫和框架的區別?node

本質區別:控制反轉,誰起到了主導做用mysql

在使用框的時候,有開發人員起到了主導做用jquery

在使用框架的時候,由框架起到了主導做用

 

二、vue能夠看做是一個mvvm模式的框架的

它內部實現了數據雙向綁定

雙向綁定的兩個方面:

一、視圖---》數據 只要視圖中的內入改變了,那麼對應的數據也會自動跟着改變

二、數據---》視圖 只要數據發生改變,對應視圖內容也會自動更新

主要是保持視圖和數據的同步

mvvm模式:適合帶有視圖的應用,好比前端(頁面)、桌面端的應用等

這個模式最先出如今微軟wpf技術中

 

三、插值表達式 mustache語法

做用:將數據插入到當前位置

插值表達式中可以使用任意的js表達式,不能出現語句(if-else/for)

它不能出如今html屬性中

 

四、經常使用指令

v-model 指令的做用:用來實現數據的雙向綁定,讓文本框的值和數據雙向綁定到一塊兒,只要任意一個改變,另一個都會自動跟着改變

(只能用在表單元素中,在不一樣的表單元素中,功能不一樣)

v-text 用來設置文本內容,至關於(innerText),若是元素中有默認內容,默認內容會被覆蓋掉

v-html 若是字符串中的內容,包含了html字符串,就用v-html(也會覆蓋)

v-bind 給html屬性動態設置內容

操做樣式 的兩種方式

v-bind:class="{ 要添加的類名: 布爾值 }"

v-bind:style="{}"

v-on: click='fn' v-on(簡寫@) 綁定事件的前綴 click事件名稱

( eg @click="foo" 注意:若是沒有給事件處理程序顯示經過 () 來傳遞參數,那麼,第一個參數默認表示:事件對象 ; 若是傳遞參數了須要使用vue中約定的$event 來獲取事件對象 )

v-show v-if 都是控制元素的展現與隱藏

v-show 值爲true顯示,false 隱藏;經過css的display :none 來控制展現與隱藏的

v-if 值爲true顯示, false隱藏,是經過移除元素,把html結構中這個標籤刪除來隱藏的,操做了dom

v-else / v-else-if 相似於js中的if-else

必須先使用v-if指令,後面才能使用v-else 或 v-else-if 指令

v-cloak 解決vue中剛渲染頁面時候插值表達式閃爍的問題

給元素添加v-cloak指令後,手動添加display:none的樣式,會讓該元素隱藏,當vue解析模版內容的時候,首先會把 {{}} 解析成對應的數據,而且將 v-cloak 指令,從元素中 移除掉。 指令移除後, display: none 的樣式 就再也不生效了,因此,最終在頁面中就看到數據內容了

v-once 該指令所在元素中的內容,只會被解析成一次
v-pre 指令所在的元素中的內容,一次都不會被解析,告訴vue跳過該指令所在的元素,不去遍歷該元素以及全部的後代元素

v-for 可以遍歷指定的數據(數據或對象),重複生成指令所在的標籤

<li v-for="(item, key, index) in obj"> item 表示對象中屬性的值 key 表示對象中屬性的鍵 index 表示索引號

只有使用了v-for指令,就要添加key屬性,key屬性的值是惟一的,通常就是用數據中的id做爲key值

爲何要加key?

使用v-for不加key 會有臨時狀態出現錯亂的現象,(好比在文本框輸入文字的時候,會錯位)

爲何會出現這樣的問題?

vue中使用v-for渲染列表數據的時候,默認採用的是就地複用的策略,出於性能的考慮

什麼是就地複用?

默認狀況下不添加key,實際狀況是以每一項的索引號做爲key,可是每一項的數據的索引號是會發生改變的,全部插入數據後,數據就錯亂了

總結:

一、默認不添加key的時候,就是按照索引號來複用元素,會有問題

二、添加key的時候,應該保證key是惟一的且不可變的,通常就是每一項的id,此時就是按照id來複用的

三、若是列表渲染不依賴於臨時狀態,此時,就可使用index做爲key值

 

五、事件修飾符

.prevent 是一個事件修飾符,用來阻止瀏覽器的默認行爲

 

六、vue採用異步的方式更新DOM

也就是說:數據發生改變後,DOM沒有當即被更新的,而是等到數據再也不發生改變的時候,一次性的將全部的DOM更新

爲何採用異步方式更新DOM? 性能考慮

由於若是數據發生改變就更新dom,這會進行大量的dom操做,引發屢次瀏覽器的重繪和重排 ,性能影響大

在某些狀況下,可能須要在修改數據後,當即獲取到DOM內容,此時,能夠經過vue中的$nextTick() 來獲取更新後的DOM

$nextTick ()參數是一個回調函數,這個回調函數會在dom更新後當即觸發

 

七、vue動態添加數據

添加單個 vue.$set(1,2,3)

參數一:表示要給哪一個對象添加響應式數據

參數二: 表示要添加的屬性名稱叫什麼

參數三: 表示要添加屬性的值爲多少

添加多個 Object.assign() 方法來批量添加

建立一個新的空對象,將後面全部對象參數中的屬性,拷貝到新對象中,而且將這個新對象返回,這樣作,不會改變原始對象的結構

Object.assign({}, vm.obj, { age: 19, gender: 'male', weight: 180 })

 

八、監視數據變化 watch

watch :{

​ 對象的健表示要監視的數據

​ xx: {

​ handler 是固定的名稱

​ 第一個參數:當前最新值

​ 第二個參數 : 表示上一次的值

​ handler( newVal, oldVal){

​ }

​ }

}

若是監聽對象類型數據的變化,須要添加deep屬性,來實現深度監聽,纔可以監聽到對象中屬性的改變

若是監聽的是對象類型的數據,那麼,newVal和oldVal 表示同一個對象

九、vue是生命週期

十、json-server 是nodeJS的一個包,做用:用來提供假數據

在沒有服務器接口的時候,經過這個工具提供一個假數據,當有了服務器的接口,再替換成爲真正的真數據便可

使用步驟:

一、全局安裝 npm i -g json-server

二、準備應該json文件

三、在json文件中,運行命令: json-server 文件名 --watch

 

json-server 提供的接口是 REST API (restful) 配合postman 插件使用

查詢:get請求

​ 查詢全部數據: http://localhost:3000/json文件名

​ 查詢某一條(把參數id帶着):http://localhost:3000/json/2

添加: post 請求

修改:PATCH / PUT 請求

​ 修改也要帶着id

若是是PATCH 請求,只須要將要修改的數據做爲參數發送給接口便可

若是用的是PUT 請求,須要將全部的數據所有發送給接口

刪除 : DELETE請求

帶着參數

 

十一、axios的使用

axios 是一個專門用來發送ajax請求的包

axios 和 vue沒有任何關係,axios能夠在任何地方用來發送請求

它是一個http客戶端,能夠在瀏覽器或node中來發送請求

使用步驟:

一、安裝 npm i axios

二、 在頁面中引入axios


發送GET請求 能夠經過.then()方法來獲取接口返回的數據
axios.get("http//localhost:3000/json").then(res=> {})

傳遞參數方式
第一種方式
axios.get("http://loaclhost:3000/json?_id=1&_name='zs'").then(res => {})
第二種方式
axios.get("http://loaclhost:3000/json",{
  params:{
      _id:1,
      _name:'zs'
  }
}).then(res=> {})
第三種方式 字符串模版
axios.get(`http://loacllhost:3000/json/${id},${name}`).then(res=>{})


發送post請求
axios.post("http://localhost:3000/json",{
  name:'zs',
  age: 18
}).then(res=> {})


發送PATCH、PUT請求
axios.patch("http://localhost:3000/json/2",{
  name:'ls'
}).then(res => { })


發送DELETE請求:
axios.delete("http://localhost:3000/json/3")

 

十二、vue中的更新機制(虛擬DOM 和 diff 算法)

vue中的dom更新是異步的

vue中更新DOM是隻更新變化的地方,也就是說,只有頁面中用到的數據發生了改變,那麼頁面中的數據纔會被更新,若是頁面中的數據沒有改變,那麼,頁面中的元素是不會被更新的

這樣作的優點:下降了DOM 更新,也就是減小了瀏覽器的重繪與重排,提高了性能

問題: vue若是知道要更新哪一個地方? 虛擬dom + diff算法實現的

爲何不使用原生的DOM對象,而是本身手動建立一個虛擬DOM對象?

由於原生DOM對象中有不少屬性,而這些屬性中絕大部分與頁面的表現沒有任何的關係

 

diff算法是如何更新DOM的?

一、vue第一次編譯模版的時候,會生成一個虛擬的DOM 對象

二、當有數據發生改變後,vue又會生成一個新的虛擬DOM對象

三、經過diff算法,來對比更新先後兩個虛擬DOM對象,找到不一樣的地方

四、只將變化的地方,更新到頁面中,這樣,用戶就看到頁面更新了

 

虛擬DOM如何產生的? vm._vnode

模版 + data = > 虛擬DOM

模版 + 新的data => 新的虛擬的DOM對象

 

1三、vue中的過濾器

vue中的過濾器是用來對數據進行格式化處理的

(數據格式化就是讓一個數據按照咱們指定好的格式輸出就是數據的格式化)

vue中的過濾器分爲:

全局過濾器

局部過濾器

 

過濾器的語法: 經過 | 管道符號 ,來使用過濾器

做用:使用date 過濾器,來格式化curTime 這個數據,最終,將格式化後的數據輸出

<p>{{ curTime | date }}</p>


註冊全局過濾器
Vue.filter('data',input=>{
  return `${input.getFullYear() - ${input.getMonth() + 1}}`
})

第一個參數:表示過濾器的名稱
第二個參數:是一個回調函數,表示過濾器的代碼邏輯,即在使用過濾器的時候,這個回調函數就會執行
返回值:表示 格式化的數據的內容,這個內容會展現在頁面中

配合moment插件使用,更簡單
Vue.filter('date',(input, format = 'YYYY-MM-DD HH:mm:ss', arg1, arg2) => {
        // 回調函數第一個參數:表示要格式化的數據
        // 後面能夠有任意多個參數,這些參數都是在 使用過濾器 的時候傳入的
        console.log('傳入參數爲:', format, arg1, arg2)
        return moment(input).format(format)
      }
  )
   
   

局部過濾器
filters: { date(input, format = 'YYYY-MM-DD HH:mm:ss') {
  return moment(input).format(format)
}
}

全局過濾器 和 局部過濾器的區別
全局過濾器能夠在任意vue實例(組件)中使用)0
局部過濾器只能在當前vue實例(組件)中使用
1四、組件化開發

將一個完整的頁面,劃分紅一個個的組件,最終由一個個組件來完成整個頁面的開發,這個過程就是組件化開發

優點: 複用

1五、組件的兩種註冊方式

全局組件和局部組件


註冊全局組件
Vue.component('hello',{
  templata: //templata 做用:指定組件模版  
  `
  <div>這是一個組件</div> // 只能出現一個根節點
  `
})
第一個參數:表示組件名稱
第二個參數:是一個配置對象

註冊局部組件
components: {
    jack: {
      template: `
      <div>這是 hello 組件的子組件 jack</div>
      `
    }
}


兩種方式的區別:
1 全局組件能夠在任意的地方使用
2 局部組件只能在所屬組件的 模板 中使用
1六、組件通信

組件是一個獨立且封閉的個體,也就說:默認狀況下,組件只能使用自身的數據,而不能使用外部的數據,在組件化開發的過程當中,兩個組件通信,就須要經過組件通信機制來解決

一、父到子通信

第一步:在子組件標籤中添加要傳遞的屬性

第二步:在子組件中經過props顯示指定要接收的數據

第三步:就能夠在子組件中直接使用父組件中的數據了


props 是隻讀的,在組件中使用的時候,只能讀取,不能修改props的值(賦值)
若是props是一個引用類型的數據,不能直接賦值,可是,能夠修改引用類型中某個屬性的值
單向數據流 :是說組件之間數據流動方向是從父組件流動到子組件的,父組件能夠經過props將數據傳遞給子組件,而且,當父組件中的這個數據改變後,這個改變後的數據會自動的再流動到子組件中,也就是說,子組件會自動接收到最新的props數據,而且自動更新

props命名的規則
一、使用純小寫字母
二、傳遞屬性的時候,使用-鏈接多個單詞,在子組件中經過駝峯命名法來接收這個數據

二、子到父通信

第一步:父組件提供一個方法,這個方法由子組件調用

第二步:父組件將這個方法傳遞給子組件

第三步:子組件調用傳遞過來的方法(觸發自定義事件 this.$emit)

第四步:將要傳遞的數據,做爲方法參數,進行傳遞,這樣,父組件中的方法就會被調用,而且能夠經過形參,來拿到子組件中傳遞過來的數據了

三、非父子組件通信

第一步:建立一個事件總線(const bus = new Vue())

第二步:哪一個組件要接收數據,就註冊事件

bus.$on(事件名稱,()=> {})

第三步:哪一個組件要傳遞數據,就觸發事件

bus.$emit(事件名稱,要傳遞的數據)

注意:註冊和觸發事件的bus 是同一個,事件的名稱也是相同的

實際上無論兩個組件是什麼關係,均可以經過bus方式來實現通信!

 

1七、SPA(single page application)單頁面應用程序

概念: 一個web應用中只有一個 頁面組成

也就是說:將原來由多個頁面配合完成的功能,如今使用一個頁面來實現

多頁面應用程序(MPA multiple page application)

概念: 一個web應用中有多個頁面組成

SPA的技術點:

一、ajax

二、哈希值

三、hashchange事件

 

爲何使用SPA?

一、加載內容更少,由於一些相同的頁面部分(頭部、側邊欄等)不須要重複加載

二、用戶體驗更好,能夠經過loading效果,告訴用戶數據加載中

三、減小服務器的壓力,由於加載內容少了,服務器須要處理的內容少了,壓力就小了

SPA的缺點:也就是ajax的缺點

不利於SEO(搜索引擎優化) 它是服務端渲染的

 

1八、路由 的基本使用

使用步驟

一、安裝路由 npm i vue-router

二、在頁面中引入路由的js文件

三、建立路由實例

四、將路由實例與vue實例關聯到一塊兒

五、配置路由規則

六、在頁面中 指定內容展現的位置(路由出口)

七、在頁面中指定路由的入口(導航菜單 a 標籤)


<body>
  <div id="app">
    <!-- 指定路由入口: -->
    <ul>
      <!-- to屬性 和 路由規則中的 path 相匹配 -->
      <li><router-link to="/home">首頁</router-link></li>
      <li><router-link to="/about">關於</router-link></li>
    </ul>

    <!-- 指定路由出口: -->
    <router-view></router-view>
  </div>

  <script src="./vue.js"></script>
  <script src="./node_modules/vue-router/dist/vue-router.js"></script>
  <script>
    /*
      路由的使用:
       
      1 安裝路由: npm i vue-router
      2 在頁面中引入路由的js文件(注意:在引入 Vue 以後)
      3 建立路由實例
      4 將路由實例與Vue實例關聯到一塊兒
      5 配置路由規則
      6 在 頁面中 指定組件內容展現的位置( 路由出口 )
      7 在 頁面中 指定路由的入口(導航菜單 a標籤)
    */

    // 註冊home組件
    const Home = Vue.component('home', {
      template: `
        <div>這是 Home 組件</div>
      `
    })
    // 快速簡潔的註冊組件:
    const About = {
      template: `
        <h2>這是 About 組件</h2>
      `
    }

    const router = new VueRouter({
      // 經過該配置配置路由規則
      routes: [
        // 每個路由規則都是一個對象
        // path 表示路由規則的路徑,不要帶有#
        // component 用來指定展現的內容,是一個組件
        { path: '/home', component: Home },
        { path: '/about', component: About }
      ]
    })

    const vm = new Vue({
      el: '#app',
      data: {},
      // 將路由實例與Vue實例關聯到一塊兒
      router
    })
  </script>
</body>

路由內部執行流程

一、點擊頁面中的router-link(也就是a標籤),瀏覽器地址欄中的哈希值發生改變

二、當哈希值發生改變的時候,vue路由就監聽到了這個變化

三、vue路由獲取到當前的哈希值,將這個哈希值與配置好的路由規則path進行匹配

四、當匹配成功了,就把當前path對應的組件渲染到頁面的router-view路由出口的位置

五、這時,用戶就能夠在頁面中看到頁面的內容變化

路由規則匹配是按照 routes數組中索引號的順序的,一個個進行匹配,若是前面的路由匹配成功了,那麼,後面的路由規則,就不會再匹配

 

默認路由:/

{path : ' /' , component :Home}

路由重定向:

進入頁面,這個路由會被默認匹配到,直接經過redirect 配置項,跳轉到 / home; 這個路由,最終,展現的 /home 對應的組件:Home


{ path: '/', redirect: '/home' },

{ path: '/home', component: Home }

路由的入口高亮

由於router-link會給當前匹配的導航菜單(路由入口)添加高亮的類名,因此咱們只須要給類名添加高亮的樣式,就能夠實現菜單高亮效果了

router-link-exact-active, router-link-active 這是自動生成的類名,只須要給他添加上高亮的樣式就能夠了

 

若是要使用第三方的樣式庫(好比:bootstrap ),此時能夠在路由中添加linkActiveClass 配置項,來將默認的高亮類名修改成樣式庫中對應的高亮的類名,這樣,路由就能夠配合樣式庫來使用了

 


<router-link to="/" exact>Index</router-link> exact表示精確匹配,只有當哈希值 和 to 屬性的值,徹底相同的時候,這個router-link纔會被添加高亮
 
默認沒有exact屬性的時候,高亮類名添加的方式是模糊匹配,只要哈希值中包含了to屬性的值,那麼,這個router-link就會被添加高亮類名
注意:精確匹配和模糊匹配只對樣式名稱有效,對路由的匹配規則無效

 

動態路由匹配 :將多個哈希值映到同一個組件的狀況,應該使用路由參數


eg   {path : '/news/:id',component : NewsInfo}

 

js中獲取路由參數 (利用$route.params.id 能夠獲取路由參數 )

vue複用了組件,能提高性能,可是複用組件有個問題,created鉤子函數只會在第一次的時候執行,複用的時候不會在被觸發

當切換路由的時候,獲取不到路由的參數,因此這個時候須要利用watch來監視路由參數的變化


watch : {
  $route(to,from){
      對路由變化作出響應
      from 從哪裏
      to   切換到哪去
  }
}
1九、webpack 模塊化打包(構建工具)

兩大職能:

一、打包(構建)

①語法轉換

​ 把less --> css -->讓瀏覽器識別

​ es6 ------>es5 --->瀏覽器可使用

​ TypeScript(TS) ---> es5 ---> 瀏覽器能夠解析

②文件壓縮、合併

​ js、css、html壓縮

​ css、js文件合併,好比將多個css文件合併爲1個css文件,減 少了請求次數,加快響應速度

​ ③提供了開發期間的服務器

​ 自動打開瀏覽器,監聽文件變化,自動刷新瀏覽器等(將 一些繁瑣、複雜、重複的機械性工做自動處理好,咱們只須要關注業務邏輯,實現對應的功能)

二、模塊化

​ 在webpack 看來,全部的資源都是模塊;它爲前端提供了模塊化開發的環境,有了webpack以後,咱們能夠像寫NodeJS代碼同樣,寫前端代碼;引入js/css等文件便可(每一個js文件都是一個獨立的模塊,模塊之間的做用域是隔離的,須要導入和導出來實現兩個模塊之間的數據共享)

​ webpack 可以識別如今前端全部的模塊化語法,無論是require、js(AMD)、nodeJS(CommonJS)、es6等語法,webpack都認識,全均可以解析

​ webpack不只實現JS的模塊化,也實現了css、圖片、視頻等全部前端資源,可使用模塊化的方式來處理

 

webpack的基本使用步驟 一

一、建立一個文件夾 webpack-basic

二、npm init -y 初始化一個package.json文件

三、安裝webpack: npm i -D webpack webpack-cli

四、在package.json 文件中的scripts配置項中,添加一個腳本命令


"scripts": {
"build": "webpack ./src/js/main.js --output ./dist/bundle.js"
},

build 表示構建、打包

webpack 入口文件路徑 --output 出口文件路徑

五、在終端中,經過 npm run build 來執行上面配置好的build 命令;最終打包好的內容就會放在 dist/bundle.js 目錄中

webpack基本使用二

一、安裝:npm i -D webpack webpack-cli

​ webpack 是webpack工具的核心包

​ webpack-cli 提供了命令行程序中打包的命令:webpack

二、在package.json中的scripts添加一個腳本命令:

​ webpack 入口文件路徑 --output 出口文件路徑

​ webpack ./src/js/main.js --output ./dist/bundle.js

三、在終端中,執行命令 npm run build


-D 參數的說明
-D 是 --save-dev 的簡寫,表示:做爲項目開發期間的依賴,它會在package.jsoon文件中生成一個devDependencies 配置項,其中:dev 是development 的簡寫,表示開發的意思
通常一些工具性質的包,都是經過-D參數來安裝的

什麼狀況下會使用 -D 參數?
若是一個包,只是在開發期間使用,應該使用-D參數,來按照這個包
(若是咱們寫的項目代碼中,沒有用到這個包的代碼,這個包應該經過-D 參數來安裝 好比 webpack)


-S 參數的說明
-S 是 --save的簡寫,表示:項目依賴項,也就是咱們寫的項目代碼中,直接使用了這些包的代碼
好比 jquery / expresss
eg npm i express --save
npm i express -s
npm 版本在5以上的,能夠省略不寫
通常能夠不用寫,默認的,直接寫成 npm i express

爲何要將webpack 命令放在scripts

由於沒法直接運行 webpack ./src/js/main.js --output ./dist/bundle.js命令

爲什沒法直接執行webpack 命令?

由於webpack不是全局安裝的,因此,終端中沒法直接識別webpack 這個命令

爲何將webpack命令放在scripts中就能夠運行了

由於scripts腳本命令在執行的時候,會自動的將webpack命令所在目錄,臨時的添加到系統環境變量中,而且在運行命令後,自動將臨時變量移除

爲何不全局安裝webpack

一、好比:電腦中有兩個項目,一個項目用的是webpack 4的版本,一個項目用的是webpack 3的版本,全局安裝不能兼顧,只能顧及到一個

二、全局安裝的包,不會在package.json文件中體現出來,當多人合做完成一個項目的時候,別人沒法知道你全局安裝了什麼包,會致使 項目沒法運行

兩個環境的說明

--mode development 開發期間的環境 --> 在項目開發期間使用 ,代碼沒有被壓縮

--mode production 生成環境(線上環境) --> 項目上線時對項目打包,使用的環境,會對代碼壓縮和優化

命令行語法簡化

webpack 能夠省略出口文件路徑,會自動生成dist文件夾,而且入口文件叫什麼名字,出口文件也叫什麼名字

 

webpack 配置 第一種方式利用命令行

使用步驟:

一、在項目根目錄中,建立webpack的配置文件,webpack.config.js

注意:這個配置文件名稱是固定好的

二、在這個配置文件中添加webpack配置


const path = require('path')

// 導出一個配置對象, webpack 會自動讀取這個配置對象的配置
module.exports = {
// 入口文件路徑
entry: path.join(__dirname, './src/js/main.js'),

// 出口文件路徑
output: {
  // 出口文件所在目錄
  path: path.join(__dirname, './dist'),
  // 出口文件的名稱
  filename: 'bundle.js'
},

// 模式
mode: 'development'
}

三、在scripts中,修改build命令:"build":"webpack"

四、在終端中執行命令 : npm run build

 

webpack-dev-server的基本使用,爲使用webpack的時候,提供了開發期間的服務器環境

webpack-dev-server的使用步驟 (命令行的方式)

一、安裝 : npm i -D webpack-dev-server

二、使用webpack-dev-server

三、在package.json中添加一個新的scripts

​ "dev":"webpack-dev-server"

四、在終端中運行命令: npm run dev

webpack-dev-server作了什麼?

在項目根目錄中開啓了一個服務器,默認的服務器地址爲: http ://localhost:8080

一、自動開啓了一個服務器

二、自動打開服務器

三、自動打開指定目錄中的頁面

四、可以修改默認端口號

五、熱更新

六、自動監視文件變化,自動刷新瀏覽器等


webpack-dev-server的配置項:(在scripts中修改)
  1 開啓服務器的時候,可以自動打開瀏覽器
    "dev": "webpack-dev-server --open"
  2 打開瀏覽器的同時,默認展現 index.html 頁面
    "dev": "webpack-dev-server --open --contentBase ./src"
  3 dev-server 這個命令,是不會生成 dist 目錄的,此時,再引入 dist/bundle.js 文件就沒有意義了
    問題: bundle.js,也就是打包好的內容去哪了??? 被放在 開啓服務器 的根目錄中了,在頁面中,能夠直接經過 /bundle.js 來引用打包好的文件
    爲何不放在磁盤中,而要放在服務器內存中? 性能,由於 內存 性能要比 磁盤 快不少!
    CPU -> 一級緩存/二級緩存/三級緩存 -> 內存 -> 固態硬盤 / 機械硬盤
  4 在修改代碼後,保存文件的時候, dev-server 會自動刷新瀏覽器
    自動監視文件變化,自動刷新瀏覽器
  5 修改默認端口號
    "dev": "webpack-dev-server --open --contentBase ./src --port 3000"
  6 熱更新
    修改了哪一個文件內容,就只更新哪一個文件內容,頁面不會刷新
   
   
  "dev": "webpack-dev-server --open --contentBase ./src --port 3000 --hot"

 

webpack-dev-server 配置文件的使用方式:

webpack-dev-server 配置文件的使用方式: 1 在 webpack.config.js 中,添加配置項 2 修改 package.json 文件中的 dev 腳本:


"dev": "webpack-dev-server --hot"

3 在終端中執行命令: npm run dev


在webpack.config.js的配置
// dev-server配置:
devServer: {
  // 自動打開瀏覽器:
  open: true,
  // 指定打開哪一個目錄中的 index.html 頁面
  contentBase: path.join(__dirname, './src'),
  // 指定端口號
  port: 3001,
  // 熱更新:
  // 第一步:
  hot: true
},

// 指定插件:
plugins: [
  // 熱更新第二步:
  new webpack.HotModuleReplacementPlugin()
]

 

webpack 命令 和 webpack-dev-server 命令的區別:

1 webpack 命令是對項目進行打包,會生成一個 dist 目錄,輸出到磁盤中 2 dev-server 命名是開發期間使用的,也會對項目構建,提供服務器環境,內容沒有輸出到磁盤中,而是放在 開啓的服務器內存 中

何時用webpack命令? 項目完成了,要對項目打包上線,此時應該使用該命令,打包後,只須要將 dist 目錄中的內容部署到服務器中便可,就完成了項目上線


npm run build

何時用 webapck-de-server命令? 開發期間


npm run dev

 

html-webpack-plugin 插件的說明

做用:


1 根據咱們指定的模板文件,在內存中生成一個新的頁面
2 而後,在這個新的頁面中,自動引入 js/css 等文件
而且,最終在瀏覽器中打開的頁面,就是該插件自動生成的頁面

使用步驟: 1 安裝: npm i -D html-webpack-plugin 2 在 webpack.config.js 中添加配置項


// 若是使用了 html-webpack-plugin 插件,那麼,這個配置項就能夠省略了,
  // 由於,此時,打開的頁面已經變爲 html-webpack-plugin 插件在內存中生成的頁面了
  // 指定打開哪一個目錄中的 index.html 頁面
  // contentBase: path.join(__dirname, './src'),

// 添加 html-webpack-plugin 插件實例:
new HtmlWebpackPlugin({
// 指定 html 頁面做爲模板
template: path.join(__dirname, './src/index.html')
})
非js靜態資源的打包處理:

eg : css/less/圖片/字體等

默認狀況下,webapck只能處理js這類的靜態資源,而對於非js的靜態資源須要使用專門loader來處理

 

處理css文件(webpack.config.js中添加配置項)

一、 安裝: npm i -D style-loader css-loader二、 在 webpack.config.js 中,添加配置項來打包處理 CSS 文件

webpack處理css文件的過程:

一、webpack 分析main.js這個入口文件

二、當webpack解析到require(‘../css/index.css’)就知道這個css文件是當前項目的依賴

三、webpack會遍歷module中的全部rules,分別使用每個規則中的test的正則來與當前導入模塊的路徑進行匹配

四、當正則與路徑匹配成功,就使用use指定的loader 來處理這個文件

五、正確處理後,css文件就生效了


// 打包處理非JS資源:
module: {
  // 在 rules 中添加處理資源的配置項:
  rules: [
    // 1 處理 CSS 資源:
    // use 執行的順序是:從右往左,也就是:先指定 css-loader 再執行 style-loader
    // 1.1 css-loader 負責讀取 CSS 文件內容,將其轉化爲一個模塊
    // 1.2 style-loader 讀取模塊中的樣式內容,建立一個 style 標籤,將讀取到的樣式做爲style標籤內容,插入到頁面的 head 標籤中
    { test: /\.css$/, use: ['style-loader', 'css-loader'] }
  ]
}
處理less文件

一、安裝 npm i -D less less-loader​ less 是用來把 less語法轉化爲css​ less-loader 依賴與less 包,用來讀取less文件,內部調用less 文件,轉化less語法

二、在webpack.config.js 添加配置


// 2 處理 less 資源:
    // less-loader 讀取less文件,將其轉化爲 CSS 語法
    { test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] }
打包處理圖片 文件:

步驟:

一、安裝: npm i -D url-loader file-loader

​ url-loader 或 file-loader 二選一便可

二、在webpack.config.js中添加配置項

注意:

一、默認狀況下,圖片在通過url-loader 處理後,會被轉化爲base64編碼的格式

爲何要轉爲base64編碼格式?

由於使用base64後,圖片就直接被嵌入到css樣式中,能夠減小一次額外的圖片請求;可是不是全部的圖片,都須要被轉化爲base64格式的;只有那種很小圖片才須要轉化爲base64,若是是大圖片,不須要轉換爲base64,不然,加載一個大的文件,可能比額外的請求一次圖片還有慢

二、使用file-loader 處理圖片

file-loader 處理後:對文件進行重命名

咱們本身寫的樣式:background-image: url(../images/1.jpg);

file-loader處理後的: background-image:url(9158a14a88d0041fcc6890fa543173ce.jpg)

file-loader內部使用MD5機制來對文件進行重命名

MD5特徵碼提取(加密算法),只要是同一個文件,無論使用MD5提取多少次,獲得的字符串特徵碼都是同樣的

爲何要使用MD5機制來對文件進行重命名?

由於對於圖片相同,可是文件命名不想同的狀況,實際上就是加載了同一張圖片,可是若是不進行重命名就會發送兩次請求,若是重命名,這兩個文件獲得的MD5是同樣的,此時,就只會發送一次請求,也就是減小了請求次數,加快網站的性能


處理 圖片 資源: 這是利用url-loader處理圖片
    注意:若是值有一個 loader,此時,能夠直接使用 字符串形式
    { test: /\.(png|jpg|jpeg|gif)$/, use: 'url-loader' }
    {
      test: /\.(png|jpg|jpeg|gif)$/,
      use: {
        loader: 'url-loader',
        options: {
          // 單位:字節(b)
          // 1024字節 = 1kb
          // 規則:
          // 1 若是圖片的文件大小,比 limit 值小了,此時,圖片會被轉化爲base64
          // 2 若是圖片的文件大小,與 limit 相等或更大,此時,圖片再也不被轉化爲base64
          //   內部會自動調用 file-loader 來處理圖片
          limit: 8106
        }
      }
    },
     
     
這是利用file-loader處理圖片
{ test: /\.(png|jpg|jpeg|gif)$/, use: 'file-loader' }
MD5的說明

在前端,爲了安全,能夠對密碼等敏感數據加密,加密後在發送給服務器,實際上,註冊用戶後,數據是存儲在數據庫中,數據庫中存儲的密碼也是加密後的密碼

MD5只能加密,不能解密的!

MD5 + 隨機字符串(本身指定) = MD5 => 32位字符串 + 隨機字符串 = MD5 => 密碼

打包字體文件:

打包方式 與 打包圖片相同,均可以用 url-loader 或 file-loader 來處理

步驟:


1 安裝: npm i -D url-loader file-loader
2 在 webpack.config.js 中添加規則

字體圖標的使用:


1 導入 字體圖標 庫的樣式
2 在 index.html 頁面中,給元素添加 字體圖標 提供的樣式名稱

webpack.config.js中的配置

 // 處理字體圖標文件
 { test: /\.(eot|svg|ttf|woff|woff2|otf)$/, use: 'url-loader' }


bable轉化語法
 webpack 默認狀況下,只能打包處理 JS 這一類的靜態資源

  可是,若是咱們的項目代碼中用到了 ES6 的新語法,此時,爲了代碼可以在常見的瀏覽器中
  正常運行,應該將 ES6 的語法轉化爲 ES5 語法,而後,再運行在瀏覽器中。

  因此,須要打包處理 ES6 的語法。

  webpack 自身只認識全部的JS模塊化語法,可是,它沒法將 ES6代碼轉化爲ES5代碼。

  若是須要將 ES6 轉化爲 ES5 語法,應該使用: babel 來處理。

  babel的做用:
    1 將 ES6 語法轉化爲 ES5 的語法
      今天就開始使用下一代 JavaScript 語法。( 擁抱將來 )
      好比:
        const fn = a => 1; 轉化爲:var fn = function(a) { return 1; }

    2 實現瀏覽器兼容,也就是說:若是瀏覽器不兼容某個方法,那麼,babel會自動的模擬這個方法的功能來本身實現一份。而後,在這個瀏覽器中就可使用這個功能了
      好比: String.prototype.padStart
            var str = 'abc';
            str.padStart();
  
  babel的使用步驟:
  1 安裝: npm i -D babel-core babel-loader@7
          npm i -D babel-preset-env

  2 在 webpack.config.js 中添加 打包JS 文件規則
  3 在項目根目錄中建立一個 babel 配置文件: .babelrc

  babel-preset-env 表示用來解析全部的標準JS語法,包括了: ES2015/ES2016/ES2017/ES2018...

  JS語法(ECMAScript),每一年都會發布一版,可使用 年份 來做爲版本號,或者使用 數字版本號來表示
    好比: ES6 也就是 ES2015
          ES7 -> ES2016
          ES8 -> ES2017
          ES9 -> ES2018
  通常平時所說的 ES6 就表示全部的新的JS語法

  除了標準的JS語法以外,還有一些不標準可是常常會使用的語法,此時,推薦使用
    babel-preset-stage-2 這個包,來處理
    安裝: npm i -D babel-preset-stage-2

  JS語法提案,須要通過 5 個階段,纔會被採納爲正式標準
    http://es6.ruanyifeng.com/#docs/intro


20、Vue中兩種不一樣的編譯模式

一、完整版:至關於 運行時 + 編譯器

​ 編譯器:用來將模版字符串編譯成爲JavaScript渲染的代碼,能夠理解爲解析Vue實例中的template模版內容,也就是說:只有編譯器才能解析vue實例中的template配置項

​ vue-cli 腳手架中導入的vue是完整版,所以,才能夠解析template配置項

 

二、運行時版:基本上就是除去編譯器的其餘一切

​ 注意:由於運行是版本沒有編譯器,因此,若是用到了運行時版本,是沒法解析vue實例中的template配置項的,而咱們本身配置的webpack中,默認導入vue是隻包含運行時版本的!全部,咱們本身寫的代碼中,只能使用render方法來渲染

在經過import vue from ‘vue'導入vue的時候,默認導入的是:運行時版本,若是要導入完整版的vue,須要在webpack中添加一個 配置項才能夠

2一、Vue中的單文件組件

以.vue 做爲後綴名的文件,就是vue中的單文件組件

爲何要使用單文件組件?

一、原來咱們使用全局組件或者局部組件在使用模版的時候,是純字符串,沒法獲得代碼提示,沒有語法高亮

二、一個組件是由html 、js 、css 樣式組成的,可是這三部分被分離了

三、 原來的方式,限制只能使用 HTML 和 ES5 JavaScript, 而不能使用預處理器,

使用單文件組件的步驟:

一、安裝:npm i -D vue-loader vue-template-compiler

二、在webpack.config.js 中添加loader 規則的配置 以及一個插件

// 打包處理 .vue 文件  配置的規則
      { test: /\.vue$/, use: 'vue-loader' }

插件
// 這個包用來輔助解析 .vue 文件
const VueLoaderPlugin = require('vue-loader/lib/plugin')


三、建立單文件組件

四、建立vue實例,在使用單文件組件

4.1 安裝: npm i vue
4.2 在 main.js 中導入 vue
4.3 建立 Vue 實例
4.4 渲染 App.vue 單文件組件


// 4.2 在 main.js 中導入 vue
// const Vue = require('vue')
// ES6中的 模塊化語法規範!!!
import Vue from 'vue'
// 導入 單文件組件
// const App = require('../App.vue')
import App from '../App.vue'

// 4.3 建立 Vue 實例
const vm = new Vue({
  el: '#app',
  data: {},

  // 4.4 渲染 App.vue 單文件組件
  render: function(createElement) {
    return createElement(App)
  }
})


2二、vue-cli vue的腳手架的使用
由於 webpack 功能很強大,是前端必不可少的打包工具,可是,由於 webpack 配置太繁瑣、太複雜了,這樣,會致使攔住了一些想用Vue可是不會用webpack開發人員。爲了解決這個問題,Vue做者就提供了一個腳手架工具,咱們經過這個工具,只要一條命令,就能夠快速生成一個配置好webpack的Vue項目了。這樣,咱們就不須要本身手動配置webpack,直接使用便可


  • 1 全局安裝: npm i -g vue-cli

  • 2 使用命令,快速生成一個Vue項目: vue init webpack 項目名稱

  • 3 進入項目:cd 項目名稱

  • 4 啓動項目:npm run dev

vue-cli 腳手架工具

vue-cli 項目配置


/*
? Project name (vue-cli-demo) 項目名稱

? Project description (A Vue.js project) 項目描述

? Author (zqran <uuxnet@163.com>) 做者

? Vue build (Use arrow keys) 構建模式
  > Runtime + Compiler: recommended for most users
    Runtime-only: about 6KB lighter min+gzip, but templates (or any Vue-specific HTML) are ONLY allowed in .vue files - render functions are required elsewhere
? Install vue-router? (Y/n) 是否安裝路由,Y 是, n 否

? Use ESLint to lint your code? (Y/n) 語法檢查工具,校驗代碼是否規範
  ? Pick an ESLint preset (Use arrow keys)
    > Standard (https://github.com/standard/standard) 不帶分號
      Airbnb (https://github.com/airbnb/javascript)   更加嚴格,規範寫代碼的方式
      none (configure it yourself)

? Set up unit tests (Y/n) 單元測試,選擇 n
? Setup e2e tests with Nightwatch? (Y/n) 端到端測試,選 n

? Should we run `npm install` for you after the project has been created? (recommended) (Use arrow keys) 是否當即下載依賴項
  > Yes, use NPM
    Yes, use Yarn
    No, I will handle that myself
*/

腳手架生成項目結構說明

├── build/ # webpack 配置├── config/ # webpack 配置├── node_module/ # 項目中安裝的依賴模塊├── src/ # 寫代碼的目錄│ ├── main.js # 程序入口文件│ ├── App.vue # 根組件│ ├── router/ # 路由文件│ ├── components/ # 其餘組件│ └── assets/ # 資源文件夾,通常放一些資源文件,好比:css/圖片等├── static/ # 純靜態資源,不須要webpack處理 (直接拷貝到dist/static/裏面)├── .babelrc # babel 配置文件├── .editorconfig # 編輯配置文件├── .eslintignore # eslint忽略文件├── .eslintrc.js # eslint配置文件├── .gitignore # git配置文件├── .postcssrc.js # postcss配置文件├── index.html # index.html 入口模板文件└── package.json # 項目文件,記載着一些命令和依賴還有簡要的項目描述信息└── 9.md # 介紹本身這個項目的,可參照github上star多的項目。

 

Vue項目說明

學什麼?

  • 1 如何使用 Vue 開發一個項目

  • 2 ElementUI 組件庫的使用

  • 3 業務邏輯(登陸、權限、商品)

建立項目

  • 經過 vue-cli 腳手架工具直接生成一個項目

  • 1 建立:vue init webpack shop-admin

  • 2 配置(根據腳手架的引導來選擇配置項)

  • 3 cd shop-admin

  • 4 啓動項目:npm run devnpm start

手動配置路由(要本身下載 vue-router)

  • 1 安裝:npm i vue-router

  • 2 在 src 目錄中,新建 router 文件夾,在文件中新建 index.js 路由的配置文件

  • 3 在 index.js 中,配置路由,並導出路由實例

  • 4 在 main.js 中導入 路由配置,而且與 Vue實例 關聯到一塊兒

  • 5 在 App.vue 中,添加路由出口

element-ui 組件庫的使用

  • 1 安裝:npm i element-ui

  • 2 在 main.js 中,導入 element-ui、樣式,並安裝插件(在文檔指南中,有element-ui的樣式說明)

  • 3 直接在文檔中找到對應的組件使用便可

項目接口本地搭建

  • 0 解壓 shop-api.zip 文件

  • 1 打開 phpStudy 啓動 MySql 服務

  • 2 打開 navicat for mysql 工具,鏈接數據庫

  • 3 在連接上,點右鍵新建數據庫,數據庫名稱爲:shop_admin

  • 4 雙擊啓用數據庫,再右鍵 運行SQL文件,選中 shop_admin.sql,並導入

  • 5 打開 shop-api 目錄,修改 config/default.json 中的數據庫用戶名和密碼(若是須要)

  • 6 在 shop-api 目錄中,打開終端,輸入:npm start 啓動接口服務

之後天天寫項目以前要作的事情

  • 1 開啓 phpStudy 中的 MySql 服務

  • 2 在 shop-api 目錄中,執行 npm start 啓動接口服務

使用 git 管理項目


# 原始提交到遠程倉庫的命令
git push https://gitee.com/zqran/shop_admin_31.git master
# 有了 remote 後:
git push shop master
# 使用 -u 命令後:
git push shop

# 將 倉庫地址 與 shop 這個名稱關聯到一塊兒
git remote add shop https://gitee.com/zqran/shop_admin_31.git

# -u 就是將 master 設置爲默認,提交的時候,就不須要每次都指定 master 分支了
# -u 命令只須要執行一次便可
git push -u shop master
瀏覽器中的模塊化規範:AMD(require.js)

NodeJS中的模塊化規範:CommonJS( 模塊化規範是全部規範中的一個內容,其實還 包含了不少其餘的規範 ) 這兩個規範,都是由 社區 提出,而且被前端開發者接收使用的,但並非標準!!! 而 ES6 中的模塊化規範,纔是真正的前端模塊化標準,由於,這是從ECMAScript語言規範提出的

在模塊化規範中,每一個JS文件都是一個獨立的模塊

ES6中的模塊化語法: 1 導入模塊

​ import

2 導出模塊

​ export

第一種導入導出語法:

導出:export default str
  default 導出在一個模塊中只能出現一次
  default 導出的內容,在導入的時候,名稱能夠是任意的(也就是 a 能夠是任意名稱)
導入:import a from './a'


第二種導入導出語法:

導出: export const num = 1
  export(非default導出)可使用任意屢次
  export 導出的內容,在導入的時候須要使用 {},而且導出的名稱必須與導入的名稱徹底相同

導入: import { num } from './b'


若是模塊中導出的內容 與 當前模塊中的變量命名衝突,此時,能夠經過 as 語法,來起別名,解決 命名衝突的問題

const num = 666

// 導入b模塊內容
//
// import { num as num1 } from './b'
// console.log('b模塊導出內容爲:', num1, num)

// 一次性導入 b 模塊中的全部內容
import * as b from './b'
console.log(b)


 

登陸訪問控制

一、若是沒有登陸,只能訪問登陸,而不能訪問其餘頁面

二、若是沒有登陸,訪問其餘頁面,應該跳回到登陸頁面

三、若是登陸了,就能夠訪問其餘頁面

如何知道有沒有登陸

一、vue項目中使用‘token' 來做爲登陸成功的標識

只要有token就說明已經登陸了

若是沒有token就說明尚未登陸

二、原來是經過sessionid + cookie機制,來實現登陸狀態保持的

將sessionid存儲到cookie中,這樣,登陸狀態標識(sessionid),就會隨着每一次請求都發送給服務器,服務器從cookie中獲取sessionid,就知道是否登陸過了

這兩種不一樣的機制都是爲了解決同一個問題:登陸狀態保持

爲何須要狀態保持? 由於http協議是無狀態的

如今登陸成功後,須要將token保存起來,存儲到localStorage中,其餘地方用到了,就直接從loaclStroage 中取出來使用就能夠了

補充:token也是有時間限制的,會失效的好比能夠設置半個小時;在瀏覽器中能夠設置順延,好比打開一個頁面,用戶有事出去了,沒有點擊其餘內容,會順延一個時間,不會直接退出(通常而言)

 

 

ref說明 , $refs 是vue提供的一個對象
// this.$refs[formName] 就是在訪問對象 $refs 中的屬性
// this.$refs.loginForm 經過 .語法來訪問對象屬性,與上面經過 [] 


做用: 用來獲取頁面中全部帶有ref屬性的元素(DOM或組件)

做用:添加給 DOM元素或組件,未來能夠經過 this.$refs.ref的值 來獲取到這個DOM對象或組件。而後,就能夠進行DOM操做或獲取組件數據、調用組件方法

爲何要獲取DOM對象或者組件對象?

由於在vue中,有些狀況下,須要手動操做Dom,此時能夠經過ref來獲Dom對象,而後,在進行dom操做

若是給組件添加了ref屬性,那麼能夠經過ref來獲取到組件對象

在當前案例中,就是經過 $refs.loginForm 來獲取到表單組件,調用組件中的 validate 方法,來進行表單驗證
經過 $refs 獲取到組件對象,而且調用組件的 validate 方法,進行表單驗證
      this.$refs[formName].validate(valid => {
        // valid 形參表示:表單驗證是否成功
        if (!valid) {
          // 驗證失敗的時候,代碼中不須要任何處理,由於,錯誤信息都已經在頁面中展現給用戶了
          return false
        }


 

編程式導航--js代碼實現路由跳轉功能
this.$router.push('/home')           字符串的形式
 參數 /home:表示要跳轉到的路由地址
this.$router.push({ name: 'home' })  能夠是一個對象
 經過 name 屬性來實現路由跳轉


 

導航守衛

全局導航守衛:任何一個路由的切換,都會通過全局導航守衛

router.beforeEach((to,from,next)=>{
    to 到哪去,也就是導航到的路由
    from從哪裏來,也就是從哪一個路由切換到了當前路由
    next() 方法是放行的信號,必須調用這個方法,那麼,組件的內容纔會展現在頁面中
 	 其餘使用方式:
    next('/login') 參數 /login 就表示要跳轉到的路由path,也就至關於:跳轉路由
    next('/login')  注意使用next('./xx)跳轉到其餘頁面的時候,必定要開啓next(),否則會一直循環,直到保存,會運行一千屢次後報錯
})


 

props類型的說明

:router = 'true' 此時,router 的值是布爾值類型的

設置爲字符串類型: router = "true"

設置爲數值類型:router="true" 此時,router的值是字符串類型的

嵌套路由使用步驟

一、在建立路由的規則的時候,要配置子路由的規則,而不是普通的路由;子路由是經過路由中的children屬性來配置的

二、在須要切換內容的組件中,添加一個子路由的出口 <router -view>

 

Promise

axios 是基於promise的,實際上axios.get()返回的就是一個promise對象;.then()方法就是promise提供的

promise 是js中實現異步編程的一個解決方案。

在沒有promise以前,咱們是經過回調函數,來實現異步編程的

js是單線程,只能同時作一件事

 

使用回調函數 實現js異步編程的問題:回調地獄

 $.ajax({
            url: '',
            success: function (data) {
              // 在這個回調函數中,就能夠經過 data 異步獲取到服務器返回的數據
              $.ajax({
                url: '',
                success: function (data) {
                  // 在這個回調函數中,就能夠經過 data 異步獲取到服務器返回的數據
                  $.ajax({
                    url: '',
                    success: function (data) {
                      // 在這個回調函數中,就能夠經過 data 異步獲取到服務器返回的數據
                    }
                  })
                }
              })
            }
          })

// 這兩種定時器中也是經過 回調函數 機制,來實現「異步效果」的
    setTimeout(function() {}, 0)
    setInterval(function() {}, 0)


一、回調嵌套回調,看起來很醜(可讀性差)

二、異步體現不直觀(代碼執行順序與正常思惟順序不一致)

三、在解決複雜異步問題時,就變得很棘手

 

promise使用的好處

一、 可讀性更好,不用層層回調嵌套了

2 、看起來更加直觀,由於:使用 Promise 就是以一種同步的方式來編寫異步代碼

三、 很容易解決複雜的異步問題

 

promise的使用:

一、promise是一個構造函數

二、能夠將promise看做一個容器,內部封裝了異步操做

三、promise的參數是一個回調函數

四、回到函數有兩個參數:

​ resolve 表示成功的回調函數,也就是:當異步操做執行成功時,應該調用這個函數

reject 表示失敗的回調函數,也就是,當異步操做執行失敗時,應該調用這個函數

異步操做成功時,調用then中的回調函數

then表示成功,當異步操做成功時,這個回調函數就會調用
理解:Promise內部調用的 resolve 至關於就是調用了then中的回調函數
而且,若是 resolve 調用的時候傳遞了參數,還能夠經過 then 中的回調函數來獲取到這個參數
const p = new Promsie((resolve,reject)=>{ resolve() })
p.then(data=>{ console.log('成功了',data)}) .then(data=>{console.log(data)}) 返回值,能夠做爲下一個then回調函數的參數


異步操做失敗時,調用catch中的回調函數

異步操做失敗時,會調用 catch 中的回調函數
注意:錯誤被 catch 捕獲後,後面的 catch 就不會再執行了
第一種寫法
const p = new Promise((resolve,reject) =>{reject()})
p.catch(err=>{console.log('出錯了')}).catch(()=>{console.log('異步出錯了')})

第二種寫法
能夠指定第二個回調函數,當異步操做失敗了,第二個回調函數的代碼就會執行
p.then(()=>{console.log('成功了')},err=>{console.log('異步操做失敗了')})



promise的狀態

每個promise對象,內部都有三個狀態

1 pending 等待中

2 resolved 成功

3 rejected 失敗

狀態轉換 pendinig ---> resolved 異步操做成功

​ pending ---》 rejected 異步操做失敗

狀態只能改變一次,也就是說,只要狀態發送改變了,就不會再次發生改變

promise中幾個經常使用的方法

需求:有三個異步請求,等到這三個異步請求都完成的時候,再執行某個操做

promise.all([ p,p1,p2]).then(res => { })

 

需求:有三個異步請求,等到其中一個異步請求完成,就執行某個操做

promise.race([ p,p1,p2]).then(res => { })

 

異步編程終極解決方案: async 和 await

這兩個關鍵字用來實現異步編程,是依賴於promise的

async 異步

await 等待

注意: await 只能用在async 函數中

添加async的規則是:就近原則,必定要加在使用await關鍵字的函數中

async就是用來修飾這個函數的,也就是告訴js解析引擎這個函數包含了await 這樣的關鍵字處理的異步操做

await會等到後面的異步操做完成,異步操做完成後,後面的代碼纔會執行

await後面能夠跟任意的表達式,可是通常都會跟着一個promise對象,也就是一個異步操做

 

錯誤處理

try{ } catch (e){ }

 

vue中的插槽 slot

vue中的插槽(slot):能夠在封裝組件時使用組件標籤中的子節點

默認狀況下,組件的子節點是不會出如今頁面中

什麼狀況下會使用插槽?

封裝組件,爲了增長組件的複用性

能夠經過vue中的插槽來使用組件子節點

一、在組件中須要動態變化的地方,添加slot組件(佔位置)

二、將要傳遞的內容做爲組件標籤的子節點

三、slot組件,就會被替換爲組件標籤的子節點

默認slot組件只能使用一次!若是使用屢次,就會報錯

沒有name屬性的插槽,叫作:默認插槽

 

具名插槽

給slot起一個名稱,那麼,在一個組件中,就可使用多個slot了

一、在組件中,使用slot的時候,添加name屬性

二、在給組件標籤添加子節點的時候,質地你哥slot=「插槽的name」

三、這樣的,對應的內容就會顯示在對應的插槽

 

做用域插槽

當使用插槽的時候,組件標籤的子節點內容是要展現在組件中的,也就是說:這些子節點最終是在組件內部使用的,因此,這些子節點中,應該可以使用組件內部的數據

可是默認狀況下,組件標籤子節點中沒法直接使用組件內部的數據!!!

爲何

由於做用域(可否在組件中訪問到某個數據)問題

標籤在哪一個組件的模版中使用的,那麼,它就只能訪問到當前組件的數據

好比: msg-box標籤的子節點p標籤,是寫在vue實例的模版中的,因此,p標籤中只能使用vue實例中的數據

那麼,咱們就說p標籤所在的做用域就是vue實例

咱們但願,在組件模版的外部,直接獲取組件內部的數據,也就是讓:

p標籤 的做用域變爲msg-box組件,爲了達到這個效果,應該使用做用域插槽來實現!

做用域插槽:

一、在組件模版中的slot標籤中,添加要被使用的數據做爲屬性

二、在p標籤(組件外部的標籤)中,添加slot-scope=‘scope’ slot-scope 是固定的屬性名稱值

scope 能夠是任意的名稱,表示要暴露出來的數據的集合(對象)

 

優化axios的使用

一、每次發送請求的時候,都要拷貝完整的基準地址

指望:配置基準地址,在發送請求的時候,只須要填寫當前接口地址

配置基準路徑:

axios.defaults.baseURL = 'http://www.baidu.com'

二、每次發送請求的時候,都須要設置一次請求頭

指望:配置請求頭,在發送請求的時候,就不須要每次都單獨設置請求頭

請求攔截器

說明:由於只要是axios發送的請求,都會執行請求攔截器中的代碼,因此,能夠在請求攔截器中,一次性添加請求頭

axios.interceptors.request.use(config => {
  // 統一添加 Authorization 請求頭
  config.headers.Authorization = localStorage.getItem('token')
  // 必定要返回 config
  return config
}))



三、每一個組件中都要單獨導入axios

指望:導入一次,而不是每一個組件中都要單獨導入

import axios from 'axios'
Vue.prototype.$http = axios


vue 中的template簡單說明

一、它是vue中內置的 組件,不須要咱們註冊這個組件,直接使用便可

二、是一個佔位符(幽靈節點),不會出如今頁面中

做用:包裹多個html元素,template僅僅是一個佔位符,最終渲染在頁面中的時候,template不會出如今頁面中,只有template中的html元素,會顯示在頁面中

vue中的.sync修飾符
一、 sync 單詞:同步
二、 做用:經過添加這個修飾符,能夠實如今組件內部直接修改props
3 、props 是隻讀的,子組件中沒法直接修改 props 值的!!!
4 、原理:經過子到父組件通信機制來實現了 子組件 修改 父組件中的傳遞過來的 props 功能


ES6中的解構

對象的解構 和數組是結構示例

對象的演示
const obj = { name :'jack',age :19}
let {name,age} =obj
console.log(name,age)

解構的同時起別名
age1 就是一個別名,有了別名後,原來的名稱 age 就無效了
  const { name, age: age1 } = obj
  console.log(age1, name)
  
  
演示解構複雜對象
解構出 obj.score.math
const {
score: { math }
	 } = obj
console.log(math)


數組是演示
const arr = [1,2,3,]
獲取全部
const [a,b,c] =arr 
只獲取第二個,第三個參數
const [,b,c] = arr
...b表示獲取全部剩餘的數據,而且是一個數組
const [a, ...b] = arr


 

vue中組件樣式的問題說明

注意:組件中的樣式應該只對當前組件生效,而不是要對其餘組件產生影響!

若是產生影響,產生組件之間樣式衝突、覆蓋等問題

vue中提供了一個scoped,只要給組件的style標籤添加這個屬性,那麼樣式就只會對當前組件生效,而不會影響其餘組件,因此推薦使用組件的時候,給style標籤添加scoped屬性

scoped 原理:動態給組件中的標籤添加一個data-v-組件惟一標識屬性,而且樣式中自動添加了屬性選擇器,由於每一個組件的惟一標識是不同的,因此,樣式就只會對當前組件生效了

 

ES6中是數組擴展運算符和對象擴展運算符
數組
const arr = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
打印數組中的每一項:
console.log(arr[0], arr[1], arr[2....)

使用 數組擴展運算符 :
... 就是數組擴展運算符,做用就是:將數組中的每一項內容分別取出來
console.log(...arr)

 
合併數組,將arr1 和 arr 合併到一塊兒
 const arr1 = [1, 2, 3]
 至關於:['a', 'b', 'c', 'd', 'e', 'f', 'g',  1, 2, 3]
 const newArr = [...arr, ...arr1]


對象的擴展運算符: 
原來 對象的擴展運算符 不是一個標準的JS語法,所以,使用的時候,須要 babel-preset-stage-2 來解析
如今,ES2018 將這個運算符引入了對象
      const obj = {
        name: 'jack'
      }
      const obj1 = {
        age: 19,
        name: 'rose'
      }
      // 先將對象 obj 中的屬性取出來放在新對象中
      // 再將對象 obj1 中的屬性取出來放在新對象中
      // 至關於 淺拷貝
      // 若是有重名的屬性,之後面的屬性爲準
      const newObj = {
        ...obj,
        ...obj1
      }
      console.log(newObj)



 

項目完成以後的操做,打包處理等

Vue項目如何打包?
npm run build
打包後的內容,會被放到 dist 目錄中
上線的時候,就是將 dist 文件夾中的內容,部署到服務器中就能夠了
打包後生成文件,應該放在服務器中運行,而不能直接雙擊頁面打開


默認狀況下打包,打包出來的文件體積很是大!!!
問題:
一、 文件體積大,用戶訪問網站時加載速度慢,等待網站加載時間長
2 、訪問網站的時候,一次性加載全部的資源文件(JS、CSS),這形成了浪費。由於用戶可能只會用到項目中的某一些功能,因此,不必一訪問網站就將全部的內容,所有加載


項目打包的優化:
1 優化打包後的文件體積
解決方式:CDN
打包後,實際上就是 vendor 這個文件的體積很是大
vendor 通常用來表示:第三方文件(vue、vue-router、axios、element-ui、element-tree-grid、vue-quill-editor)
處理思路: 再也不將第三方文件直接打包到 vendor.js 中,而是引用在線的地址來加載這些第三方文件,這樣就能夠解決 vendor 體積太大的問題了

2 按需加載
首屏加載時間是衡量網站性能的一個很重要的指標。
如何提升首屏加載速度? 只加載首屏中用到的內容,而首屏沒有用到的,就不加載。等到用戶看到這些內容的時候在加載
在 Vue 項目中,使用按需加載後,當訪問某個路由的時候,纔會加載這個路由對應的組件的內容
原理:利用 webpack代碼分割 和 Vue異步組件 ,很容易就能夠實現按需加載功能


優化:按需加載的步驟

說明:基於webpack 的代碼分離和vue異步組件

一、修改router文件夾下index.js中導入的語法

把 import Home from '@/components/home/Home'
修改成:
const Home = () =>import('@/components/home/Home')


把組件按組分塊

有時候咱們想把某個路由下的全部組件都打包在同個異步塊 (chunk) 中。只須要使用 命名 chunk,一個特殊的註釋語法來提供 chunk name (須要 Webpack > 2.4)。

const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')


Webpack 會將任何一個異步模塊與相同的塊名稱組合到相同的異步塊中。

二、 (該步可省略)修改 /build/webpack.prod.conf.js 中的 chunkFilename

{
  // [name] 代替 [id]
  chunkFilename: utils.assetsPath('js/[name].[chunkhash].js')
}


 

CDN簡介
CDN(Content Delivery Network):內容分發網絡

對於經常使用的資源(好比:Vue/vue-router/axios 等)這些都是有免費的 CDN 服務的
因此,對於這些文件,咱們項目中直接用就能夠了。

可是,對於咱們公司中本身寫的JS/CSS/圖片等文件,就沒有免費的CDN使用了。
這時候,若是要想使用CDN提供的優點,就須要公司本身花錢買CDN服務。

什麼內容須要被CDN緩存?
JS、CSS、圖片等前端資源
可是對於 接口請求 不能被緩存!!!
好比,有一張圖片已經被CDN緩存了,可是,如今圖片更新了,此時,咱們但願用戶看到最新的圖片,此時,如何解決緩存的問題???
1 只要從 CDN 服務的後臺,清理CDN緩存就好了,也就是說:你購買的CDN服務器後臺,通常都會提供清CDN緩存功能的
2 只要讓新文件的路徑與舊文件的路徑不一樣便可
  好比: a.jpg -> b.jpg
  a.jpg -> a.jpg?t=151231231213 添加時間戳(或者隨機數)查詢字符串,就能夠解決瀏覽器緩存的問題


優化:使用CDN
項目中使用CDN

問題:打包後 vendor(第三方資源文件) 體積過大

  • 緣由:項目中用到了不少的第三方包,這些包在打包的過程當中,所有打包到了 vendor 這個一個JS文件中,致使體積過大

  • 如何優化 vendor 體積? 使用CDN

  • 原理:使用CDN處理第三方包,是引用的在線地址。此時,這些包不會被打包到 vendor 文件中,所以,vendor 體積就會變的更小

CDN使用步驟
  • 1 在 index.html 中引入 CDN 提供的 JS 文件

  • 2 在 /build/webpack.base.conf.js 中(resolve 前面)添加配置 externals

  • 注意:經過 CDN 引入 element-ui 的樣式文件後,就不須要在 main.js 中導入 element-ui 的 CSS 文件了。因此,直接註釋掉 main.js 中的導入 element-ui 樣式便可

externals 配置
externals: {
  // 鍵:表示 導入包語法 from 後面跟着的名稱
  // 值:表示 script 引入JS文件時,在全局環境中的變量名稱
  //  window.Vue / window.axios / window.VueRouter
  vue: 'Vue',
  axios: 'axios',
  'vue-router': 'VueRouter',
  // 注意:帶有樣式文件的第三方包,須要在 代碼中 將樣式註釋掉!!!
  'element-ui': 'ELEMENT',
  'element-tree-grid': 'ElTableTreeColumn',
  'vue-quill-editor': 'VueQuillEditor'

  BMap: 'BMap',
  echarts: 'echarts',
}


經常使用包 CDN
緩存和保留組件狀態

keep-alive

解決方式:使用 keep-alive ,步驟以下:

一、在須要被緩存組件的路由中添加meta屬性 meta屬性用來給路由添加一些元信息(也就是一些附加信息)
{
	path:'/',
	name:'home',
	component:Home,
	須要被緩存
	meta:{keepAlive:true}
}
二、修改路由出口,替換成如下形式,根據meta是否只有keepAlive屬性,決定該路由是否被緩存
<keep-alive>
  <!-- 這裏是會被緩存的視圖組件 -->
  <router-view v-if="$route.meta.keepAlive"> </router-view>
</keep-alive>

<!-- 這裏是不被緩存的視圖組件 -->
<router-view v-if="!$route.meta.keepAlive"> </router-view>



啓動路由的History模式

經過在路由中添加mode:history 能夠去掉 瀏覽器地址欄中的#

在開發期間,只須要添加這個配置便可

可是,在項目打包之後,就會出現問題 ,須要後端配合解決

後端的處理方式

  • 1 優先處理靜態資源

  • 2 對於非靜態資源的請求,所有統一處理返回 index.html

  • 3 當瀏覽器打開 index.html 就會加載 路由的 js 文件,那麼路由就會解析 URL 中的 /login 這種去掉#的路徑了要後端配合解決

反向代理
proxyTable: {
  // 使用:/api/movie/in_theaters
  // 訪問 ‘/api/movie/in_theaters’ ==> 'https://api.douban.com/v2/movie/in_theaters'
  '/api': {
    // 代理的目標服務器地址
    target: 'https://api.douban.com/v2',
    // https請求須要該設置
    secure: false,
    // 必須設置該項
    changeOrigin: true,
    // '/api/movie/in_theaters' 路徑重寫爲:'/movie/in_theaters'
    pathRewrite: {"^/api" : ""}
  }
}


代理服務器原理:

一、目標服務器的地址

二、接口規則,讓代理服務器知道哪些請求須要被代理

 

 

 

 

 

Vuex是專門爲vue提供的狀態管理工具

狀態即數據

狀態管理就是管理vue組件中的數據

內部機制:vuex採用集中式的方式,來統一管理vue中須要共享的數據(即多個組件中都會用到的數據)

vuex中的數據也是響應式的

vuex借鑑了Flux、Redux等狀態管理模式,前端最先的狀態管理思想就是React中的Flux

有什麼用?

使用場景:複雜項目中,解決組件通信的難題

何時用?

一、不要以爲vuex很強大就使用,這是個錯誤的觀點

二、小項目不須要使用vuex

三、只有大型項目或者開發過程當中以爲組件通信太多,管理組件外的數據太麻煩,此時可使用vuex

 

Vuex中的核心概念

store

  • 1 一個Vue項目中只能有一個store(倉庫)

  • 2 store中提供了:1 共享的數據(state) 2 操做數據的方法

  • 3 若是想要修改 store 中的state,應該經過 store 提供的方式,而不能手動修改!!!

state

  • 狀態即數據

  • state 也就是原來 Vue 中的 data

  • 一個Vue項目中應該只有一個state

getters

  • Vuex 的計算屬性

  • 使用方式 與 計算屬性同樣

    • 建立的時候是一個方法

    • 使用的時候是一個屬性 $store.getters.leftCount

mutations

  • 做用:提供修改 state 的方法

  • 說明:數據只能經過 mutations 中提供的方法來修改數據

  • 注意:mutations中只能同步修改數據!!!

actions

  • 做用:封裝異步操做,調用 mutations 修改數據

  • 區分 同步和異步 最本質的區別: 異步操做放在 actions 中能用 devtools 追蹤狀態變化;若是放在 mutations 中是沒法追蹤狀態變化的

相關文章
相關標籤/搜索