1. VUE完整系統簡介


今天開始系統學習vue前端框架. 我是有前端基礎的, 剛工作那會, 哪里分那么清楚啊, 前后端我都得做, 所以, css, js, jquery, bootstrap都會點, 還系統學過ext, 哈哈,是不是都不知道是啥, 沒事, 都過時了. 現在開始, 學習最流行的Vue, 后端不會頁面, 說不過去呀.....

言歸正傳, Ready, Go!

目錄

1. 認識Vuejs

2. Vuejs的安裝方式

3. Vuejs的初體驗-三個案例

4. MVVM模型

5. Vue對象的生命周期

6. Vue源碼


 

一. 認識Vuejs

  1. 為什么學習Vuejs

    • 這幾年Vue.js成為前端框架中最火的一個。越來越多的網站前端開始采用Vue.js開發。前端開發必備技能.
    • Vuejs是開源世界華人的驕傲,其作者是我國尤雨溪。學習門檻低,成本低,可跨設備和多平台開發Vue.js.
    • 前端換工作, 面試必問的框架.

  2. 簡單認識一下Vuejs

    • 官網地址: https://cn.vuejs.org/
    • 是一套用於構建用戶界面的漸進式框架, 什么是漸進式框架呢?

        漸進式框架是說, vue可以作為應用的一部分嵌入.

        比如:之前項目使用的是jquery開發的, 項目體量比較大, 現在知道vue使用上,效果上都更方便, 想要替換為vue, 可問題是之前的頁面特別多,如果全部替換,工作量太大,那么沒關系, vue允許你部分嵌入, 也就是說原來的頁面依然使用jquery, 而后開發的頁面使用Vuejs. vue可以作為一部分嵌入到項目中. 后面再逐漸替換.

    • 如果是使用vue開發新項目, 那么可以使用vue的全家桶. 包括核心庫和和生態系統. 比如: Core+Vue Router + Vuex.

  3. Vuejs的核心功能

    • 解耦視圖和數據
    • 可復用的組件
    • 前端路由技術
    • 狀態管理
    • 虛擬DOM

二. Vuejs安裝方式

vuejs的安裝有三種方式, 

  1. CDN引入

    • CDN引入有兩個版本: 開發環境和生產環境. 也就是說, 不用本地安裝vue, 而是引入CDN中vue的包
      <!-- 開發環境 -->
      <script src= "https://cdn.jsdelivr.net/npm/vue/dist/vue.js></script>
      <!-- 生產環境 -->
      <script src= "https://cdn.jsdelivr.net/npm/vue/vue.js></script>


      生產環境建議帶上版本號, 避免因版本問題產生異常
      <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>

      使用這個版本的優點是: 速度快. 缺點也很明顯: 那就是每次打開都要去cdn上下載, 浪費時間. 學習不建議使用這種方式

  2. 下載和引入

    • 這里也有兩個版本, 開發環境和生產環境, 在CDN上下載很慢, 那么我們可以將vue.js下載到本地, 引入到項目中
      開發環境
      https://vuejs.org/js/vue.js
      
      生產環境
      https://vuejs.org/js/vue.min.js

      開發時可以使用開發包, 可以看到源碼. 生產環境的包更穩定, 體積也會更小

  3. NPM安裝管理

    • 在用 Vue 構建大型應用時推薦使用 NPM 安裝
    • vuejs可以和webpack和CLI等模塊配合使用
    • 后續學習都是用這種方式操作的.

三. Vuejs初體驗

  1. Hello Vuejs

    我們學習程序, 經典代碼helloworld. 這里說一下開發工具, 開發工具建議使用vscode, 因為里面有很多插件, 但是其他也不是不可以哈

    我們在感受vue的時候, 為了簡單, 方便的體驗vue, 我們使用第二種方式(注: 后面詳細研究還是會使用npm編譯的方式), 下載vue.js, 並引入到項目中. 接下來開始操作.

    • 第一步: 先搭建一個簡單的項目. 我的項目名稱就叫vue-study. 在里面創建一個文件夾js, 項目結構如下:

    

    •  第二步: 然后下載vue.js, 將其放入到js文件夾中

    •  第三步: 寫一個html頁面, 並引入vue.js.

      <html>
          <head>
              <title>第一個vue程序</title>
              <script src="../js/vue.js"></script>
          </head>
          <body>
              
          </body>
      </html>

      我們看到, 第一步引入了vue.js. 其實這里有個簡單的辦法, 只需要把項目中js拖進來, 就可以了.引入了vue.js, 那么要如何使用呢? vue.js我們可以理解為對象. 使用使用new Vue()的方式.

      <html>
      
          <head>
              <title>第一個vue程序</title>
              <script src="../js/vue.js"></script>
          </head>
      
          <body>
              <div id="app">{{message}}</div>
              <script> const app = new Vue({ el: "#app", data: { message: "hello, 盛開的太陽!" } }); </script>
          </body>
      </html>

      如上, 我們看到了new Vue(), 相當於把這個對象構建了一份. 然后賦值給了一個常量const app. 這里需要說一下, 以前,我們都是直接使用var, 既可以設置變量也可以設置常量, 但在vue中, 我們的變量和常量都有自己的聲明方式

      聲明方式:  常量使用const, 變量使用let.

      創建vue對象的時候, 傳入了一個option, option中有兩個元素

      el:全稱element, 表示指向的元素.其值使用的是jquery表達式. 該屬性決定了這個vue對象掛載到那個元素上, 可以看出, 我們這里是掛載到了id="app"的元素上
      
      data: 這個屬性用來存儲數據, 這些數據可以試試手動寫的, 也可以是動態從服務端取的

      data定義數據. 這里需要重點說一下了. vue采用的是VMMV的設計模式, 也就是數據和試圖分離. 這里的data指的就是數據. 而id="app"的div是視圖. 當頁面解析的時候, 解析到script腳本時發現, 我們已經將div交給vue容器了, 那么, 這時候, vue就會去尋找目標元素是否有待填補的變量. 這里我們看到<div id="app">{{message}}</div>里面定義了一個變量message, 而這個變量在vue容器中進行了聲明, 因此可以進行對應的自動填充. 

       這里如果暫時不理解, 也沒關系, 先混個眼熟, 后面還有詳細講解

    • 第四步: 分析瀏覽器執行代碼的流程

       1 <html>
       2 
       3     <head>
       4         <title>第一個vue程序</title>
       5         <script src="../js/vue.js"></script>
       6     </head>
       7 
       8     <body>
       9         <div id="app">{{message}}</div>
      10         <script>
      11             const app = new Vue({
      12                 el: "#app",
      13                 data: {
      14                     message: "hello, 盛開的太陽!"
      15                 }
      16             });
      17         </script>
      18     </body>
      19 </html>

      頁面渲染, 首先加載1-10行, 顯示出對應的html. 執行到第11行的時候, 創建了vue實例, 並且對照html進行解析和修改.

  2. Vue列表展示

    下面來看一個稍微復雜一點的例子---列表展示

    先來看看效果

  

    下面思考, 如果我們使用jquery會如何實現呢? 需要些一個for循環, 然后在里面定義n個li, 然后拼裝數據. 很復雜.  然而, 使用vue完全不需要在js代碼中拼裝html元素的數據, 下面來看看怎么做

    • 第一步: 新建一個html頁面, 命名為02-list.html, 然后引入vue.js

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>列表頁面</title>
          <script src="../js/vue.js"></script>
      </head>
      <body>
          
      </body>
      </html>
    •  第二步構建vue對象

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>Title</title>
          <script src="../js/vue.js"></script>
      </head>
      <body>
          <div id="app">
              <h1>{{title}}</h1>
              <ul>
                  <li v-for = "item in languages">{{item}}</li>
              </ul>
          </div>
          <script>
              const app = new Vue({ el: "#app", data:{ title: "常見的后端編程語言有哪些?", languages: ["python", "go", "java", "net", "php", "c++"] } }); </script>
      </body>
      </html>

      這里指定了當前構建的vue對象掛載在id="app"的元素上. 並填充值title和languages. 和上一個案例不同, 這里有一個數組元素languages. 那么數組元素應該如何取值呢?

      <ul>
          <li v-for = "item in languages">{{item}}</li>
      </ul>

      注意紅色粗體部分. 使用了一個vue的指令v-for, 這是表示for循環, 這個第一次見到, 先熟悉一下. 后面還會具體講. 我們以前使用jquery會怎么寫呢?

      <ul>
          <li >python</li>
          <li >go</li>
          <li >java</li>
          <li >php</li>
          <li >.net</li>
          <li >...</li>
      </ul>

      以前我們要這么寫一大堆, 如果是動態從服務端取數據, 那么還要拼li代碼, 很容易出錯, 還很費勁. 但使用了vue指令, 我們發現一句話就搞定了, 這里是不是可以傲嬌一下. 怪不得vue能這么流行.

       

  3. 案例:計數器

     計數器是一個小的綜合案例, 通過這個案例來再次感受一下vue的強大. 我們先來看一下效果

    

    分析: 這里有一個變量, 兩個按鈕. 點擊+, 數字加1, 點擊-, 數字減1. 下面我們就來實現這個功能

    • 第一步: 創建一個html文件03-計數器.html 
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>Title</title>
          <script src="../js/vue.js"></script>
      </head>
      <body>
          <div id="app"> 當前數字: {{counter}} <br>
              <button v-on:click="counter++"> + </button>
              <button v-on:click="counter--"> - </button>
          </div>
          <script>
              const app  = new Vue({ el: "#app", data:{ counter: 0 } }); </script>
      </body>
      </html>

      引入vue.js, 並創建一個Vue對象. 這些之前都說過, 就不多說了. 接下來看看

      <button v-on:click="counter++"> + </button>

      這是什么意思呢? 這是vue的寫法. v-on是vue的指令, 這里先有個印象, 后面會詳細講解. v-on表示要執行一個事件, :click就是具體的事件, 這里是點擊事件, 點擊后執行什么邏輯呢? 執行counter ++. 是不是很神奇? 也許還沒有感覺, 那么我們來看看, 如果是jQuery, 要怎么做吧?

      1. 給+按鈕添加一個點擊事件
      2. 獲取counter計數器對象的值
      3. 對counter進行++
      4. 再講counter計算后的結果賦值給計數器對象.

      現在感受到了吧, jquery是命令式編程, 一行命令執行一個語句. 這里要執行好幾句話, 而vue一句話就搞定了.

       
    • 第二步: 這里click事件中就有一句話, counter++, 那么要是有好多邏輯怎么辦呢? 那就需要提出來單獨處理了.
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>Title</title>
          <script src="../js/vue.js"></script>
      </head>
      <body>
          <div id="app">
              當前數字: {{counter}}
              <br>
              <button v-on:click="add"> + </button>
              <button v-on:click="sub"> - </button>
          </div>
          <script>
              const app  = new Vue({
                  el: "#app",
                  data:{
                      counter: 0
                  },
                  methods: { add: function() { console.info("add方法被執行") this.counter ++; }, sub: function () { console.info("sub方法被執行") this.counter --; } }
              });
          </script>
      </body>
      </html>

      在vue里面,要想增加一個事件, 那就放在methods屬性里就可以了. 這里有一點需要注意. 在方法里要對data中的變量執行counter ++, 直接這么寫是不行的, 需要加上this.counter++. this表示的是new出來的Vue對象. 有朋友可能就要說了, this在方法里面, 不應該是表示當前方法么?vue做了一層代理, 所以, 這里的this指的是new Vue()對象.  

四. Vuejs的MVVM

  1. 什么是MVVM

    MVVM是Model-View-ViewModel的簡寫。它本質上就是MVC 的改進版。MVVM 就是將其中的View 的狀態和行為抽象化,讓我們將視圖 UI 和業務邏輯分開。當然這些事 ViewModel 已經幫我們做了,它可以取出 Model 的數據同時幫忙處理 View 中由於需要展示內容而涉及的業務邏輯。View綁定到ViewModel,然后執行一些命令在向它請求一個動作。而反過來,ViewModel跟Model通訊,告訴它更新來響應UI。這樣便使得為應用構建UI非常的容易。

    MVVM有助於將圖形用戶界面的開發與業務邏輯或后端邏輯(數據模型)的開發分離開來,這是通過置標語言或GUI代碼實現的。MVVM的視圖模型是一個值轉換器,這意味着視圖模型負責從模型中暴露(轉換)數據對象,以便輕松管理和呈現對象。在這方面,視圖模型比視圖做得更多,並且處理大部分視圖的顯示邏輯。 視圖模型可以實現中介者模式,組織對視圖所支持的用例集的后端邏輯的訪問。

  2. MVVM的優點

    MVVM模式和MVC模式一樣,主要目的是分離視圖(View)和模型(Model),有幾大優點

    • 低耦合。視圖(View)可以獨立於Model變化和修改,一個ViewModel可以綁定到不同的"View"上,當View變化的時候Model可以不變,當Model變化的時候View也可以不變。
    • 可重用性。你可以把一些視圖邏輯放在一個ViewModel里面,讓很多view重用這段視圖邏輯。
    • 獨立開發。開發人員可以專注於業務邏輯和數據的開發(ViewModel),設計人員可以專注於頁面設計,使用Expression Blend可以很容易設計界面並生成xaml代碼。
    • 可測試。界面素來是比較難於測試的,測試可以針對ViewModel來寫。 

  3. MVVM模式的組成部分

    • 模型

      模型是指代表真實狀態內容的 領域模型(面向對象),或指代表內容的 數據訪問層(以數據為中心)。
    • 視圖

      就像在 MVCMVP模式中一樣,視圖是用戶在屏幕上看到的結構、布局和外觀(UI)。
    • 視圖模型

      視圖模型是暴露公共屬性和命令的視圖的抽象。MVVM沒有MVC模式的控制器,也沒有MVP模式的presenter,有的是一個 綁定器。在視圖模型中,綁定器在視圖和數據綁定器之間進行通信。
    •  綁定器

      聲明性數據和命令綁定隱含在MVVM模式中。綁定器使開發人員免於被迫編寫樣板邏輯來同步視圖模型和視圖。在微軟的堆之外實現時,聲明性數據綁定技術的出現是實現該模式的一個關鍵因素

  4. Vue中的VMMV

    下圖不僅概括了MVVM模式(Model-View-ViewModel),還描述了在Vue.js中ViewModel是如何和View以及Model進行交互的。

    

 

 

     

    ViewModel是Vue.js的核心,它是一個Vue實例。Vue實例是作用於某一個HTML元素上的,這個元素可以是HTML的body元素,也可以是指定了id的某個元素。

    當創建了ViewModel后,雙向綁定是如何達成的呢?

    首先,我們將上圖中的DOM Listeners和Data Bindings看作兩個工具,它們是實現雙向綁定的關鍵。 
    從View側看,ViewModel中的DOM Listeners工具會幫我們監測頁面上DOM元素的變化,如果有變化,則更改Model中的數據; 
    從Model側看,當我們更新Model中的數據時,Data Bindings工具會幫我們更新頁面中的DOM元素。

    

    拿第一個案例來說

<html>

    <head>
        <title>第一個vue程序</title>
        <script src="../js/vue.js"></script>
    </head>

    <body>
        <div id="app">{{message}}</div>
        <script>
            const app = new Vue({ el: "#app", data: { message: "hello, 盛開的太陽!" } }); </script>
    </body>
</html>

 

在這里, 定義了一個View, 定義了model, 創建了一個Vue實例(view-model), 它用於連接view和model

在創建Vue實例時,需要傳入一個選項對象,選項對象可以包含數據、掛載元素、方法、模生命周期鈎子等等。

在這個示例中,選項對象的el屬性指向View,el: ‘#app’表示該Vue實例將掛載到<div id="app">...</div>這個元素;data屬性指向Model,data: { message: "hello, 盛開的太陽" 表示我們的Model是一個對象。

Vue.js有多種數據綁定的語法,最基礎的形式是文本插值,使用一對大括號語法,在運行時{{ message }}會被數據對象的message屬性替換,所以頁面上會輸出”hello, 盛開的太陽!”。

 

五. Vue實例的生命周期

每個 Vue 實例在被創建時都要經過一系列的初始化過程——例如,需要設置數據監聽、編譯模板、將實例掛載到 DOM 並在數據變化時更新 DOM 等。同時在這個過程中也會運行一些叫做生命周期鈎子的函數,這給了用戶在不同階段添加自己的代碼的機會。

比如 created 鈎子可以用來在一個實例被創建之后執行代碼:

new Vue({
  data: {
    a: 1
  },
  created: function () {
    // `this` 指向 vm 實例
    console.log('a is: ' + this.a)
  }
})
// => "a is: 1"

也有一些其它的鈎子,在實例生命周期的不同階段被調用,如 mountedupdated 和 destroyed。生命周期鈎子的 this 上下文指向調用它的 Vue 實例。

注意:

不要在選項 property 或回調上使用箭頭函數,比如
  created: () => console.log(this.a) 或 vm.$watch('a', newValue => this.myMethod())。
因為箭頭函數並沒有 thisthis 會作為變量一直向上級詞法作用域查找,直至找到為止,經常導致
Uncaught TypeError: Cannot read property of undefined 或
Uncaught TypeError: this.myMethod is not a function 之類的錯誤。

 

1. 生命周期圖示

下圖展示了實例的生命周期。你不需要立馬弄明白所有的東西,不過隨着你的不斷學習和使用,它的參考價值會越來越高。 

 

 2. Vue生命周期函數

如上圖, 常用的生命周期函數有: beforeCreate, created, beforeMount, mounted, beforeUpdate, updated, beforeDestory, destoryed, 這些鈎子函數都是回調函數, 在vue生命周期執行過重,方便用戶操作控制的入口

 

 六. Vue源碼

我們知道了vue的生命周期了, 接下來看看vue的源碼, 對vue的生命周期加深理解

源碼下載地址: https://github.com/vuejs/vue

我們選擇一個release版本. 下載代碼到本地

 

 

 

 下載好以后, 打開項目, 我們來看看項目結構.

 

 

 

剛開始, 我們不熟悉, 那么先猜測一下, 哪個是主要文件, 經驗告訴我們, src里面的才是主目錄, 在src中和核心目錄是core. 

 

 

 我們看到了index.js, 通常一個網站的入口是index.html, 而對應的js腳本就是index.js. 打開index.js

import Vue from './instance/index'
import { initGlobalAPI } from './global-api/index'
import { isServerRendering } from 'core/util/env'
import { FunctionalRenderContext } from 'core/vdom/create-functional-component'

initGlobalAPI(Vue)

Object.defineProperty(Vue.prototype, '$isServer', {
  get: isServerRendering
})

Object.defineProperty(Vue.prototype, '$ssrContext', {
  get () {
    /* istanbul ignore next */
    return this.$vnode && this.$vnode.ssrContext
  }
})

// expose FunctionalRenderContext for ssr runtime helper installation
Object.defineProperty(Vue, 'FunctionalRenderContext', {
  value: FunctionalRenderContext
})

Vue.version = '__VERSION__' export default Vue

這里面有兩句非常重要的話, 第一句

export default Vue

這句話表示export導出Vue, 我們new的就是這里導出的Vue. 我們看到index.js中沒有主邏輯, 那主邏輯在哪里呢? 在第二句話里面: 

import Vue from './instance/index'

導入了./instance/index中的文件. 我們來看看這個文件

import { initMixin } from './init'
import { stateMixin } from './state'
import { renderMixin } from './render'
import { eventsMixin } from './events'
import { lifecycleMixin } from './lifecycle'
import { warn } from '../util/index' function Vue (options) { if (process.env.NODE_ENV !== 'production' &&
    !(this instanceof Vue)
  ) {
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  this._init(options)
}

initMixin(Vue) stateMixin(Vue) eventsMixin(Vue) lifecycleMixin(Vue) renderMixin(Vue)

export default Vue

首先, 我們看到定義了一個Vue對象, 在對象里面執行了很多操作, 初始化, 事件監聽, 生命周期處理, 渲染等等. 這就是vue的整個流程. 我們進入到initMixin(Vue)初始化方法里面看一下

/* @flow */

import config from '../config'
import { initProxy } from './proxy'
import { initState } from './state'
import { initRender } from './render'
import { initEvents } from './events'
import { mark, measure } from '../util/perf'
import { initLifecycle, callHook } from './lifecycle'
import { initProvide, initInjections } from './inject'
import { extend, mergeOptions, formatComponentName } from '../util/index'

let uid = 0

export function initMixin (Vue: Class<Component>) {
  Vue.prototype._init = function (options?: Object) {
    const vm: Component = this
    // a uid
    vm._uid = uid++

    let startTag, endTag
    /* istanbul ignore if */
    if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
      startTag = `vue-perf-start:${vm._uid}`
      endTag = `vue-perf-end:${vm._uid}`
      mark(startTag)
    }

    // a flag to avoid this being observed
    vm._isVue = true
    // merge options
    if (options && options._isComponent) {
      // optimize internal component instantiation
      // since dynamic options merging is pretty slow, and none of the
      // internal component options needs special treatment.
      initInternalComponent(vm, options)
    } else {
      vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor),
        options || {},
        vm
      )
    }
    /* istanbul ignore else */
    if (process.env.NODE_ENV !== 'production') {
      initProxy(vm)
    } else {
      vm._renderProxy = vm
    }
    // expose real self
    vm._self = vm
    initLifecycle(vm) initEvents(vm) initRender(vm) callHook(vm, 'beforeCreate') initInjections(vm) // resolve injections before data/props initState(vm) initProvide(vm) // resolve provide after data/props callHook(vm, 'created') ......

初始化的時候又做了一系列的操作. 注意在方法創建之前有一個鈎子函數callHook(vm, 'beforeCreate'),  方法創建之后, 有一個callHook(vm, 'created')函數, 這里可以和上面的生命周期圖對比研究, 就能更加熟悉Vue的聲明周期了

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM