【圖文並茂,點贊收藏哦!】重學鞏固你的Vuejs知識體系

前沿

置身世外只爲暗中觀察!!!Hello你們好,我是魔王哪吒!重學鞏固你的Vuejs知識體系,若是有哪些知識點遺漏,還望在評論中說明,讓我能夠及時更新本篇內容知識體系。歡迎點贊收藏!javascript

談談你對MVC、MVP和MVVM的理解?css

github.com/webVueBlog/…html

轉角遇到Vuejs

  1. 你爲啥學習Vuejs
  2. 前端開發的複雜化
  3. Vuejs的特色
  4. 安裝Vuejs
  5. 體驗Vuejs
  6. MVVM架構:data和Vue對象的分離,Vue中的MVVM

目錄:

起步

  1. 插值語法:Mustache,v-once,v-html,v-text,v-pre,v-block。
  2. 綁定屬性:v-bind的介紹,v-bind的基礎,v-bind的語法糖,綁定class,綁定樣式。
  3. 計算屬性
  4. 事件監聽:v-on介紹,v-on基礎,v-on參數,v-on修飾符
  5. 條件和循環:條件渲染,v-show指令,v-if和v-show對比
  6. 表單綁定:基本使用,v-model原理,其餘類型,值綁定,修飾符。

組件化開發:

什麼是組件化,Vue組件化開發思想前端

  1. 註冊的步驟
  2. 全局和局部組件
  3. 父組件和子組件
  4. 註冊組件語法糖
  5. 模板的分離寫法
  6. 組件的其餘屬性
  7. 父級向子級傳遞
  8. 子級向父級傳遞
  9. 父子組件的訪問
  10. 非父子組件通訊

組件化高級語法:

  1. 插槽slot:編譯做用域,爲何使用slot,slot的基本使用,slot的具名插槽,slot的做用域插槽。
  2. 動態組件
  3. 異步組件
  4. 組件聲明週期

Vue Cli

  1. 什麼是webpack
  2. webpack和gulp對比
  3. 手動webpack的配置
  4. Vue Cli是什麼
  5. Vue Cli依賴環境
  6. Vue Cli的安裝

網絡封裝

  1. 使用傳統的Ajax是基於XMLHttpRequest(XHR)
  2. 使用jQuery-Ajax
  3. Vue-resource
  4. 使用axios

axios的使用vue

  1. 瞭解axios:axios請求方式
  2. 發送請求,發送get請求,發送併發請求,axios全局配置,常見配置選項。
  3. axios實例,爲何建立axios實例,如何建立axios實例,axios的封裝。
  4. axios的攔截器:請求和響應

vuejs原理相關:響應式原理,源碼。html5

vue.js是什麼

  • vue是一套用於構建用戶界面的漸進式框架。
  • 從自底向上逐層應用,核心庫是隻關注圖層。
  • 易於學習,便於與第三方庫或既有項目整合。

Vue基礎語法

對於基礎知識須要掌握,簡單寫寫✍java

vue.js安裝

直接CDN引入:node

  1. 對於製做原型或學習

代碼:<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>react

  1. 對於生產環境

代碼:<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>linux

  1. NPM

代碼:

# 最新穩定版
$ npm install vue
複製代碼

vue響應式初體驗

聲明式編程:

代碼:

<!DOCTYPE html>
<!-- 魔王哪吒 -->
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="vue.js" type="text/javascript" charset="UTF-8"></script>
		<!-- <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> -->
	</head>
	<body>
		<div id="app">
		  {{ a }}
		</div>
		
		<script type="text/javascript">
			// 咱們的數據對象
			var data = { a: 1 };
			
			// 該對象被加入到一個 Vue 實例中
			var vm = new Vue({
			  el: "#app",
			  data: data
			});
			
			// data.a = "dada"
			vm.a = "qianduan";
			data.a == vm.a;
		</script>
	</body>
</html>
複製代碼

小案例-計算器

  1. 新的屬性:methods,該屬性是用於Vue對象中定義的方法。
  2. 新的指令:@click,該指令是用於監聽某個元素的點擊事件,而且須要指定當發生點擊時,執行的方法。

代碼:

<div id="app">
    <h1>當前計數{{counter}}</h1>
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
</div>

<script src="../js/vue.js"></script>

<script>
    let app = new Vue({
        el: '#app',
        data: {
            counter: 0
        },
        methods: {
            increment(){
                this.counter++
            },
            decrement(){
                this.counter--
            },
        }
    })
</script>
複製代碼

Vue中的MVVM

MVVM的思想

  1. view是咱們的DOM
  2. Model是咱們抽離出來的obj
  3. ViewModel是咱們建立的Vue對象實例

它們之間是如何工做的呢?

  1. ViewModel經過Data Binding讓obj中的數據實時在DOM中顯示
  2. ViewModel經過DOM Listener來監聽DOM事件,而且經過methods中的操做,來改變obj中的數據

  • el:類型:string | HTMLElement
  • 做用:決定以後Vue實例會管理哪個DOM
  • data:類型:Object | Function
  • 做用:Vue實例對應的數據對象
  • methods:類型:{[key:string]:Function}
  • 做用:定義屬於Vue的一些方法,能夠在其餘地方調用,也能夠在指令中使用。

什麼是Vue的生命週期

生命週期:☞ 事物從誕生到消亡的整個過程

  • release穩定版本
  • debug版本
  1. Mustache語法也就是雙大括號
  2. 插值操做
  3. 綁定屬性
  4. 計算屬性
  5. 事件判斷
  6. 循環遍歷
  7. 階段案例
  8. v-model

v-once指令的使用

<div id="app">
 <h1>{{message}}</h1>
 <h2 v-once>{{message}}</h2>
</div>
複製代碼

v-once

  1. 該指令後面不須要跟任何表達式
  2. 該指令表示元素和組件只渲染一次,不會隨着數據的改變而改變

v-html

當咱們從服務器請求到的數據自己就是一個HTML代碼時

  1. 若是直接經過{{}}來輸出,會將HTML格式進行解析,而且顯示對應的內容。
  2. 可使用v-html指令
  3. 該指令後跟上一個string類型
  4. 會將stringhtml解析處理而且進行渲染
<h1 v-html="url"></h1>
複製代碼

v-text的做用和Mustache比較類似,獨使用於將數據顯示在界面中,通常狀況下,接受一個string類型。

<div id="app">
 <h2 v-text="message"></h2>
 <h2>{{message}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
 let vm = new Vue({
    el: '#app',
    data: {
        message: '你好'
    }
 })
</script>
複製代碼

v-pre用於跳過這個元素和它子元素的編譯過程,用於顯示本來的Mustache語法。

<div id="app">
 <p v-pre>{{message}}</p>
</div>
<script src="../js/vue.js"></script>
<script>
 let app = new Vue({
  el: '#app',
  data: {
      message: 'hello'
  }
 })
</script>
複製代碼

v-cloak斗篷的意思。

<div id="app">
 <h2 v-cloak>hello{{name}}</h2>
</div>
<script>
 setTimeout(()=>{
     let app = new Vue({
      el: '#app',
      data: {
          name: 'web'
      }
     })
 },10000)
</script>

<style>
 [v-cloak] {
     display: none;
 }
</style>
複製代碼

v-bind的介紹

v-bind用於綁定一個或多個屬性值,或者向另外一個組件傳遞props值。

<div id="app">
 <a v-bind:href="link">vuejs</a>
 <img v-bind:src="url" alt="">
</div>

<script>
 let app = new Vue({
  el: '#app',
  data: {
      
  }
 })
複製代碼

v-bind語法糖

v-bind有一個對應的語法糖,就是簡寫方式

<div id = "app">
    <a :href="link">vuejs</a>
    <img :src="longURL" alt="">
</div>
複製代碼

v-bind動態綁定class

<style>
 .active{
     color: red;
 }
</style>

<div id="app">
 <h1 class="active">{{message}}</h2>
</div>

<script>
 const app = new Vue({
  el: '#app',
  data: {
      message: 'hello'
  }
 })
</script>
複製代碼

綁定class有兩種方式:

  1. 對象語法
  2. 數組語法

對象語法:

用法一:直接經過{}綁定一個類
<h2 :class="{'active': isActive}">hello</h2>

用法二,傳入多個值
<h2 :class="{'active': isActive, 'line': isLine}">hello</h2>

用法三:
<h2 class="title" :class="{'active': isActive}"></h2>

用法四:
能夠放在一個methods或者computed中
<h2 class="title" :class="classes">hello</h2>
複製代碼

v-bind動態綁定class,數組語法

<div id="app">
 <h2 class="title" :class="[active, line]">{{mesg}}</h2>
 <h2 class="title" :class="getClasses()">{{mesg}}</h2>
</div>

<script>
 const app = new Vue({
     el: '#app',
     data: {
         message: 'hello',
         active: 'aaa',
         line: 'bbb',
     },
     methods: {
         getClasses: function() {
             return [this.active, this.line]
         }
     }
 })
</script>
複製代碼

v-bind動態綁定style

對象語法和數組語法兩種綁定。

綁定方法:對象語法:

:style="{ color: currentColor, fontSize: fontSize + 'px' }"
複製代碼

style後面跟的是一個對象類型,對象的keycss屬性名稱,對象的value是具體賦的值,值能夠來自於data中的屬性。

綁定方法:數組語法:

<div v-bind:style="[baseStyles, overStyles]"></div>
複製代碼

style後面跟的是一個數組的類型,多個值,分割便可。

計算屬性的基本屬性

計算屬性,寫在實例的computed選項中:

<div id="app">
 <h2>{{firstName}}{{lastName}}</h2>
</div>

<script>
 const vm = new Vue({
  el: '#app',
  data: {
      firstName: 'web',
      lastName: 'it',
  }
 })
</script>
複製代碼
<div id="app">
 <h2>{{fullName}}</h2>
</div>

<script>
 const vm = new Vue({
  el: '#app',
  data: {
      firstName: 'jeskson',
      lastName: 'it',
  },
  computed: {
      fullName() {
          return this.firstName + ' ' + this.lastName
      }
  }
 })
</script>
複製代碼

計算屬性的緩存:

爲何使用計算屬性這個東西?

緣由:計算屬性會進行緩存,若是屢次使用時,計算屬性只會調用一次。

setter和getter

每一個計算屬性都包含一個getter和一個setter

<div id="app">
 <div>{{fullName}}</div>
 <div>{{firstName}}</div>
 <div>{{lastName}}</div>
</div>

<script>
 let vm = new Vue({
  el: '#app',
  data: {
      firstName: 'web',
      lastName: 'it',
  },
  computed: {
      fullName: {
          get() {
              rturn this.firstName+" "+this.lastName
          },
          set(newValue){
              const names = newValue.split(' ')
              this.firstName = names[0]
              this.lastName = names[1]
          }
      }
  }
 })
</script>
複製代碼
computed: {
    fullName: function() {
        return this.firstName+" "+this.lastName
    }
    
    // 計算屬性通常是沒有set方法,只讀屬性。
    fullName: {
        get: function() {
            return this.firstName + " " + this.lastName
        }
    }
}
複製代碼

const的使用

const的使用,在JavaScript中使用const修飾的標識符爲常量,不能夠再次賦值。

在es6開發中,優先使用const,只有須要改變一個標識符的時候才使用let。

在使用cost定義標識符,必須進行賦值。

常量的含義是指向的對象不能修改,可是能夠改變對象內部的屬性。

何時使用const呢?

當咱們修飾的標識符不會被再次賦值時,就可使用const來保證數據的安全性。

const的使用:

const a=20;
a = 10; // 錯誤:不能夠修改

const name; // 錯誤,const修飾的標識符必須賦值
複製代碼

let和var

塊級做用域:

JS中使用var來聲明一個變量,變量的做用域主要是和函數的定義有關。

對於其餘塊定義來講是沒有做用域的,好比if/for等,開發中每每會引起一些問題。

// 監聽按鈕的點擊
var btns = document.getElementsByTagName('button');
for(var i=0; i<btns.length; i++) {
    (function(i){
        btns[i].onclick = function(){
            alert('點擊了'+i+"個")
        }
    })(i)
}
複製代碼
let btns = document.getElementsByTagName('button');
for(let i=0;i<btns.length;i++){
    btns[i].onclick = function(){
        alert('點擊了'+i+'個')
    }
}
複製代碼

塊級做用域

變量做用域:變量在什麼範圍內是可用的。

var func;
if(true) {
    var name = 'web';
    func = function() {
        console.log(name); // web
    }
    
    func(); // web
}

// name = 'it'
func(); // web -> it
console.log(name); // web -> it
複製代碼

沒有塊級做用域引發的問題,for的塊級

var btns = document.getElementsByTagName('button');
for(var i=0; i<btns.length; i++) {
    btns[i].addEventListener('click', function(){
        console.log('第'+i+'個按鈕被點擊');
    })
}
複製代碼

閉包:

var btns = document.getElementsByTagName('button');
for(var i=0; i<btns.length;i++){
    (function(i){
        btns[i].addEventListener('click', function(){
          console.log('第'+i+'個按鈕');  
        })
    })(i)
}
複製代碼

爲何閉包能夠解決問題,由於函數是一個做用域。

對象的加強寫法

屬性初始化簡寫和方法的簡寫:

// 屬性的簡寫
// es6前
let name = 'web'
let age = 12
let obj1 = {
    name: name,
    age: age,
}
console.log(obj1);
// es6後
let obj2 = {
    name, age
}
console.log(obj2)
複製代碼
// 方法的簡寫
// es6以前
let obj1 = {
    test: function() {
        console.log('obj1')
    }
}
obj1.test();

// es6後
let obj2 = {
    test() {
        console.log('obj2')
    }
}
obj2.test();
複製代碼

v-on基礎

v-on:click="counter++"

<div id="app">
 <h2>點擊次數:{{counter}}</h2>
 <button v-on:click="counter++">按鈕點擊</button>
 <button v-on:click="btnClick">按鈕點擊2</button>
</div>

let app = new Vue({
 el: '#app',
 data: {
     counter: 0
 },
 methods: {
     btnClick(){
         this.counter++
     }
 }
})
複製代碼

v-on修飾符的使用

<div id="app">
 <div @click="divClick">
 web
 <button @click.stop="btnClick">按鈕</button>
</div>
複製代碼

Vue提供了一些修飾符:

.stop 調用event.stopPropagation()

.prevent 調用event.preventDefault()

.native 監聽組件根元素的原生事件

.once 只觸發一次回調
複製代碼
// 中止冒泡
<button @click.stop="doThis"></button>

// 阻止默認行爲
<button @click.prevent="doThis"></button>

// 阻止默認行爲,沒有表達式
<form @submit.prevent></form>

// 串聯修飾符
<button @click.stop.prevent = "doThis"></button>

// 鍵修飾符,鍵別名
<input @keyup.enter="onEnter">

// 鍵修飾符,鍵代碼
<input @keyup.13="onEnter">

// 點擊回調智慧觸發一次
<button @click.once="doThis"></button>
複製代碼

v-if,v-else-if,v-else

簡單使用:

<div id="app">
 <p v-if="score>=90">優秀</p>
 <p v-else-if="score>=80">良好</p>
 <p v-else-if="score>=60">及格</p>
 <p v-else="score<60">不及格</p>
</div>
複製代碼

登陸切換:

<div id="app">
 <span v-if="type==='username'">
  <label>用戶帳號:</label>
  <input placeholder="用戶帳戶">
 </span>
 <span v-else>
  <label>郵箱地址:</label>
  <input placeholder="郵箱地址">
 </span>
 <button @click="handleToggle">切換類型</button>
</div>

<script>
 let app = new Vue({
  el: '#app',
  data: {
      type: 'username'
  },
  methods: {
      handleToggle(){
          this.type = this.type === 'email' ? 'username' : 'email'
      }
  }
 })
</script>
複製代碼
<div id="app">
 <span v-if="isUser">
  <label for="username">用戶帳戶</label>
  <input type="text" id="username" placeholder="用戶帳戶">
 </span>
 
 <span v-else>
  <label for="email">用戶郵箱</label>
  <input type="text" id="email" placeholder="用戶郵箱">
 </span>
 <button @click="isUser=!isUser">切換類型</button>
</div>

<script>
const app = new Vue({
 el: '#app',
 data: {
     isUser: true
 }
})
</script>
複製代碼

v-for遍歷對象

<div id="app">
 <ul>
  <li v-for="(value, key, index) in info">
   {{value}}-{{key}}-{{index}}
  </li>
 </ul>
</div>

<script>
 let app = new Vue({
  el: '#app',
  data: {
      info: {
          name: 'web',
          age: 12,
      }
  }
 })
</script>
複製代碼

組件的Key屬性

使用v-for時,給對應的元素或組件添加上一個:key屬性。

key的做用主要是爲了高效的更新虛擬dom。

數組中哪些方法是響應式的

push()
pop() 刪除數組中的最後一個元素
shift() 刪除數組中的第一個元素
unshift() 在數組最前面添加元素

splice()
sort()
reverse()
複製代碼

購物車

<div id="app">
<table>
<thead>
<tr>
<th></th>
<th>書籍名稱</th>
<th>出版日期</th>
<th>價格</th>
<th>購買數量</th>
<th>操做</th>
</tr>
</thead>
<tbody>
<tr v-for="item in books">
<td v-for="value in item">{{value}}</td>
</tr>
</tbody>
</table>
</div>
複製代碼

表單綁定v-model

vue中使用v-model指令來實現表單元素和數據的雙向綁定。

<div id="app">
 <input type="text" v-model="message">
 <h2>{{message}}</h2>
</div>
複製代碼

reduce做用對數組中全部的內容進行彙總。

JavaScript reduce() 方法

var numbers = [65, 44, 12, 4];
 
function getSum(total, num) {
    return total + num;
}
function myFunction(item) {
    document.getElementById("demo").innerHTML = numbers.reduce(getSum);
}
複製代碼

定義和用法

reduce() 方法接收一個函數做爲累加器,數組中的每一個值(從左到右)開始縮減,最終計算爲一個值。

reduce() 能夠做爲一個高階函數,用於函數的 compose。

注意: reduce() 對於空數組是不會執行回調函數的。

語法

array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
複製代碼

v-model的使用以及原理

<input type="text" :value="message" @input="message = $event.target.value">

<script>
 const app = new Vue({
  el: '#app',
  data: {
      message: '你好啊'
  },
  methods: {
      valueChange(event){
          this.message = event.target.value;
      }
  }
 })
</script>
複製代碼

v-model是語法糖,本質:

  1. v-bind綁定一個value屬性
  2. v-on指令給當前元素綁定input事件

代碼:

<input type="text" v-model="message">

<input type="text" v-bind:value="message" v-on:input="message = $event.target.value">
複製代碼

v-model:checkbox

複選框分爲兩種狀況,單個勾選框和多個勾選框。

單個勾選框:

v-model即爲布爾值。inputvalue並不影響v-model的值。

多個複選框:

當是多個複選框時,對應的data中屬性是一個數組。

當選中某一個時,就會將inputvalue添加到數組中。

<div id="app">
 <label for="check">
  <input type="checkbox" v-model="checked" id="check">贊成協議
 </label>
 <label><input type="checkbox" v-model="hobbies" value="籃球">籃球</label>
 <label><input type="checkbox" v-model="hobbies" value="檯球">檯球</label>
</div>
複製代碼

v-model:select

select分單選和多選兩種狀況

單選:只能選中一個值,多選:能夠選擇多個值。

v-model結合select類型

checkbox同樣,select分單選和多選兩種狀況。

單選,只能選擇一個值,v-model綁定的是一個值。當咱們選中option中的一個時,會將它對應的value賦值到mySelect中。

多選,能夠選中多個值。v-model綁定的是一個數組。當選中多個值時,就會將選中的option對應的value添加到數組mySelects中。

// 選擇一個值
<select v-model="mySelect">
 <option value="web">web</option>
 <option value="it">it</option>
</select>
<p>您最喜歡的{{mySelect}}</p>

// 選擇多個值
<select v-model="mySelects" multiple>
 <option value="web">web</option>
 <option value="it">it</option>
</select>
<p>您最喜歡的{{mySelects}}</p>
複製代碼

input中的值綁定

<label v-for="item in origin">
 <input type="checkbox" :value="item" v-model="hobbies">
 {{item}}
</label>
複製代碼

修飾符

lazy修飾符:

  1. 默認狀況下,v-model默認是在input事件中同步輸入框的數據的。
  2. 一旦有數據發生改變對應的data中的數據就會自動發生改變。
  3. lazy修飾符可讓數據在失去焦點或者回車時纔會更新。

number修飾符:

  1. 默認狀況下,在輸入框中不管咱們輸入的是字母仍是數字,都會被當作字符串類型進行處理。
  2. 可是若是咱們但願處理的是數字類型,那麼最好直接將內容當作數字處理。
  3. number修飾符可讓在輸入框中輸入的內容自動轉成數字類型。

trim修飾符:

  1. 若是輸入的內容首尾有不少空格,一般咱們但願將其去除
  2. trim修飾符能夠過濾內容左右兩邊的空格

示例:

<div id="app">
 <input type="text" v-model.lazy="message">
 <h2>{{message}}</h2>
</div>
複製代碼

什麼是組件化

  1. 組件化是vue.js中的重要思想
  2. 它提供了一種抽象,讓咱們能夠開發出一個個獨立可複用的小組件來構造咱們的應用
  3. 任何的應用都會被抽象成一顆組件樹

註冊組件的基本步驟:

  1. 建立組件構造器
  2. 註冊組件
  3. 使用組件

示例:

調用Vue.extend()方法建立組件構造器
調用Vue.component()方法,註冊組件
在Vue實例的做用範圍內使用組件
複製代碼

組件示例:

<div id="app">
<my-cpn></my-cpn>
</div>

<script src="../js/vue.js"></script>
<script>
 // 建立組件構造器
 const myComponent = Vue.extend({
    template: `
     <div>
      <h2>組件標題</h2>
      <p>組件段落</p>
     </div>`
 });
 
 // 註冊組件
 Vue.component('my-cpn',myComponent);
</script>
複製代碼

全局組件和局部組件

  1. Vue.extend()調用Vue.extend()建立一個組件構造器。
  2. 一般在建立組件構造器時,傳入template表明咱們自定義組件的模板。
  3. 該模板在使用到組件的地方,顯示的html代碼。
  4. 這種寫法在Vue2.x的文檔幾乎看不到了。
  5. Vue.component()是將剛纔的組件構造器註冊爲一個組件,而且給它起一個組件的標籤名稱。
  6. 註冊組件的標籤名,組件構造器。

示例:

組件標題

<div id="app">
 <my-cpn><my-cpn>
 <div>
  <my-cpn><my-cpn>
 </div>
</div>
複製代碼

示例:

<div id="app1">
 <my-cpn></my-cpn>
</div>
<div id="app2">
 <my-cpn></my-cpn>
</div>

<script src="../js/vue.js"></script>
<script>
// 建立組件構造器
const myComponent = Vue.extend({
    template: `
    <div>
     <h2>web</h2>
    </div>
    `
})
// 註冊組件
Vue.component('my-cpn',myComponent);
let app1 = new Vue({
 el: '#app1'
})
let app2 = new Vue({
 el: '#app2'
})
複製代碼
<div id="app1">
 <my-cpn></my-cpn>
</div>
<div id="app2"> // 沒有被渲染出來
 <my-cpn></my-cpn>
</div>
<script src="../js/vue.js"></script>
<script>
// 建立組件構造器
const myComponent = Vue.extend({
 template: `
 <div>
  <h2>web</h2>
 </div>
 `
 })
 let app1=new Vue({
  el: '#app1',
  components: {
      'my-cpn': myComponent
  }
 })
 let app2 = new Vue({
  el: '#app2'
 })
</script>
複製代碼

父組件和子組件

組件樹

  1. 組件和組件之間存在層級關係
  2. 其中一種很是重要的關係就是父子組件的關係

示例:

<div id="app">
 <parent-cpn></parent-cpn>
</div>
<script src="../js/vue.js"></script>
<script>
 // 建立一個子組件構造器
 const childComponent = Vue.extend({
  template: `
  <div>我是子組件的內容</div>
  `
 })
 // 建立一個父組件的構造器
 const parentComponent = Vue.extend({
  template: `
  <div>
  我是父組件的內容
  <child-cpn></child-cpn>
  </div>
  `
  components: {
      'child-cpn': childComponent
  }
 })
 let app = new Vue({
  el: '#app',
  components: {
      'parent-cpn': parentComponent
  }
 })
複製代碼

註冊組件的語法糖

示例:全局組件

<div id="app">
 <cpn1></cpn1>
</div>
<script>
 // 全局組件註冊的語法糖
 // 註冊組件
 Vue.component('cpn1', {
  template: `
  <div>
   <h2>web</h2>
  </div>
  `
 })
 const app = new Vue({
  el: '#app',
  data: {
      message: 'web',
  }
 })
</script>
複製代碼
<div id="app">
 <cpn2></cpn2>
</div>
// 註冊局部組件的語法糖
const app = new Vue({
 el: '#app',
 data: {
     message: 'web'
 },
 components: {
     'cpn2': {
         template: `
         <div>
          <h1>web</h1>
         </div>
         `
     }
 }
})
</script>
複製代碼

vue簡化了註冊組件的方式,提供了註冊的語法糖。

組件模板抽離的寫法

vue提供了兩種定義html模塊內容:

  1. 使用<script>標籤
  2. 使用<template>標籤

示例:

<div id="app">
 <my-cpn></my-cpn>
</div>

<script type="text/x-template" id="myCpn">
 <div>
  <h2>web</h2>
 </div>
</script>

<script src="../js/vue.js"></script>
<script>
 let app = new Vue({
  el: '#app',
  components: {
      'my-cpn': {
          template: '#myCpn'
      }
  }
 })
</script>
複製代碼

template標籤

<template id="cpn">
 <div>
  <h2>web</h2>
 </div>
</template>
// 註冊一個全局組件
Vue.component('cpn', {
 template: '#cpn'
})
複製代碼

組件能夠訪問vue實例數據嗎

組件是一個單獨的功能模塊封裝,有屬於本身的html模板和本身的數據data

組件對象有一個data屬性,methods屬性,這個data屬性必須是一個函數,函數返回一個對象,對象內部保存着數據。

<div id="app">
 <my-cpn></my-cpn>
</div>

<template id="myCpn">
 <div>{{message}}</div>
</template>
<script src="..."></script>
<script>
let app = new Vue({
 el: '#app',
 components: {
     'my-cpn': {
         template: 'myCpn',
         data() {
             return{
                 message: 'web'
             }
         }
     }
 }
})
複製代碼

父子通訊-父傳子props

如何進行父子組件間的通訊呢?

  1. 經過props向子組件傳遞數據
  2. 經過事件向父組件發送消息

props基本用法

在組件中,使用props來聲明從父級接收到的數據

props的值:

  1. 字符串數組,數組中的字符串就是傳遞時的名稱。
  2. 對象,對象能夠設置傳遞時的類型,也能夠設置默認值等。

camelCase (駝峯命名法) 的 prop 名須要使用其等價的 kebab-case (短橫線分隔命名) 命名:

Vue.component('blog-post', {
  // 在 JavaScript 中是 camelCase 的
  props: ['postTitle'],
  template: '<h3>{{ postTitle }}</h3>'
})
<!-- 在 HTML 中是 kebab-case 的 -->
<blog-post post-title="hello!"></blog-post>
複製代碼

重申一次,若是你使用字符串模板,那麼這個限制就不存在了。

prop 各自的名稱和類型:

props: {
 title: String,
 likes: Number,
 isPublished: Boolean,
 commentIds: Array,
 author: Object,
 callback: Function,
 contactsPromise: Promise // or any other constructor
}
複製代碼
<!-- 動態賦予一個變量的值 -->
<blog-post v-bind:title="post.title"></blog-post>

<!-- 動態賦予一個複雜表達式的值 -->
<blog-post
  v-bind:title="post.title + ' by ' + post.author.name"
></blog-post>

<!-- 即使 `42` 是靜態的,咱們仍然須要 `v-bind` 來告訴 Vue -->
<!-- 這是一個 JavaScript 表達式而不是一個字符串。-->
<blog-post v-bind:likes="42"></blog-post>

<!-- 用一個變量進行動態賦值。-->
<blog-post v-bind:likes="post.likes"></blog-post>
複製代碼

傳入一個對象的全部屬性

若是你想要將一個對象的全部屬性都做爲 prop 傳入,你可使用不帶參數的 v-bind (取代 v-bind:prop-name)

post: {
  id: 1,
  title: 'My Journey with Vue'
}

<blog-post v-bind="post"></blog-post>

<blog-post
  v-bind:id="post.id"
  v-bind:title="post.title"
></blog-post>
複製代碼

一個簡單的props傳遞:

<div id="app">
 <child-cpn :message="message"></child-cpn>
</div>

<template id="childCpn">
 <div> 顯示信息:{{message}}</div>
</template>

<script>
let app = new Vue({
 el: '#app',
 data: {
     message: 'hello'
 },
 components: {
     'child-cpn': {
         templte: '#childCpn',
         props: ['message']
     }
 }
})
</script>
複製代碼

Vue 中,父子組件的關係

props向下傳遞,事件向上傳遞。

父組件經過 props給子組件下發數據,子組件經過事件給父組件發送消息。

props支持的數據類型:

String

Number

Boolean

Array

Object

Date

Function

Symbol
複製代碼

示例:

Vue.component('my-component',{
 props: {
     // 基礎的類型檢查
     propA: Number,
     // 多個可能的類型
     propB: [String, Number],
     // propC: {
         type: String,
         required: true
     },
     // 帶有默認值的數字
     propD: {
         type: Number,
         default: 100
     },
     // 帶有默認值的對象
     propE: {
         type: Object,
          default: function(){
              return {message: 'web'}
          }
     },
     // 自定義驗證函數
     propF: {
         vfunc: function(value) {
             return value > 1
         }
     }
 }
})
複製代碼

子傳父

代碼:

this.$emit('item-click',item)
複製代碼

props用於父組件向子組件傳遞數據,還有一種比較常見的是子組件傳遞數據或事件到父組件中。

自定義事件:

  1. 在子組件中,經過$emit()來觸發事件。
  2. 在父組件中,經過v-on來監聽子組件事件。

自定義事件代碼:

<div id="app">
 <child-cpn @increment="changeTotal" @decrement="changeTotal"></child-cpn>
 <h2>點擊次數</h2>
</div>

<template id="childCpn">
 <div>
  <button @click="increment">+1</button>
  <button @click="decrement">-1</button>
 </div>
</template>

let app = new Vue({
 el: '#app',
 data: {
     total: 0
 },
 methods: {
     changeTotal(counter) {
         this.total = counter
     }
 },
 components: {
     'child-cpn': {
         template: '#childCpn',
         data(){
             return{
                 counter: 0
             }
         },
         methods: {
             increment(){
                 this.counter++;
                 this.$emit('increment', this.counter)
             },
             decrement(){
                 this.counter--;
                 this.$emit('decrement',this.counter)
             }
         }
     }
 }
})
複製代碼

父子組件的訪問方式:$children

有時候須要父組件直接訪問子組件,子組件直接訪問父組件,或者是子組件訪問父組件。

  1. 父組件訪問子組件,使用$children或者$refs
  2. 子組件訪問父組件,使用$parent

對於$children的訪問:

  1. this.$children是一個數組類型,它包含全部子組件對象。
  2. 經過遍歷,取出全部子組件的message狀態。

示例:

<div id="app">
 <parent-cpn></parent-cpn>
</div>

// 父組件template
<template id="parentCpn">
 <div>
  <child-cpn1></child-cpn1>
  <child-cpn2></child-cpn2>
  <button @click="showChildCpn">顯示全部子組件信息</button>
 </div>
</template>

// 子組件
<template id="childCpn1">
 <h2>我是子組件1</h2>
</template>
// 子組件
<template id="childCpn2">
 <h2>我是子組件2</h2>
</template>

Vue.component('parent-cpn',{
 template: '#parentCpn',
 methods: {
     showChildCpn(){
         for(let i=0; i<this.$children.length; i++){
             console.log(this.$children[i].message)
         }
     }
 }
})
複製代碼

父子組件的訪問方式:$parent

子組件中直接訪問父組件,能夠經過$parent

  1. 雖然能夠經過$parent來訪問父組件,可是儘可能不要這樣作
  2. 子組件應該儘可能避免直接訪問父組件的數據,由於這樣耦合度過高了。

父子組件的訪問方式$refs

$children的缺陷:

  1. 經過$children訪問子組件,是一個數組類型,訪問其子組件要經過索引值。
  2. 子組件過多時,須要拿其中一個時,不能肯定它的索引值,還可能發生變化。
  3. 獲取其中一個特定的組件,可使用$refs

$refs的使用:

  1. $refsref指令一般一塊兒使用
  2. 經過ref給某個子組件綁定一個特定的id
  3. 經過this.$refs.id能夠訪問到該組件

示例:

<child-cpn1 ref="child1"></child-cpn1>
<child-cpn2 ref="child2"></child-cpn2>
<button @click="show">經過refs訪問子組件</button>

show() {
    console.log(this.$refs.child1.message);
    console.log(this.$refs.child2.message);
}
複製代碼

看看一個.vue文件項目

<template>
 <div class="xxx">
  <div class="xxx"
   :class="{active: currentIndex === index}"
   @click="itemClick(index)"
   v-for="(item,index) in titles">
   <span>{{item}}</span>
   </div>
  </div>
</template>

<script>
 export default {
     name: 'xxx',
     props: {
         titles: {
             type: Array,
             default() {
                 return []
             }
         }
     },
     data: function() {
         return {
             currentIndex: 0
         }
     },
 }
</script>

<style scoped>
 .xxx {
     xxx: xxx;
 }
</style>
複製代碼

三層部分:

slot插槽的使用

vue中的代碼slot是什麼呢,它叫插槽,<slot>元素做爲組件模板之中的內容分發插槽,傳入內容後<slot>元素自身將被替換。

v-slot用法:

  1. 默認插槽
  2. 具名插槽
  3. 做用域插槽
  4. slot以及slot-scope的用法:子組件編寫,父組件編寫

默認插槽

子組件:

// 子組件
<template>
<div class="content">
// 默認插槽
<content-box class="text">
<slot>默認值</slot>
<content-box>
</div>
</template>
複製代碼

slot基本使用

  1. 在子組件中,使用<slot>能夠爲子組件開啓一個插槽。
  2. 該插槽插入什麼內容取決於父組件如何使用。

子組件定義一個插槽:

  1. <slot>中的內容表示,若是沒有在該組件中插入任何其餘內容,就默認顯示改內容。

示例:

<div id="app">
 <my-cpn></my-cpn>
 <my-cpn>
  <p>web</p>
 </my-cpn>
</div>

<template id="myCpn">
 <div>
  <slot>我是誰</slot>
 </div>
</template>
<script>
Vue.component('my-cpn',{
 template: '#myCpn'
})

let app = new Vue({
 el: '#app'
})
</script>
複製代碼

使用具名插槽

  1. slot元素添加一個name屬性
  2. <slot name="web"></slot>

示例:

<div id="app">
 // 沒有任何內容
 <my-cpn></my-cpn>
 
 // 傳入某個內容
 <my-cpn>
  <span slot="left">left</span>
 </my-cpn>
 
 <my-cpn>
  <span slot="left">left</span>
  
  <span slot="center">center</span>
  
  <span slot="right">right</span>
</div>

<template id="myCpn">
 <div>
  <slot name="left">1</slot>
  <slot name="center">2</slot>
  <slot name="right">3</slot>
 </div>
</template>
<script>
 Vue.component('my-cpn', {
  template: '#myCpn'
 })
 let app = new Vue({
  el: '#app'
 })
</script>
複製代碼

編譯做用域

Vue實例屬性:

父組件模板的全部東西都會在父級做用域內編譯,子組件模板的全部東西都會在子級做用域內編譯。

父組件替換插槽的標籤,可是內容由子組件來提供。

模塊化開發

什麼是模塊化,將一組模塊以正確的順序拼接到一個文件中的過程,模塊是實現特定功能的一組屬性和方法的封裝。

利用構造函數封裝對象

function web() {
    var arr = [];
    this.add = function(val) {
        arr.push(var)
    }
    this.toString = function() {
        return arr.join('')
    }
}
var a = new web();
a.add(1); // [1]
a.toString(); // "1"
a.arr // undefined
複製代碼

示例:

var ModuleA = (function(){
    // 定義一個對象
    var obj = {}
    // 在對象內部添加變量和方法
    obj.flag = true
    obj.myFunc = function(info) {
        console.log(info)
    };
    // 將對象返回
    return obj
}
複製代碼
if(ModuleA.flag) {
    console.log('web')
}

ModuleA.myFunc('webweb')
複製代碼

常見的模塊化規範:

CommonJS,AMD,CMD,ES6中的Modules

什麼是AMD,異步模塊定義,它是在瀏覽器端實現模塊化開發的規範,可是該規範不是原生js支持的,使用AMD規範進行開發的時候須要引入第三方的庫函數,就是RequireJS

RequireJS解決了多個js文件可能有依賴的關係,被依賴的文件須要早於依賴它的文件加載到瀏覽器;js加載的時候瀏覽器會中止頁面渲染,加載文件越多,頁面就會失去響應時間越長。

CMD是什麼,它是通用模塊定義,解決的問題和AMD同樣,不過在模塊定義方式和模塊加載時機上不一樣,CMD須要額外的引入第三方的庫文件SeaJS

JavaScript模塊化編程

  1. 能夠解決項目中的全局變量污染問題
  2. 開發效率高,利於多人協同開發
  3. 職責單一,方便代碼複用和維護
  4. 解決了文件的依賴問題

那麼什麼是模塊化呢

將一個項目按照功能劃分,理論上一個功能一個模塊,互不影響,在須要的時候載入,儘可能遵循高內聚低耦合。

瞭解CommonJS

CommonJS 是一種思想,本質上是可複用的JavaScript,它導出特定的對象,提供其它程序使用。

使用module.exportsexports.obj來導出對象,並在須要它的程序中使用require('module')加載。

模塊化的核心就是:導入和導出

導出:CommonJS

module.exports = {
    flag: true,
    test(a,b) {
        return a+b
    },
    demo(a,b) {
        return a*b
    }
}
複製代碼

導入:CommonJS

// CommonJS模塊
let {test, demo, flag} = require('moduleA');

// =>
let ma = require('moduleA');
let test = ma.test;
let demo = ma.demo;
let flag = ma.flag;
複製代碼

由於網站開發愈來愈複雜,js文件又不少,就會出現一些問題:

  1. 變量名衝突
  2. 文件依賴複雜度高
  3. 頁面加載過多,不利於維護

CommonJS,定義模塊,一個單獨的js文件就是一個模塊,每一個模塊都有本身單獨的做用域,在該模塊內部定義的變量,沒法被其餘模塊讀取,除了定義爲global對象的屬性。

模塊的導出:exportsmodule.exports

模塊的導入:require

  1. node中,每一個模塊內部都有要給本身的module對象
  2. module對象中,有一個成員exports也是一個對象
  3. 經過exports對象導出當前方法或變量,也可經過module.exports導出
  4. node簡化了操做,exports等於module.exports,至關於var exports = module.exports

es模塊的導入和導出

export function add(num1, num2) {
    return num1 + num2
}
複製代碼
export function accString(param) {
	if (param == 0) {
		return '關'
	}else if(param == 1) {
		return '開'
	}
}

import {
		accString
	} from '../../utils'
複製代碼
const name = 'web'

export default name
複製代碼

export default

一個模塊中包含某個功能,若是不但願給功能命名,可讓導入者本身來定:

export default function(){
    console.log('web')
}
複製代碼

使用:

import myFunc from '../web.js'

myFunc()
複製代碼

export default在同一個模塊中,不容許同時存在多個

import使用

export指令導出了模塊對外提供的接口

import指令用於導入模塊中的內容

import {name, age} from './web.js'
複製代碼

經過*能夠導入模塊中全部全部的export變量

import * as web from './web.js'

console.log(web.name);
複製代碼

生命週期

首先:new Vue(),new一個Vue的實例,Observe data數據查看,init Events綁定事件,created執行created方法,判斷是否有el屬性,若是沒有,vm.$mount(el)表示處於未掛載狀態,能夠手動調用這個方法來掛載。判斷是否有template屬性。

若是有el屬性,判斷是否有template屬性。

實例化期和加載期 建立期間的生命週期函數:beforeCreatecreatedbeforeMountmounted

beforeCreate在實例初始化後,數據觀測data observerevent/watcher事件配置以前被調用。

更新期

運行期間的生命週期函數:beforeUpdateupdated

created實例已經建立完成後被調用。

實例已完成如下的配置:數據觀測data observer,屬性和方法的運算,watch/event事件回調。

掛載階段還沒開始,$el屬性目前不可見。

beforeMount在掛載開始以前被調用,相關的render函數首次被調用。mountedvm.$el已經掛載在文檔內,對已有dom節點的操做能夠在期間進行。beforeUpdate數據更新時調用,發生在虛擬dmo從新渲染和打補丁以前。updated當這個鉤子被調用時,組件dom已經更新,因此你如今能夠執行依賴於dom的操做。activateddeactivatedbeforeDestroydestroyed。實例銷燬以前調用,vue實例銷燬後調用。

卸載期

銷燬期間的生命週期函數:beforeDestroydestroyed

實例生命週期鉤子

每一個vue實例在被建立時都要通過一系列的初始化過程,須要設置數據監聽,編譯模板,將實例掛載到dom並在數據變化時更新dom等,同時在這個過程當中也會運行一些叫作生命週期鉤子的函數。

用於給用戶在不一樣階段添加本身代碼的機會。

beforeCreate,此時的data是不可見的

data() {
    return {
        a: 1
    }
},
beforeCreate() {
    // red
    console.log(this.a); // 看不見
}
複製代碼

created實例已經建立完成後被調用,這個時候你看不見你頁面的內容,實例已完成表示:數據觀測data observer,屬性和方法的運算,watch/event事件回調。

這個時候掛載階段還沒開始,$el屬性目前不可見。

export default {
    data() {
        return {
            a: 1
        }
    },
    beforeCreate() {
        console.log(this.a);
    },
    created() {
        // red
        console.log(this.a);
        console.log(this.$el);
        // 此時data數據裏面的a可見,this.$el不可見
    }
}
複製代碼

beforeMount在掛載開始以前被調用,相關的render函數首次被調用。

export default{
    data() {
        return {
            a: 1
        }
    },
    beforeCreate() {
        console.log(this.a); // 不可見
    },
    created() {
        console.log(this.a);
        console.log(this.$el); // 不可見
    },
    beforeMount() {
        console.log(this.$el); // 不可見
    }
}
複製代碼

mounted

export default {
    data() {
        return {
            a: 1
        }
    },
    mounted() {
        console.log(this.$el); // 此時$el 可見
    }
}
複製代碼

beforeUpdate鉤子,dom更新以前調用:

beforeUpdate() {
    console.log(this.a);
}

// document.getElementById("web").innerHTML
複製代碼

updated鉤子,dom更新以後調用:

updated() {
    console.log(this.a);
}

// document.getElementById("web").innerHTML
複製代碼

activateddeactivated(組件)

activated() {
    console.log("組件使用了");
},

deactivated() {
    console.log("組件停用了");
Data to Drag},
複製代碼

keep-alivevue的內置組件,能在組件切換過程當中將狀態保留在內存中,防止重複渲染dom

<keep-alive> 包裹動態組件時,會緩存不活動的組件實例,而不會銷燬它們。和<transition>類似,<keep-alive>是一個抽象組件:它自身不會渲染一個DOM元素,也不會出如今父組件鏈中。

當組件在<keep-alive>內被切換,它的activateddeactivated這兩個生命週期鉤子函數將會被對應指定。

它的使用是由於咱們不但願組件被從新渲染而影響使用體驗,或者是性能,避免屢次渲染下降性能。緩存下來,維持當前得狀態。

場景:

  1. 商品列表頁點擊商品跳轉到商品詳情,返回後仍顯示原有信息
  2. 訂單列表跳轉到訂單詳情,返回,等等場景。

keep-alive生命週期:

初次進入時:created > mounted > activated;退出後觸發 deactivated;再次進入:會觸發activated;事件掛載的方法等,只執行一次的放在mounted中;組件每次進去執行的方法放在 activated 中。

app.vue父組件:

<template>
 <div>
  <button @click="myBtn"> myBtn </button>
  <keep-alive>
   <range v-if="isShow"></range>
  </keep-alive>
 </div>
</template>

<script>
 import range from './components/range.vue'
 export default {
     data() {
         return {
             a: 1,
             isShow: true
         }
     },
     methods: {
         myBtn() {
             this.isShow = !this.isShow
         }
     },
     components: {
         range
     }
 }
</script>
複製代碼

beforeDestroydestroyed

beeforeDestroy類型爲function,詳細:實例銷燬以前調用,在這一步,實例仍然徹底可用。

該鉤子在服務器端渲染期間不被調用。

destroyed類型爲function,詳細:vue實例銷燬後調用,調用後,vue實例指示的全部東西都會解綁定,全部的事件監聽器會被移除,全部的子實例也會被銷燬。

該鉤子在服務器端渲染期間不被調用。

beforeRouteEnterbeforeRouteLeave

beforeRouteEnter() {
    console.log('beforeRouteEnter')
},

beforeRouteLeave() {
    console.log('beforeRouteLeave')
}
複製代碼

vue路由使用的,路由進去和路由離開的時候添加的。

created() {
    console.log('開始執行created鉤子函數')
    // 獲取data數據
    console.log('獲取created屬性'+this.value)
    // 獲取頁面元素
    console.log(this.$refs['example'])
    this.$nextTick(()=>{
        console.log('執行created建立的this.$nextTick()函數')
    })
},

mounted() {
    console.log('開始執行mounted鉤子函數')
    // 獲取掛載數據
    console.log('獲取掛載數據--'+this.$refs['example'].innerText)
    this.$nextTick(()=>{
        console.log('執行mounted建立的this.$nextTick()函數')
    })
},

methods: {
    // 更新數據
    updateDate(){
        
    },
    get(){
        this.value='更新data內的value屬性值'
        // 獲取頁面元素數據
        console.log(this.$refs['example').innerText)
        this.$nextTick(()=>{
          console.log(this.$refs['example'].innerText)  
        })
    }
}
複製代碼

var vm=new Vue({})表示開始建立一個Vue的實例對象,init events&liftcycle表示剛初始化了一個vue空的實例對象,這個時候,對象身上,只有默認的一些生命週期函數和默認事件,其餘東西都沒有建立,beforeCreate生命週期函數執行的時候,datamethods中的數據都沒有初始化。在created中,datamethods都已經被初始化好了,若是要調用methods中的方法,或者操做data中的數據,只能在created中操做。而後vue開始編輯模板,把vue代碼中的那些指令進行執行,最終在內存中生成一個編譯好的最終模板字符串,渲染爲內存中的dom,此時只是在內存中,渲染好了模板,並無把模板掛載到真正的頁面中去。beforeMount函數執行的時候,模板已經在內存中編譯好了,可是還沒有掛載到頁面中去。create vm.$el and replace 'el' with it這一步是將內存中編譯好的模板,真實的替換到瀏覽器的頁面中去。mounted,只要執行完了mounted,就表示整個vue實例已經初始化完了。此時,組件從建立階段進入到了運行階段。

beforeUpdate執行的時候,頁面中顯示的數據還舊的,而data數據是最新的,頁面還沒有和最新的數據保持同步。updated事件執行的時候,頁面和data數據已經保持同步了,都是新的。virtual dom re-render and patch執行,先根據data中最新的數據,在內存中,從新渲染出一份最新的內存dom樹,當最新的內存dom樹被更新以後,會把最新的內存dom樹,從新渲染到真實的頁面中,完成數據從dataview的跟新。

beforeDestroy鉤子函數執行時,vue實例就從運行階段,進入到了銷燬階段。此時的實例仍是可用的階段,沒有真正執行銷燬過程。destroyed函數執行時,組件已經被徹底銷燬了,都不可用了。

vue面試題

談一談你對mvvm的理解

雙向綁定的過程

視圖view,路由-控制器Controller,數據Model

view->domviewModelModel數據

傳統的mvc指用戶操做會請求服務器端路由,路由會調用對應的控制器來處理,控制器會獲取數據,將結果返回給前端,讓頁面從新渲染。

mvvm,對於傳統的前端會將數據手動渲染到頁面上,mvvm模式不須要用戶收到操做dom元素,將數據綁定到viewModel層上,會自動將數據渲染到頁面中,視圖變化會通知viewModel層更新數據。

Vue響應式原理

  1. vue內部是如何監聽message數據的改變
  2. 當數據發生改變,vue是如何知道要通知哪些人,界面發生刷新

核心:

  • Object.defineProperty,監聽對象屬性的改變
  • 發佈訂閱者模式

代碼:

Object.keys(obj).forEach(key => {
 let value = obj[key]
 
 Object.defineProperty(obj, key, {
    set(newValue) {
        // 監聽改變
        value = newValue
    },
    get() {
        return value
    }
 })
})

obj.name = 'web'
複製代碼

發佈者訂閱者

class Dep {
    constructor() {
        this.subs = []
    }
}

class Watcher {
    constructor(name) {
        this.name = name;
    }
}
複製代碼

對象的Object.defindeProperty中的訪問器屬性中的getset方法

  • 把數據轉化爲gettersetter,創建watcher並收集依賴。

說明:

watcher經過回調函數更新view;observer觀測data數據,經過get通知dep收集watcherdep經過notify()通知watcher數據更新,watcher經過addDep()收集依賴。

Observer:用於監聽劫持全部data屬性,dep,watcher,viewCompile解析el模板中的指令。

依照下圖(參考《深刻淺出vue.js》)

首先從初始化data數據開始,使用Observer監聽數據,個體每一個數據屬性添加Dep,而且在Data,有兩個gettersetter。在它的getter過程添加收集依賴操做,在setter過程添加通知依賴的操做。

在解析指令或者給vue實例設置watch選項或者調用$watch時,生成對應的watcher並收集依賴。

Data經過Observer轉換成了getter/setter的形式,來對數據追蹤變化。

修改對象的值的時候,會觸發對應的settersetter通知以前依賴收集獲得的 Dep 中的每個Watcher,告訴它們值改變了,須要從新渲染視圖。

數據雙向綁定原理

什麼是響應式的原理

  1. 核心:Object.defineProperty
  2. 默認vue在初始化數據時,會給data中的屬性使用Object.defineProperty從新定義全部屬性,當頁面取到對應屬性時,會進行依賴收集,若是屬性發生變化會通知相關依賴進行更新操做。

initData初始化用戶傳入的data數據,new Observer將數據進行觀測,this.walk(value)進行對象的處理,defineReactive循環對象屬性定義響應式變化,Object.defineProperty,使用Object.defineProperty從新定義數據。

使用使用Object.defineProperty從新定義數據的每一項。

Object.defineProperty(obj,key,{
 enumerable: true,
 configurable: true,
 get: function reactiveGetter(){
     const value=getter?getter.call(obj):val
     if(Dep.target){
         dep.depend()
         if(childOb){
             childOb.dep.depend()
             if(Array.isArray(value)){
                 dependArray(value)
             }
         }
     }
     return value
 },
 set: function reactiveSetter(newVal) {
     const value=getter?getter.call(obj).val
     if(newVal === value || (newVal !== newVal && value !==value)){
         return
     }
     if(process.env.NODE_ENV !== 'production' && customSetter){
         customSetter()
     }
     val = newVal
     childOb = !shallow && observe(newVal)
     dep.notify()
 }
})
複製代碼

vue中式如何檢測數組變化

使用函數劫持的方式,重寫了數組的方法,vuedata中的數組進行了原型鏈的重寫,指向了本身定義的數組原型方法,這樣當調用數組api時,能夠通知依賴跟新,若是數組中包含着引用類型,會對數組中的引用類型再次進行監控

initData初始化用戶傳入的data數據,new Observer將數據進行觀測,protoAugment(value,arrayMethods)將數據的原型方法指向重寫的原型。

  • 對數組的原型方法進行重寫
  • observerArray深度觀察數組中的每一項

代碼:

if(Array.isArray(value)){
    // 判斷數組
    if(hasProto){
        protoAugment(value, arrayMethods)// 改寫數組原型方法
    }else{
        copyAugment(value,arrayMethods,arrayKeys)
    }
    this.observeArray(value)
    //深度觀察數組中的每一項
}else{
    this.walk(value) 
    // 從新定義對象類型數據
}

function protoAugment(target, src: Object){
    target.__proto__ = src
}

export const arrayMethods = Object.create(arrayProto)
const methodsToPatch=[
 'push',
 'pop',
 'shift',
 'unshift',
 'splice',
 'sort',
 'reverse'
]

methodsToPatch.forEach(function (method){
    const original = arrayProto[method]
    def(arrayMethods, method, function mutator(...args){
        const result = original.apply(this.args)
        const ob = this.__ob__
        let inserted
        switch(method) {
            case 'push':
            case 'unshift':
            inserted = args
            break
            case 'splice':
            inserted = args.slice(2)
            break
        }
        if(inserted) ob.observerArray(inserted)
        // 對插入的數據再次進行觀測
        ob.dep.notify()
        // 通知視圖更新
        return result
    }
}

observeArray(items: Array<any>) {
    for(let i=0, l = items.length; i<1; i++) {
        observe(item[i])
        // 觀測數組中的每一項
    }
}
複製代碼

爲何vue採用異步渲染

若是不採用異步更新,每次更新數據都會對當前組件進行從新渲染,爲了性能考慮。

dep.notify()通知watcher進行更新操做,subs[i].update()依次調用watcherupdatequeueWatcherwatcher去重放到隊列中,nextTick(flushSchedulerQueue)異步清空watcher隊列。

nextTick實現原理

微任務高於宏任務先執行

nextTick方法主要使用了宏任務和微任務,定義了一個異步方法,屢次調用了nextTick會將方法存入到隊列中,經過這個異步方法清空當前隊列。

nextTick方法是異步方法。

原理:nextTick(cb)調用nextTick傳入cbcallbacks.push(cb)將回調存入數組中,timerFunc()調用timerFunc,返回promise支持promise的寫法。

webpack

什麼是webpack,webpack是一個現代的JavaScript應用的靜態模塊打包工具。

webpack是前端模塊化打包工具

安裝webpack須要安裝node.js,node.js自帶有軟件包管理工具npm

全局安裝

npm install webpack@3.6.0 -g
複製代碼

局部安裝

npm install webpack@3.6.0 --save-dev
複製代碼

webpack.config.js固定名文件:

const path = require("path")
module.exports = {
    entry: './src/main.js',
    output: {
        patch: './dist',
        filename: ''
    },
}
複製代碼

package.json

{
    "name": 'meetwebpack',
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
        "test": "echo ..."
    },
    "author": "",
    "license": "ISC"
}
複製代碼

什麼是loader

loaderwebpack中一個很是核心的概念

loader使用過程:

  1. 經過npm安裝須要使用的loader
  2. webpack.config.js中的moudules關鍵字下進行配置

package.json中定義啓動

{
    "name": "meetwebpack",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
        "build": "webpack"
    },
    "author": "",
    "license": "ISC",
    "devDependencies": {
        "webpack": "^3.6.0"
    }
}
複製代碼

webpack的介紹

webpack能夠看作是模塊打包機,它能夠分析你的項目結構,找到JavaScript模塊以及其它的一些瀏覽器不能直接運行的拓展語言,將其打包爲合適的格式以供瀏覽器使用。

能夠實現代碼的轉換,文件優化,代碼分割,模塊合併,自動刷新,代碼校驗,自動發佈。

安裝本地的webpack

webpack webpack-cli -D
複製代碼

初始化:

yarn init -y
複製代碼
yarn add webpack webpack-cli -D
複製代碼

webpack能夠進行0配置,它是一個打包工具,能夠輸出後的結果(Js模塊),打包(支持js的模塊化)

運行webpack命令打包

npx webpack
複製代碼

webpack.config.jswebpacknode寫出來的node的寫法:

let path = require('path')
console.log(path.resolve('dist');

module.exports = {
    mode: 'development',
    // 模式,默認兩種,production,development
    entry: '' // 入口
    output: {
        filename: 'bundle.js',
        // 打包後的文件名
        path: path.resolve(__dirname, 'build'),
        // 把相對路徑改寫爲絕對路徑
    }
}
複製代碼

自定義,webpack.config.my.js

使用命令:

npx webpack --config webpack.config.my.js
複製代碼

package.json:

{
    "name": 'webpack-dev-1',
    "version": "1.0.0",
    "main": "index.js",
    "license": "MIT",
    "scripts": {
      "build": "webpack --config webpack.config.my.js"  
    },
    "devDependencies": {
        "webpack": "^4.28.3",
        "webpack-cli": "^3.2.0"
    }
}
複製代碼

使用命令:

npm run build

// npm run build -- --config webpack.config.my.js
複製代碼

開發服務器的配置

代碼:

let path = require('path')
let HtmlWebpackPlugin = require('html-webpack-plugin')
console.log(path.resolve('dist');

module.exports = {
    devServer: {
      // 開發服務器的配置  
      port: 3000,
      // 看到進度條
      progress: true,
      contentBase: "./build",
      compress: true
    },
    mode: 'development',
    // 模式,默認兩種,production,development
    entry: '' // 入口
    output: {
        filename: 'bundle.js',
        // 打包後的文件名
        path: path.resolve(__dirname, 'build'),
        // 把相對路徑改寫爲絕對路徑
    },
    plugins: [
        // 數組,全部的webpack插件
        new HtmlWebpackPlugin({
            template: './src/index.html',
            filename: 'index.html',
            minify:{
                removeAttributeQuotes: true,//刪除「」
                collapseWhitespace: true, // 變成一行
               
            },
             hash: true
        })
    ],
    module: {
        // 模塊
        rules: [
            // 規則
            {test: /\.css$/, use: [{
                loader: 'style-loader',
                options: {
                    insertAt: 'top'
                }
            },'css-loader'] },
        ]
    }
}
複製代碼
output: {
    filename: 'bundle.[hash:8].js',// 打包文件名後只顯示8位
}
複製代碼
{
    "name": 'webpack-dev-1',
    "version": "1.0.0",
    "main": "index.js",
    "license": "MIT",
    "scripts": {
      "build": "webpack --config webpack.config.my.js",
      "dev": "webpack-dev-server"
    },
    "devDependencies": {
        "webpack": "^4.28.3",
        "webpack-cli": "^3.2.0"
    }
}
複製代碼
yarn add css-loader style-loader -D
複製代碼

樣式:

  1. style-loader將模塊的導出做爲樣式添加到dom
  2. css-loader解析css文件後,使用import加載,而且返回css代碼
  3. less-loader加載和轉譯less文件
  4. sass-loader加載和轉譯sass/scss文件
  5. postcss-loader使用PostCSS加載和轉譯css/sss文件
  6. stylus-loader加載和轉譯Stylus文件

style-loader安裝:

npm install style-loader --save-dev
複製代碼

用法:

建議將style-loadercss-loader結合使用

component.js

import style from './file.css'
複製代碼
  1. css-loader只負責將css文件進行加載
  2. style-loader負責將樣式添加到dom
  3. 使用多個loader時,是從右到左

代碼:

// webpack.config.js
module: {
    rules: [
        {
            test: /\.css$/,
            use: ['style-loader', 'css-loader']
        }
    ]
}
複製代碼

css文件處理:style-loader

安裝style-loader

npm install --save-dev style-loader
複製代碼

style-loader須要放在css-loader的前面,webpack在讀取使用的loader的過程當中,是按照從右向左的順序讀取的。

webpack.config.js的配置以下:

const path = require('path')

module.exports = {
    // 入口:能夠是字符串/數組/對象,這裏咱們入口只有一個,因此寫一個字符串便可。
    entry: './src/main.js',
    // 出口:一般是一個對象,裏面至少包含兩個重要屬性,path和filename
    output:{
        path: path.resolve(__dirname, 'dist'), // 注意:path一般是一個絕對路徑
        filename: 'bundle.js'
    },
    module: {
        rules: {
            {
                test: /\.css$/,
                use: ['style-loader','css-loader']
            }
        }
    }
}
複製代碼

webpack less文件處理

安裝:

npm install --save-dev less-loader less
複製代碼

示例:

css-loader,style-loader,less-loader鏈式調用,能夠把全部樣式當即應用於dom

// webpack.config.js
module.exports = {
    ...
    rules: [{
        test: /\.less$/,
        use: [{
            loader: 'style-loader'
        },{
            loader: 'css-loader'
        },{
            loader: 'less-loader'
        }]
    }]
}
複製代碼

圖片文件處理

css normal代碼:

body {
    background: url("../img/test.jpg")
}
複製代碼

url-loader

npm install --save-dev url-loader
複製代碼

用法

url-loader功能相似於file-loader,可是在文件大小低於指定的限制時,能夠返回一個DataURL

import img from './image.png'
複製代碼

webpack.config.js

module.exports = {
    module: {
        rules: [
            {
                test: /\.(png|jpg|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 8192
                        }
                    }
                ]
            }
        ]
    }
}
複製代碼

img,文件要打包到的文件夾

name,獲取圖片原來的名字,放在該位置

hash:8,爲了防止圖片名稱衝突,依然使用hash,可是咱們只保留8位

ext,使用圖片原來的擴展名

es6轉es5的babel

若是但願es6轉成es5,那麼就須要使用babel

npm install --save-dev babel-loader@7 babel-core babel-preset-es2015
複製代碼

配置webpack.config.js文件:

{
    test: /\.m?js$/,
    use: {
        loader: 'babel-loader',
        options: {
            presets: ['es2015']
        }
    }
}
複製代碼

使用vue

如何在咱們的webpack環境中集成vue.js

代碼:

npm install vue --save
複製代碼
  1. runtime-only代碼中,不能夠有任何的template
  2. runtime-compiler代碼中,能夠有template由於有compiler能夠用於編譯template

spa(simple age web application)->vue-router(前端路由)

.vue文件封裝處理

安裝vue-loadervue-template-compiler

npm install vue-loader vue-template-compiler --save-dev
複製代碼

認識webpack的plugin

  1. plugin是什麼?
  • plugin是插件的意思,一般用於對某個現有的架構進行擴展。
  • webpack中的插件,是對webpack現有功能的各類擴展。
  1. loaderplugin的區別
  • loader主要用於轉換某些類型的模塊,它是一個轉換器。
  • plugin是插件,它是對webpack自己的擴展,是一個擴展器。
  1. plugin的使用過程:
  • 經過npm安裝須要使用的plugins
  • webpack.config.js中的plugins中配置插件

webpack.config.js的文件:

查看bundle.js文件的頭部:

Vue Cli詳解

什麼是vue cliCommand-Line Interface,命令行界面,俗稱腳手架,vue cli是一個官方發佈的項目腳手架。使用vue-cli能夠快速搭建vue開發環境以及對應的webpack配置。

vue cli的使用

安裝vue腳手架

npm install -g @vue/cli
複製代碼

vuecli2初始化過程

代碼:

vue init webpack vuecli2test
複製代碼
  1. 根據名稱建立一個文件夾,存放以後項目的內容,該名稱會做爲默認的項目名稱,可是不能包含大寫字母等
  2. Project name 項目名稱,不能包含大寫
  3. Project description項目描述
  4. Author做者信息
  5. Vue build``runtime
  6. Install vue-router``no是否安裝等

目錄結構詳解

build``configwebpack相關配置,node_modules 是依賴的node相關的模塊,src是寫代碼地方。 .babelrc是es代碼相關轉換配置,.editorconfig項目文本相關配置,.gitignore``git倉庫忽略的文件夾配置,.postcssrc.jscss相關轉化的配置。

.editorconfig

前端模塊化:

爲何使用模塊化,簡單寫js代碼帶來的問題,閉包引發代碼不可複用,本身實現了簡單的模塊化,es中模塊化的使用:exportimport

npm install @vue/cli -g
複製代碼
npm clean cache -force
複製代碼

vue cli2初始化:

vue init webpack my-project
複製代碼

vue cli3初始化項目:

vue create my-project
複製代碼

箭頭函數的使用和this

箭頭函數,是一種定義函數的方式

  1. 定義函數的方式:function
const a = function(){
    
}
複製代碼
  1. 對象字面量中定義函數
const obj = {
    b: function() {
        
    },
    b() {
        
    }
}
複製代碼
  1. 箭頭函數
const c = (參數列表) => {
    
}
const c = () => {
    
}
複製代碼

箭頭函數參數和返回值

代碼:

const sum = (num1, num2) => {
    return num1 + num2
}

const power = (num) => {
    return num * num
}

const num = (num1,num2) => num1 + num2
複製代碼
const obj = {
    a() {
        setTimeout(function() {
            console.log(this); // window
        })
        setTimeout(()=>{
          console.log(this); // obj對象 
        })
    }
}
複製代碼

路由,,vue-router基本使用,vue-router嵌套路由,vue-router參數傳遞,vue-router導航守衛。

路由是一個網絡工程裏面的術語,路由就是經過互聯的網絡把信息從源地址傳輸到目的地址的活動。

路由器提供了兩種機制:路由和轉送。路由是決定數據包歷來源到目的地的路徑,轉送將輸入端的數據轉移到合適的輸出端。路由中有一個很是重要的概念叫路由表。路由表本質上就是一個映射表,決定了數據包的指向。

後端路由:後端處理url和頁面之間的映射關係。

前端路由和後端路由,前端渲染和後端渲染

vue-routerkoa-router的區別:

vue-router是前端路由,koa-router是後端路由。

vue-router前端路由原理:

前端路由主要模式:hash模式和history模式。

路由的概念來源於服務端,在服務端中路由描述的是 URL 與處理函數之間的映射關係。

先後端渲染之爭

url中的hashhtml5history

前端路由的核心是改變url,可是頁面不進行總體的刷新。單頁面,其實spa最重要的特色就是在先後端分離的基礎上加了一層前端路由。就是前端來維護一套路由規則。

urlhash

urlhash是錨點#,本質上是改變window.locationhref屬性。直接賦值location.hash來改變href,可是頁面不發生刷新。

html5history模式:pushState

html5history模式:replaceState

html5history模式:go

history.go()

history.back()等價於history.go(-1)

history.forward()等價於history.go(1)

安裝vue-router

npm install vue-router --save
複製代碼
  1. 導入路由對象,而且調用Vue.use(VueRouter)
  2. 建立路由實例,而且傳入路由映射配置
  3. Vue實例中掛載建立的路由實例

代碼:

// 配置路由相關的信息
import VueRouter from 'vue-router'
import vue from 'vue'
import Home from '../components/Home'
import About from '../components/About'

// 經過Vue.use(插件),安裝插件
Vue.use(VueRouter)

// 配置路由和組件之間的應用關係
const routes = [
 {
     path: '/home',
     component: Home
 },
 {
     path: '/about',
     component: About
 }
]

// 建立VueRouter對象
const router = new VueRouter({
 routes
})

// 將router對象傳入到`Vue`實例
export default router
複製代碼

main.js

import Vue from 'vue'
import App from './App'
import router from './router'

Vue.config.productionTip = false

new Vue({
 el: '#app',
 router,
 render: h => h(App)
})
複製代碼

使用vue-router的步驟

  1. 建立路由組件
  2. 配置路由映射:組件和路徑映射關係
  3. 使用路由:經過<router-link><router-view>

代碼:

組件components

// home
<template>
 <div>
  <h2>我是首頁</h2>
 </div>
</template>

<script>
 export default {
     name: 'Home'
 }
</script>

<style scoped>
</style>
複製代碼
<template>
 <div>
  <h2>我是關於</h2>
 </div>
</template>

<script>
 export default {
     name: 'Aboout'
 }
</script>

<style scoped>
</style>
複製代碼

App.vue

<template>
 <div id="app">
  <router-link to="/home">首頁</router-link>
  <router-link to="/about">關於</router-link>
  <router-view></router-view>
 </div>
</div>

<script>
export default {
    name: 'App'
}
</script>

<style>
</style>
複製代碼

main.js

import Vue from 'vue'
import App from './App'
import router from './router'
Vue.config.productionTip = false
new Vue({
 el: '#app',
 router,
 render: h => h(App)
})
複製代碼

路由的偶然值和修改成history模式

建立router實例

代碼:

router->index.js

import Vue from 'vue'
import VueRouter from 'vue-router'

// 注入插件
Vue.use(VueRouter)

// 定義路由
const routes = []

// 建立router實例
const router = new VueRouter({
 routes
})

// 導出router實例
export default router
複製代碼

main.js代碼:

import Vue from 'vue'
import App from './App'
import router from './router'

new Vue({
 el: '#app',
 router,
 render: h=>h(App)
})
複製代碼

router->index.js

import Vue from 'vue'
import VueRouter from 'vue-router'

import Home from '../components/home'
import About from '../components/about'

// 注入插件
Vue.use(VueRouter)

// 定義路由
const  routes = [
 {
     path: '/home',
     component: Home
 },
 {
     path: '/about',
     component: About
 }
]
複製代碼

使用App.vue代碼

<template>
 <div id="app">
  <router-link to="/home">首頁</router-link>
  <router-link to="/about">關於</router-link>
  <router-view></router-view>
 </div>
</template>
<script>
export default {
    name: 'App',
    components: {
        
    }
}
複製代碼
  1. <router-link>該標籤是一個vue-router已經內置的組件,它會被渲染成一個<a>標籤
  2. <router-view>該標籤會根據當前的路徑,動態渲染出不一樣的組件。
  3. 網頁的其餘內容,好比頂部的標題或導航,或者底部的一些版本信息等會和<router-view>處於同一個等級。
  4. 在路由切換時,切換的是<router-view>掛載的組件,其餘內容不會發生改變。

路由的默認路徑

默認狀況下,進入網站的首頁,<router-view>渲染首頁的內容,可是默認沒有顯示首頁組件,必須讓用戶點擊才能夠。

那麼如何讓路徑默認跳轉到首頁,而且<router-view>渲染首頁組件呢,只須要配置一個映射就能夠:

const routes = [
 {
     path: '/',
     redirect: '/home'
 }
]
複製代碼

配置解析:在routes中又配置了一個映射,path配置的是根路徑:/redirect是重定向,就是咱們將根路徑重定向到/home的路徑下。

// main.js
const router = new VueRouter({
 // 配置路由和組件之間的應用關係
 routes,
 mode: 'history'
})
複製代碼

改變路徑的方式:

  1. urlhash
  2. html5history
  3. 默認狀況下,路徑的改變使用的urlhash

使用html5history模式:

// 建立router實例
const router = new VueRouter({
 routes,
 mode: 'history'
})
複製代碼

router-link,使用了一個屬性:to,用於指定跳轉的路徑。tag能夠指定<router-link>以後渲染成什麼組件。

replace屬性不會留下history記錄,指定replace的狀況下,後退鍵返回不能返回到上一個頁面中。

active-class屬性,當<router-link>對應的路由匹配成功時,會自動給當前元素設置一個router-link-activeclass,設置active-class能夠修改默認的名稱。

const router = new VueRouter({
 routes,
 mode: 'history',
 linkActiveClass: 'active'
})
複製代碼

路由代碼跳轉

App.vue代碼:

// app.vue
<template>
 <div id="app">
  <button @click="linkToHome">首頁</button>
  <button @click="linkToAbout">關於</button>
  <router-view></router-view>
 </div>
</template>

<script>
 export default {
     name: 'App',
     methods: {
         linkToHome() {
             this.$router.push('/home')
         },
         linkToAbout() {
             this.$router.push('/about')
         }
     }
 }
</script>
複製代碼

<img :src="imgURL" alt="">

<router-link :to="'/uer/' + userId"> 用戶 </router-link>

<script>
 export default {
     name: 'User',
     computed: {
         userId() {
             return this.$route.params.userId
         }
     }
 }
</sript>
複製代碼

const Home = () => import('../components/Home')
const HomeNews = () => import('../components/HomeNews')
const HomeMessage = () => import('../components/HomeMessage')

{
    path: '/home',
    component: Home,
    children: [
        {
            path: 'news',
            component: HomeNews
        },
        {
            path: 'news',
            component: HomeMessage
        }
    ]
}
複製代碼
<router-link to = "/home/news">新聞</router-link>
<router-link to = "/home/message">信息</router-link>
複製代碼

默認選中:

傳遞參數的方式

傳遞參數主要有兩種類型,paramsquery

params的類型:

  1. 配置路由方式:/router/:id
  2. 傳遞的方式:在path後面跟着對應的值
  3. 傳遞後造成的路徑:/router/123

vue-router傳遞參數代碼

<router-link :to="{path: '/profile'}">用戶</router-link>
複製代碼

統一資源定位符

統一資源定位符,統一資源定位器,統一資源定位地址,Url地址等,網頁地址。如同在網絡上的門牌,是因特網上標準的資源的地址。

userClick() {
    this.$router.push('/user/' + this.userId)
}

btnClick() {
    this.$router.push({
     path: '/user',
     query: {
         name: 'web',
         age: 12,
         height: 1.2
     }
    })
}
複製代碼

$route$router是有區別的

獲取參數經過$route對象獲取的,在使用vue-router的應用中,路由對象會被注入每一個組件中,賦值爲this.$route,而且當路由切換時,路由對象會被更新。

<template>
 <div>
  <p> {{$route.params}} </p>
 </div>
</template>
複製代碼

query的類型:

  1. 配置路由格式:/router也是普通配置
  2. 傳遞方式,對象中使用querykey做爲傳遞方式
  3. 傳遞後造成的路徑,router?id=123,/router?id=abc

$route$router是有區別的

const router = new VueRouter({
 routes,
 mode: 'history',
 linkActiveClass: 'active'
})
複製代碼

Vue.config.productionTip = false

Vue.prototype.test = function() {
    console.log('test')
}

Vue.prototype.name  = 'web'
複製代碼

$route$router是有區別的

  1. $routerVueRouter實例,想要導航到不一樣url,則使用$router.push方法。
  2. $route爲當前router跳轉對象裏面能夠獲取name,path,query,params等。

vue-router全局導航

meta:元數據

router.beforeEach((to,from,next) => {
    // from 跳轉到to
    document.title = to.matched[0].meta.title
    console.log(to);
    next()
})
複製代碼
// 後置鉤子hook
router.afterEach((to,from) => {
  console.log();  
})
複製代碼

導航守衛:導航表示路由正在發生改變。

vue-router提供的導航守衛主要用來經過跳轉或取消的方式守衛導航。有多種機會植入路由導航過程當中,全局的,單個路由獨享的,或者組件級的。

全局守衛

可使用router.beforeEach,註冊一個全局前置守衛:

const router = new VueRouter({..})

router.beforeEach((to,from,nex)=>{
    
})
複製代碼

當一個導航觸發時,全局前置守衛按照建立順序調用。守衛是異步解析執行,此時導航在全部守衛resolve完以前一直處於等待中。

  1. to:Route,即將要進入的目標路由對象
  2. from:Route,當前導航正要離開的路由
  3. next:Function,必定要調用該方法來resolve這個鉤子。

vue-router-keep-alive

keep-alivevue-router

router-view是一個組件,若是直接被包含在keep-alive裏面,全部路徑匹配到的視圖組件都會被緩存。

keep-aliveVue內置的一個組件,可使被包含的組件保留狀態,或避免從新渲染。

屬性:

  1. include字符串或正則表達式,只有匹配的組件會被緩存
  2. exclude字符串或正則表達式,任何匹配的組件都不會被緩存
<keep-alive>
 <router-view>
  // 全部路徑匹配到的視圖組件都會被緩存
 </router-view>
<keep-alive>
複製代碼

Promise的使用

es6的特性Promise,它是異步編程的一種解決方案。

定時器的異步事件:

setTimeout(function() {
    let data = 'web'
    console.log(content)
},1000)

new Promise((resolve, reject) => {
    setTimeout(function(){
        resolve('web')
        reject('error')
    },1000)
}).then(data=>{
    console.log(data)
}).catch(error=> {
    console.log(error)
})
複製代碼

Promise三種狀態:

  1. pending等待狀態,好比正在進行網絡請求,或定時器沒有到時間。
  2. fulfill,知足狀態,主動回調resolve時,而且回調.then()
  3. reject,拒絕狀態,回調reject時,而且回調.catch()

Vuex詳解

vuex是一個專門爲vue.js應用程序開發的狀態管理模式

它採用集中式存儲管理應用的全部組件的狀態,,並以相應的規則保證狀態以一種可預測的方式發生變化。

  1. 狀態管理模式
  2. 集中式存儲管理

View components -> actions(dispatch方式) -> mutations(commit方式) -> state -> View components
複製代碼

Vuex核心概念5個:

StateGettersMutationActionModule

State單一狀態樹,單一數據源。

Mutation狀態更新

Vuexstore的更新惟一方式,提交Mutation

Mutation的主要包括兩部分:

  1. 字符串的事件類型
  2. 一個回調函數,該回調函數的第一個參數就是state

mutation的定義:

mutations: {
    increment(state) {
        state.count++
    }
}
複製代碼

經過mutation更新

increment: function() {
    this.$store.commit('increment')
}
複製代碼

參數被稱爲是mutation的載荷payload

Vuexstore中的state是響應式的,當state中的數據發生改變時,Vue組件會自動更新。

  1. 提早在store中初始化好所需的屬性
  2. state中的對象添加新屬性時:使用
  • 使用Vue.set(obj,'newObj',123)
  • 用新對象給舊對象賦值

Mutation常量類型

// mutation-types.js
export const UPDATE_INFO = 'UPDATE_INFO'

import Vuex from 'vuex'
import Vue from 'vue'
import * as types from './mutation-types'

Vue.use(Vuex)

const store = new Vuex.Store({
    state: {
        info: {
            name: 'web',
            age: 12
        }
    },
    mutations: {
        [types.UPDATE_INFO](state, payload) {
            state.info = {...state.info, 'height': payload.height
        }
    }
})
複製代碼
<script>
 import {UPDATE_INFO} from './store/mutation-types';
 export default{
     name: 'App',
     components: {
         
     },
     computed: {
         info(){
             return this.$store.state.info
         }
     },
     methods: {
         updateInfo(){
             this.$store.commit(UPDATE_INFO,{height:1.00})
         }
     }
 }
</script>
複製代碼

注意:不要再mutation中進行異步操做,mutation同步函數,在其中的方法必須時同步方法。

action的基本定義,若是有異步操做,好比網絡請求,

// 不能再mutation中使用異步操做,不能再這裏進行異步操做
update(state) {
    setTimeout(()=>{
        state.info.name = 'web'
    },1000)
}

mutations: {
    // 方法
    [INCREMENT](state){
        state.counter++
    }
}
複製代碼
actions: {
    // context:上下文,=》store
    <!--aUpdateInfo(context) {-->
    <!--    setTimeout(()=>{-->
    <!--        state.info.name = 'web'-->
    <!--    },1000)-->
    <!--}-->
}
複製代碼
actions: {
    aUpdateInfo(context) {
        setTimeout(()=>{
            context.commit('updateInfo')
        },1000)
    }
}

// xx.vue
updateInfo(){
    this.$store.dispatch('aUpdateInfo')
}
複製代碼

updateInfo(){
    <!--this.$store.commit('updateInfo')-->
    this.$store.dispatch('aUpdateInfo',{
        message: 'web',
        success: () => {
            console.log('web')
        }
    })
}
複製代碼
aUpdateInfo(context, payload) {
    return new Promise((resolve, reject) => {...})
}
複製代碼

vuex中的modules使用

modules時模塊的意思

getters: {
    stu(){
        
    },
    stuLength(state, getters) {
        return getters.stu.length
    }
}
複製代碼

使用根數據:

getters: {
    fullName(state) {
        return state.name + '1'
    },
    fullName1(state, getters) {
        return getters.fullName + '2'
    },
    fullName3(state, getters, rootState) {
        return getters.fullName2+rootState.counter
    }
}
複製代碼

在模塊中actions打印console.log(context)

actions接收一個context參數對象,局部狀態經過context.state暴露出來,根節點狀態爲context.rootState

import mutations from './mutations'
import actions from './actions'
import getters from './getters'
import moduleA from './modules/moduleA'

import Vuex from 'vuex'
import Vue from 'vue'
Vue.use(Vuex)

const state = {
    
}

const store = new Vuex.Store({
    state,
    mutations,
    actions,
    getters,
    modules: {
        a: moduleA
    }
})

export default store
複製代碼

網絡封裝

axios網絡模塊的封裝

ajax是基於XMLHttpRequest(XHR)jQuery-Ajax相對於傳統的ajax很是好用。

axios特色:

  • 在瀏覽器中發送XMLHttpRequests請求
  • node.js中發送http請求
  • 支持Promise API
  • 攔截請求和響應
  • 轉換請求和響應數據

axios請求方式:

axios(config)
axios.request(config)
axios.get()
axios.delete()
axios.head()
axios.post()
axios.put()
axios.patch()
複製代碼

安裝

npm install axios --save
複製代碼
axios({
    // 默認get
    url: '',
    method: 'get'
}).then(res=>{
    console.log(res)
})
複製代碼
// import request from "../utils/request.js"
import {request} from './network'

export function getHome() {
    return request({
        url: '/home/xxx'
    })
}

export function getXX(type, page) {
    return request({
        url: '/home/xx',
        params: {
            type,
            page
        }
    })
}
複製代碼

併發請求

代碼:

axios.all([axios({
 url: ''
}), axios({
 url: '',
 params: {
     type: '',
     page: 1,
 }
})]).then(results => {

})

// then(axios.spread((res1,res2)=>{...}))
複製代碼

全局配置

axios.defaults.baseURL=''

axios.all ..{
    url: '/home'
}

axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

axios.defaults.baseURL = global.HOST;
複製代碼

request.js

import axios from 'axios'
export function request(config,success,failure){
    // 建立axios實例
    const instance = axios.create({
        baseURL: '',
        timeout: 5000
    })
    // 發送網絡請求
    instance(config)
    .then(res=>{
        success(res)
    })
    .catch(err=>{
        failure(err)
    })
}
複製代碼

main.js

import {request} from './xx/request'

request({
    url: ''
},res=>{

),err=>{
    
}
複製代碼

也可使用promise方法,不過自己返回的就是promise

import axios from 'axios'
export function request(config) {
    const instance = axios.create({
        baseURL: '',
        timeout: 2000
    })
    return instance(config)
}
複製代碼

axios攔截器的使用

// 配置請求和響應攔截
instance.interceptors.request.use(config => {
    console.log('request攔截success中')
    return config
},err => {
    console.log('request攔截failure中')
    return err
})

instance.interceptors.response.use(response => {
    console.log('response攔截success中')
    return response.data
},err => {
    console.log('response攔截failure中')
    return err
})
複製代碼

封裝axios

// request.js
import axios from 'axios'
cosnt service = axios.create({
 baseURL: process.env.BASE_API,
 timeout: 2000
})

service.interceptors.request.use(config=>{
 //發請求前作的一些處理,數據轉化,配置請求頭,設置token,設置loading等
 config.data=JSON.stringify(config.data);
 config.headers = {
     'Content-Type':'application/x-www-form-urlencoded'
 }
 return config
},error=>{
 Promise.reject(error)
})

// 響應攔截器
service.interceptors.response.use(response => {
 return response
}, error => {
  if (error && error.response) {
    switch (error.response.status) {
      case 400:
        error.message = '錯誤請求'
        break;
      case 401:
        error.message = '未受權,請從新登陸'
        break;
      case 403:
        error.message = '拒絕訪問'
        break;
      case 404:
        error.message = '請求錯誤,未找到該資源'
        window.location.href = "/NotFound"
        break;
      case 405:
        error.message = '請求方法未容許'
        break;
      case 408:
        error.message = '請求超時'
        break;
      case 500:
        error.message = '服務器端出錯'
        break;
      case 501:
        error.message = '網絡未實現'
        break;
      case 502:
        error.message = '網絡錯誤'
        break;
      case 503:
        error.message = '服務不可用'
        break;
      case 504:
        error.message = '網絡超時'
        break;
      case 505:
        error.message = 'http版本不支持該請求'
        break;
      default:
        error.message = `鏈接錯誤${error.response.status}`
    }
  } else {
    if (JSON.stringify(error).includes('timeout')) {
      Message.error('服務器響應超時,請刷新當前頁')
    }
    error.message('鏈接服務器失敗')
  }
  Message.error(err.message)
  return Promise.resolve(error.response)
})
// 導入文件
export default service
複製代碼

封裝請求http.js

import request from './request'
const http ={
    /**
     * methods: 請求
     * @param url 請求地址 
     * @param params 請求參數
     */
    get(url,params){
        const config = {
            methods: 'get',
            url:url
        }
        if(params){
         config.params = params
        }
        return request(config)
    },
    post(url,params){
        const config = {
            methods: 'post',
            url:url
        }
        if(params){
         config.data = params
        }
        return request(config)
    },
    put(url,params){
        const config = {
            methods: 'put',
            url:url
        }
        if(params){
         config.params = params
        }
        return request(config)
    },
    delete(url,params){
        const config = {
            methods: 'delete',
            url:url
        }
        if(params) {
         config.params = params
        }
        return request(config)
    }
}

export default http
複製代碼
// api.js
import http from '../utils/http'
let resquest = "/xx/request/"
// get請求
export function getListAPI(params){
    return http.get(`${resquest}/getList.json`,params)
}

// js

//建立新的axios實例,
const service = axios.create({
  baseURL: process.env.BASE_API,
  timeout: 3 * 1000
})
複製代碼

項目

建立項目:

vue create webMall

npm run serve
複製代碼

// .editorconfig
root = true
[*]
charset = utf-8
indent_style=space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
複製代碼

項目在window下部署

main.js代碼:

import store from './store'
import FastClick from 'fastclick'
import VueLazyLoad from 'vue-lazyload'

import toast from 'components/common/toast'

Vue.config.productionTip = false
// 添加事件總線對象
Vue.prototype.$bus = new Vue()
// 安裝toast插件
Vue.use(toast)
// 解決移動端300ms延遲
FastClick.attach(document.body)
// 使用懶加載的插件
Vue.use(VueLazyLoad,{
 loading: require('./xx.png')
})
複製代碼

windows安裝nginxlinux部署,centos上安裝nginx

linux ubuntu

Ubuntu是一個以桌面應用爲主的Linux操做系統,其名稱來自非洲南部祖魯語或豪薩語的「ubuntu"一詞。

操做系統:Window10 + Centos6.5(虛擬機)

yum install nginx
systemtl start nginx.service
systemctl enable nginx.service
複製代碼

經過Xftp將vue項目文件上傳至雲服務器

使用Xshell鏈接雲服務器

主機就是阿里雲上建立的實例的公網ip

輸入登陸名和密碼,登陸名就是購買服務器時輸入的登陸名和密碼。

運行npm run build命令,有一個dist文件夾,這就是vue項目打包後的文件。

nginx安裝配置

Xshell終端輸入命令yum install nginx,當須要確認時輸入」y「回車。

安裝完成後,輸入service nginx start啓動nginx服務。

經過命令nginx -t查看nginx所在的安裝目錄。

在命令行輸入命令cd/etc/nginx 切換到nginx目錄下,再輸入cat nginx.conf可查看當前nginx配置文件。

輸入命令 wget https://nodejs.org/dist/v10.8.0/node-v10.8.0-linux-x64.tar.xz 回車,等待安裝。

輸入命令tar xvf node-v10.8.0-linux-x64.tar.xz 回車進行解壓操做。

小結:

  1. 計算屬性在屢次使用時,只會調用一次,由於它是有緩存額
  2. 修飾符:stopprevent.enter.once.native等,lazynumbertrim等。
  3. 模板的分類寫法:scripttemplate
  4. 父子組件的通訊:父傳子,props,子傳父,$emit
  5. 項目,npm installnpm run serve
  6. webStorm開發vuePlugins安裝插件vue.js
  7. 2.6.0 版本中,Vue爲具名插槽和做用域插槽引入了一個新的統一的語法 (即 <v-slot> 指令)。它取代了 slotslot-scope 這兩個目前已被廢棄、還沒有移除,仍在文檔中的特性。
  8. v-slot 用法,分爲三類:默認插槽、具名插槽以及做用域插槽。

做用域插槽,經過 slot-scope屬性來接受子組件傳入的屬性集合

  • 默認插槽

代碼:

// 子組件
<template>
  <div>
  
    <header>
      <slot>默認值</slot>
    </header>
    
  </div>
</template>
複製代碼

任何沒有被包裹在帶有v-slot<template>中的內容都會被視爲默認插槽的內容。當子組件只有默認插槽時,<v-slot>標籤能夠直接用在組件上

// 父組件
<template>
  <div>
  
    <child>
      內容1
      <template>內容2</template>
      內容3
    </child>

    <child v-slot="web">
      插槽<br>
      插槽<br>
    </child>
    
  </div>
</template>
複製代碼
  • 具名插槽:v-slot 重複定義一樣的 name 後只會加載最後一個定義的插槽內容
// 子組件
<template>
  <div>
  
    <main>
      <slot name="main"></slot>
    </main>
    
    <footer>
      <slot name="footer"></slot>
    </footer>
    
  </div>
</template>
複製代碼
  • 做用域插槽:
// 子組件
<template>
  <div>
  
    <footer>
      <slot name="footer" :user="user" :testBtn="testBtn">
        {{user.name}}
      </slot>
    </footer>
    
  </div>
</template>

<script>

exportdefault {
    name: 'child',
    data () {
      return {
        user: {
          title: 'web',
          name: 'web'
        }
      };
    },
    methods:{
      testBtn(){
        alert('web');
      }
    }
  };
  
</script>
複製代碼

Vue如何直接調用Component裏的方法

<template>
  <div>
    <b-component ref="BComponent"></b-component>
  </div>
</template>
 
<script>
import BComponent from './BComponent'
 
export default {
  name: 'A',
 
  data () {
  },
 
  components: {
    BComponent
  },
 
  methods: {
    callACompoentFunction () {
      this.$refs.BComponent.sayHi()
    }
  }
}
</script>
 
<style scoped>
</style>
複製代碼
<template>
  <div></div>
</template>
 
<script>
 
export default {
  name: 'B',
 
  data () {
  },
 
  methods: {
    sayHi () {
      console.log('web!')
    }
  }
}
</script>
 
<style scoped>
</style>
複製代碼

最後

歡迎加我微信Jeskson(xiaoda0423),拉你進技術羣(掘金前端羣,達達前端技術社羣⑥),長期交流學習。

我的網站:www.dadaqianduan.cn/#/

相關文章
相關標籤/搜索