Vue2.x 總結

Vue2.x 總結

Vue 是一套用於構建用戶界面的漸進式框架

也意味着,既能夠把VUE做爲該應用的一部分嵌入到一個現成的服務端應用,或者在先後端分離的應用中,利用Vue 的核心庫及其生態系統,把更多的邏輯放在前端來實現。html

A Progressive Framework

漸進式框架前端

與Vue相比,React學習曲線陡峭,在學習React以前,須要瞭解JSX和ES2015,固然入門後,發現還要學習React全家桶。而Vue就能夠在簡單閱讀了文檔後,開始構建應用程序。vue

這就要得益於Vue主張的 漸進式
能夠簡單看下官方給出這張圖:react

a progressive framework

能夠看出來,主要是介紹了Vue設計思想,就是框架作分層設計,每層均可選,能夠單獨引入,爲不一樣的業務需求制定靈活的方案。主張最少,不會多作職責之外的事。webpack

Vue做者尤雨溪的觀點,Vue設計上包括的解決方案不少,可是使用者徹底不須要一上手,就把全部東西全都用上,由於徹底沒有必要,通常都是根據項目的複雜度,在覈心的基礎上任意選用其餘的部件,不必定要所有整合在一塊兒。git

這樣漸進式的解決方案,使得學習成本大大減小了。github

聲明式渲染

也就是說,DOM狀態只是數據狀態的一個映射,基本全部的框架都已經認同了這個見解,Vue也是主張 數據驅動狀態web

說到這裏,基本都會提到如今主流的MVVM的模式。
mvvmajax

採用了雙向數據綁定的思想,基本能夠分爲三層:vue-router

  • M(Model,模型層),負責業務數據相關。
  • V(View,視圖層),視圖相關,展現給用戶的交互界面,同時捕獲用戶的操做
  • VM(ViewModel, V與M鏈接的橋樑,也能夠看作控制器)。

基於這個思想,Vue從一開始就利用ViewModel與view,model進行交互
Vue mvvm
ViewModel是Vue.js的核心,它是一個Vue實例,做用在某個HTML元素上,通常都是指定 id= app的元素,圖中 的DOM listenersData Bindings能夠看作兩個工具,它們是實現雙向數據綁定的關鍵。

從用戶(View)角度看,DOM Liisteners利用在相應的元素上添加事件綁定,捕獲用戶的點擊,滑動等手勢動做,在事件流中改變對應的Model。好比 經常使用的 v-model 指令,就是捕獲表單元素的inputchange等事件,改變相應的綁定值。

從Model方向看,Data Bindings則將操做的數據變化,反應到view上。好比經過ajax 從後臺獲取的數據,能夠刷新數據列表,反應到用戶界面。這也是實現雙向數據綁定的關鍵。

Vue2中是經過Object.definedProperty方法中定義的getters和 setters構造器來實現數據響應的。能夠簡化下源碼中的實現:

Object.defineProperty(obj, key, {
         enumerable: true,
         configurable: true,
         get: function reactiveGetter () {
            return value
         },
         set: function reactiveSetter (newVal) {
             var value = getter ? getter.call(obj) : val;
             /* eslint-disable no-self-compare */
             if (newVal === value || (newVal !== newVal && value !== value)) {
               return
             }
             /* eslint-enable no-self-compare */
             if ("development" !== 'production' && customSetter) {
               customSetter();
             }
             if (setter) {
               setter.call(obj, newVal);
             } else {
               val = newVal;
             }
             childOb = !shallow && observe(newVal);
             dep.notify();
           }
       });
   }

經過這種方法定義對象obj上的某個屬性,每次獲取屬性值的時候就,會主動觸發get對應的回調函數,而後給該屬性賦值時,就會觸發裏面的set對應的回調函數,在set回調函數裏面,加入了dep.notify()方法,而後能夠看下這個方法

notify () {
 // stabilize the subscriber list first
 const subs = this.subs.slice()
 for (let i = 0, l = subs.length; i < l; i++) {
   subs[i].update()
 }
}

裏面的定義的常量subs每次深拷貝this.subs數組,數組裏面保存的就是全部的subscriber訂閱者,對應的發佈者就是obj裏面對應的屬性,或者說是Vue中的data值。通知全部的訂閱者,數據更新了。原生js實現發佈訂閱模式(publish/Subscribe),能夠參考這裏

經常使用基礎語法

hello world

<!DOCTYPE html>
  <html>
    <head>
      <meta charset="utf-8">
      <title>hello world</title>
      <script src="https://gw.alipayobjects.com/as/g/h5-lib/vue/2.4.4/vue.min.js"></script>
    </head>
    <body>
      <div id="app">
        {{message}}
      </div>
      <script>
        var app = new Vue({
          el:"#app",
          data:{
            message:'hello vue'
          }
        })
      </script>
    </body>
  </html>

這樣就簡單建立了一個Vue 應用,數據message 和DOM頁面產生了關聯,相似html模板引擎,把相應的數據渲染到頁面中。

指令

指令 (Directives) 是帶有 v- 前綴的特殊屬性,這些特殊屬性能夠響應式的做用域DOM,

  • v-if 接受Boolean 類型,好比: <p v-if = "seen">如今你看到我了</p> ,經過seen的真假來插入/移除< p>元素。 這裏判斷的時候使用 === 全等,seen = 「false」 的時候,也會插入
  • v-bind,響應式的更新HTM屬性。完整形式<a v-bind:href="url">...</a> 。 縮寫形式<a :href="url">...</a>。 經常使用於改變dom的style, class ,href ,src 等屬性。 動態綁定的屬性能夠寫成 :屬性名="屬性值"
  • v-on,綁定點擊事件,好比 完整形式<a v-on:click="doSomething">...</a>,簡寫形式 <a @click="doSomething">...</a>, doSomething對應的指向methods裏面定義的函數。 注意,除非在須要傳遞參數的時候,寫成 @click = "doSomething($event,args1,args2)",$event表明事件對象,args表明自定義參數

style or class

v-bind用於classstyle時,Vue.js作了專門的加強,表達式結果的類型除了字符串以外,還能夠是對象或數組。

綁定HTML Class

  • 直接賦值。

    < div :class="className"> </div>
    data:{
       className:"div-class"
    }

    結果:

    <div class="div-class"></div>
  • 對象語法。

    < div class="static" :class="{active:isActive,'text-danger':hasError}" /></div>
    
       data: {
         isActive:true,
         hasError:false,
       }

    結果:

    <div class="static active" ></div>
  • 數組語法,

    <div :class="['one',bTwo?'two':'three']" </div>
    
      data:{
         bTwo:true
      }
    
      <style>
         .one{}
         .two{}

    結果:

    <div class='one two'></div>

綁定內聯樣式

  • 對象語法

    <div :style = "{color:activeColor,fontSize:fontSize+'px'}"></div>
         data: {
           activeColor: 'red',
           fontSize: 30
         }

    結果:

    <div style="color:red:font-size:30px;"></div>
  • 數組語法

    <div v-bind:style="[baseStyles, overridingStyles]"></div>
    
      data:{
        baseStyles:{
          color:'red'
        },
        overridingStyles:{
          fontSize:'30px'
        }
    
      }

    結果:

    <div style="color:red:font-size:30px;"></div>

條件渲染

  • v-if

    一樣也是一個指令,添加到一個元素上,對應利用 === 全等判斷綁定的值truefalse來決定是否渲染裏面的節點。
    能夠與它一塊兒使用的指令有 v-else ,v-else-if,v-else 元素必須緊跟在都有v-if或者v-else-if的元素後面

    <div v-if= "num===0">
       0
       </div>
       <div v-else-if ="num ===1">
       1
       </div>
       <div v-else>
          not 0/1
       </div>
    
       data:{
         num:3
       }

    結果:

    <div>
        not 0/1
    </div>
  • v-show

    根據條件展現元素的選項,簡單的切換元素的內聯樣式display

    適用場景:

    • 頁面複用的(modal)彈出窗,利用v-show,控制顯示或者隱藏。參考這裏
    • tab頁面切換的時候,不一樣頁面不相互影響,利用v-show不會銷燬元素,參考這裏

列表渲染

  • v-for 把一個數組對應爲一組元素,推薦給每一個列表,添加惟一標識的key

    <div v-for="(item,idx) in items" :key="idx">
         {{idx}} --- {{item.product}}
      </div>
    
      data:{
        items:[
         {product:"foo"},
         {product:"bar"}
        ]
      }

    結果:

    <div>
          0 --- foo
    </div>
    <div>
        1 --- bar
    </div>
  • 數組更新檢測

    包含一組觀察數組變異方法,用來觸發試圖更新:
    push(),pop(),shift(),unshift(),splice(),sort(),reverse()

    利用索引給數組賦值或者手動修改數組的長度,都不會被檢測到更新
    替代方案:

    Vue.set(example1.items,indexOfItem,newValue)
     // 或者
     example1.items.splice(indexOfItem,1,newValue)
    
     // 改變數組的長度:
     example1.items.splice(newLength)

    對於對象中的屬性添加或刪除,也可使用Vue.set方法,或者在定義的Vue實例內部,使用this.$set,this.$set只是全局Vue.set的別名

    Vue.set(object,key,value)

v-model 表單綁定

使用v-model在表單input<textarea>元素上建立雙向數據綁定。

<input v-model = "message" placeholer= "edit me">
 <p>Message is {{message}}</p>

這樣input輸入框中的值就與P標籤中的內容綁定了,一樣也適用textareacheckbox,
radio,select等表單。

實質上,v-model只是語法糖。

<input v-model = "something"

對應的完整形式:

<input
       v-bind:value="something"
       v-on:input="something = $event.target.value">

表單數組校驗。
利用修飾符 .number進行數字校驗,是最實用的方法,在v-model上添加number修飾符。

<input v-model.number="age" type= "number" >

組件通訊

組件能夠用來擴展HTML,封裝可重用的代碼,全部的組件都是Vue的實例。

命名: 建議遵循W3C規則(小寫,而且包含一個短杆)

組件組合:使用中最多見的是造成父子組件的關係,組件A在它的模板中使用了組件B,那麼他們之間就須要通訊。組件間通訊的關係能夠用下面的圖示代表:
props-events

歸納爲: prop 向下傳遞,事件向上傳遞。

  • 利用Prop 傳遞數據,同時藉助.sync,進行雙向數據通訊

    父組件的數據要經過Prop才能下發到子組件中。
    prop 屬性命名:在使用camelCase(駝峯式命名)的prop須要裝換成對應的kebab-case(短橫線分隔式命名)。同時,也能夠綁定動態的Prop傳遞給子組件。

    而後,子組件中prop值改變,是沒法反應到父組件中的。在Vue1.x中使用.sync修飾符能夠提供雙向綁定,可是違背了單向數據流的思想,在2.0中就移除了,但在2.3.0中做爲一種語法糖的形式引入了

    Vue.component('child',{
        props:['myMessage'],
        template:'<span @click="handleClick">{{myMessage}}</span>',
       methods:{
          handleClick:function(){
            this.$emit("update:myMessage","message from child")
          }
       }
      })
    
      <!--  在HTML 中使用時   .sync的語法糖  -->
      <child :my-message.sync="parentMsg"></child>

    點擊子組件中的span,就能夠改變父組件中prop綁定的parentMsg值。.sync語法也會被擴展成爲

    <child :my-message="parentMsg" @update:myMessage = "val => parentMsg = val"

    裏面 @update:myMessage 就是綁定了自定義事件,回過來看下上面父子通信的規則 prop向下傳遞,事件向上傳遞,也很是符合。

  • 非父子組件通訊

    官方推薦使用空的Vue實例做事件總線

    var bus = new Vue();
    
        // 在A 組件中觸發了事件
         bus.$emit("change",1);
    
        // 在B 組件中監聽事件
        bus.$on('change',function(id){})

狀態管理

組件通訊變得複雜時,就要考慮使用全局狀態管理,Vue也提供了vuex狀態管理庫。

Vuex 是一個專門爲Vue.js應用程序開發的狀態管理模式。它採用集中式存儲管理應用的全部組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。

固然,使用Vuex並非首選,只有在構建中大型單頁面應用時,考慮到全局的狀態管理,天然就會想到Vuex。
下面這張圖,表示狀態管理「單向數據流」的理念
vuex

核心概念包括(簡單計數器爲例):

  • state: 做爲單一狀態樹,惟一的數據源,而且每一個應用僅僅包含一個store實例,通常經過計算屬性獲取某個狀態。

    state:{
      count:0
    },
  • getter: 至關於store的計算屬性,數據源發生變化時,返回通過處理後的值,

    getters:{
       getState:state=>{
         return state.count
       }
    },
  • mutation: 相似於事件,對應的回調函數到狀態進行處理,必須經過store.commit的方式手動觸發

    mutations:{
      increment:state => state.count++,
      decrement:state => state.count--
    },
  • actions: 利用commit提交mutation,能夠執行異步操做,經過 store.dispatch方式觸發

    // 模擬異步請求
    var delay = (timeout,cb) => new Promise(resolve => setTimeout(()=>{cb(); resolve("test incrementAsync")},timeout));
    
    actions:{
      incrementAsync({commit}) {
          return delay(600,function(){commit("increment")})
    
      },
    }
  • module: 當store對象比較龐大的時候,能夠考慮將store分隔成模板。每一個模塊擁有本身的state、mutation、action、getter。不多狀況下使用

把全部部分組合起來,就構成一個簡單的計數器:

var delay = (timeout,cb) => new Promise(resolve => setTimeout(()=>{cb(); resolve("test incrementAsync")},timeout));
var store = new Vuex.Store({
  state:{
    count:0
  },
  getters:{
     getState:state=>{
       return state.count
     }
  },
  mutations:{
    increment:state => state.count++,
    decrement:state => state.count--
  },
  actions:{
    incrementAsync({commit}) {
        return delay(600,function(){commit("increment")})
    },
    decrementAsync({commit}) {
        return delay(600,function(){commit('decrement')});
    }
  }
})

而後組件中觸發actions,就能夠

store.dispatch('decrementAsync').then(() => {
// ...
})

在瀏覽器中,使用vue-devtool,試下時間旅行功能。
vue-devtool

頁面路由

使用Vue.js建立單頁面應用,就可使用vue-router,目前版本是3.0.1,把組件映射到對應的路由,經過改變url來渲染不一樣的頁面。官方中文文檔

vue-router 默認hash模式,每次url只會改變#後面對應的值,頁面就不會從新加載,而且也不須要服務器端做任何配置。

若是使用路由的history模式,url就會正常http://yoursite.com/user/id,只須要添加配置mode:'history',同時須要後端配置,否則頁面從新刷新,會匹配不到任何資源。

不一樣模式下的服務器配置及生產環境部署,能夠參考vue、react等單頁面項目應該這樣部署到服務器.

基礎概念:

  • < router-link>

    <router-link to="/foo">Go to Foo </router-link>
      <router-link to= "/bar">Go to Bar</router-link>

    使用router-link 組件導航,經過傳入to屬性指定連接,至關於原生的a 標籤。

  • < router-view>
    路由出口,路由匹配到的組件將渲染在這裏

    <router-view></router-view>

    能夠在上面添加一些過渡效果

    <transiton name="slide">
         <router-view></router-view>
      </transiton>
  • 初始化路由配置

    若是使用vue-cli腳手架構造項目,在init的時候,會出現選項提示用戶安裝路由

    vue-router

    確認後,自動生成src/router.js文件,相關路由配置文件就能夠寫在裏面。

    // 首先引入不一樣的vue組件(默認安裝了[vue-loader](https://vue-loader.vuejs.org/zh-cn/start/spec.html),每一個.vue文件當作一個完整的組件)
      import components1 from "./page/xx.vue"
      import components2 from "./page/xx2.vue"
    
      // router 數組用來定義路由配置,非嵌套路由
      const routers = [
         {path:'/foo',component:components1},
         {path:'/bar',component:components2}
      ]
    
     // 最後拋出這個配置數組
      export default routes;

    注入到router配置參數裏面

    const app = new Vue({
            router
       }).$mount("#app")

    存在嵌套路由的時候,須要使用 children配置,好比上面的components1組件內部包含本身的嵌套<router-view>,就可使用嵌套路由。

    const routers = [
         { path:'/foo',
           component:components1,
           children:[
             // 當  /foo/detail 匹配成功後,component3 會被渲染在components1中 <router-view> 的位置
              {  path:'detail',
                  component:component3
              },
            // 若是 /foo 匹配成功,沒有匹配子路由,默認就會渲染這個空的子路由。
              {
                path:'',
                component:component4
              }
           ]
         }
      ]
  • router 實例方法
    在Vue實例內部,能夠經過this.$router獲取實例對象,

    • router.push({path:'/user',params:{id:'123'}}) 跳轉
    • router.replace(),與上面相同,不會添加新的記錄。
    • router.go(-1),表示在路由記錄中前進或者後退多少步。
    • 在html <template></template>中,能夠經過 {{$route}},獲取路由配置的相關信息,從而渲染DOM。好比: 經過

      <template v-for="(items,index) in $router.options.routes">
        <title>
           {{items.name}}
        </title>
      </template>

      就能夠將路由配置信息與頁面導航欄對應,列表渲染出導航欄,

    • watch方法中監聽$route,能夠動態配置組件,不一樣url複用同一組件

      watch:{
              `$route`:function(to,from) {
                  // 經過to,from 獲取url信息
              }
           }
    • 導航守衛(路由鉤子)

      經過註冊一個全局路由鉤子函數,在初始化const router = new VueRouter({})的時候,定義router.beforeEach((to,from,next)=> {...}),在每次進入目標路由以前觸發。配合Vuex能夠很是方便的進行權限管理

      router.beforeEach((to, from, next) => {
             if (store.getters.getisAuthority) {
               // 檢查已經登陸了,就繼續跳轉。
               next()
             }else if(to.fullPath === "/login"){
                 // 跳轉到登陸頁面,則清空登陸相關信息
                 clearCookie()
                 next()
             } else {
               next({
                   path:"/login"
               });
          }})

Vue-cli入門

Vue 提供一個 官方命令行工具,可用於快速搭建大型單頁面應用

目前已經發布到了V3.0.0-alpha.5

npm install -g @vue/cli
  vue create my-project

基本用法,文檔裏面也比較清楚,參考這裏,
經過下面幾步,快速搭建項目基礎結構。

# 全局安裝 vue-cli
    $ npm install --global vue-cli
    # 建立一個基於 webpack 模板的新項目
    $ vue init webpack my-project
    # 安裝依賴,走你
    $ cd my-project
    $ npm install/ yarn
    $ npm run dev

(若是沒有使用任何框架的基礎上,也想快速搭建一個大型項目的目錄結構,能夠考慮yeoman快速生成一個新的項目)

基礎配置:

  • 修改開發環境下port

    /config/index.js文件中, 手動修改 module.exports = { dev:{ port :8080}}

  • 配置代理

    /config/index.js目錄下,(以代理3000端口上數據請求爲例)

    dev: {
              proxyTable: {
                '/rest/*':{
                          target:'http://127.0.0.1:3000',
                          secure:false,
                          pathRewrite:{
                             '^/rest':''
                          }
                      }
              },
  • 生產環境關閉sourcemap

    /config/index.js目錄下,build:{} 中的productionSourceMap改成false

  • 配置路徑別名(alias)

    一般在項目中會看到諸如這樣的 import Cookie from "@/util/cookie.js"的引入,@就是vue-cli中默認設置的alias

    /build/webpack.base.conf.js/文件中,resolve對象下添加屬性,指向對應的路徑

    resolve:{
         alias:{
           'page':path.resolve(__dirname,'../src/page')
         }
      }
  • 區分不一樣環境

    • 經過process.env.NODE_ENV值區分

      /build/webpack.dev.conf.js/build/webpack.prod.conf.js中,經過

      new webpack.DefinePlugin({
          'process.env': env
       }),

      建立了編譯時能夠配置的全局常量,用來區分開發/發佈/測試環境,env對應的值,能夠在/config/目錄下的,*.dev.js文件下配置的。

      而後,在其它業務代碼裏面,直接使用這個全局變量,好比在 main.js裏面:

      if(process.env.NODE_ENV === "development"){
               console.log("開發環境")
           }
    • 經過命令行區分不一樣環境

      一樣使用上面的方法,添加一個全局變量,不一樣的是從命令行中獲取參數。
      好比,打包時還區分 發佈環境 和 預發環境,就能夠修改以下,

      new webpack.DefinePlugin({
         'process.env': env,
         'VERSION':process.argv[2] == "pro"?'"pro"':'"sit"'
      }),

      在命令行中打包時,可使用 npm run build --env sit,在業務代碼中,經過全局變量VERSION,一樣能夠區分不一樣環境。

參考連接

相關文章
相關標籤/搜索