Vue入門與進(jìn)階

1. Vue概述

1.1 Vue介紹

Vue 是一套用于構(gòu)建用戶界面的漸進(jìn)式框架。

1.2 Vue核心思想

  1. 雙向數(shù)據(jù)綁定
    Vue雙向數(shù)據(jù)綁定利用了Object對(duì)象的set()get()方法,原理如下:
  <input type="text" id="userName" />
  <span id="uName"></span>
  <script>
    const obj = {}
    Object.defineProperty(obj, 'text', {
      get: function(val) {
        console.log('get init');
      },
      set: function(val) {
        console.log('set:' + val);
        ipt.value = val;
        span.innerText = val;
      }
    })
    const ipt = document.getElementById('userName');
    const span = document.getElementById('uName');
    ipt.addEventListener('keyup', function(e) {
      obj.text = e.target.value;
    })
  </script>

1.3 Vue與React對(duì)比

1.3.1 不同點(diǎn)

一干毅、Vue

  • 簡(jiǎn)單的語(yǔ)法和項(xiàng)目構(gòu)建。

二、React

  • 適用于大型項(xiàng)目以及更好的可測(cè)試性窿给。
  • 更大的生態(tài)圈帶來(lái)的更多的支持工具馋辈。

1.3.2 相同點(diǎn)

  • 虛擬DOM
  • 輕量級(jí)
  • 響應(yīng)式
  • 服務(wù)端渲染
  • 易于集成路由工具抚芦、打包工具和狀態(tài)管理工具
  • 優(yōu)秀的支持和社區(qū)

2. Vue基礎(chǔ)語(yǔ)法

2.1 Vue環(huán)境搭建

2.1.1 環(huán)境構(gòu)建方式

  1. 官方拷貝
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
  2. npm 安裝
  3. vue-cli工具構(gòu)建

2.1.1 vue-cli工具構(gòu)建SPA應(yīng)用

  1. npm i -g vue-cli
  2. vue init webpack-simple demo
    初始化一個(gè)簡(jiǎn)單的webpack項(xiàng)目
  3. vue init webpack demo
    初始化一個(gè)完整的webpack項(xiàng)目

2.2 Vue基礎(chǔ)語(yǔ)法

  1. 模板語(yǔ)法
  • Mustache語(yǔ)法:{{msg}}
  • Html賦值:v-html = ""
  • 綁定屬性: v-bind:id = ""
  • 使用表達(dá)式:{{ok ? 'YES' : 'NO'}}
  • 文本賦值:v-text = ""
  • 指令:v-if = ""
  • 過(guò)濾器:{{message | capitalize}}v-bind:id = "rawId | formtaId"
    注釋: vue組件中的data推薦使用方法的方式data(){return {}}返回?cái)?shù)據(jù),這樣不同組件實(shí)例之間就不會(huì)共用數(shù)據(jù)迈螟。
  1. ClassStyle綁定
  • 對(duì)象語(yǔ)法
<div v-bind:class="{active: isActive, 'text-danger': hasError}">
  • 數(shù)組語(yǔ)法
<div v-bind:class="[activeClass, errorClass]">
data: {
  activeClass: 'active',
  errorClass: 'text-danger'
}
  • style綁定
<div v-bind:style="{color: activeColor, fontSize: fontSize + 'px'}">
  1. 條件渲染
  • v-if
  • v-else
  • v-else-if
  • v-show
  • v-cloak
  1. 事件處理器
  • v-on:click="greet" 叉抡、 @click="greet"
  • v-on:click.stopv-on:click.stop.prevent答毫、v-on:click.self褥民、v-on:click.once
  • v-on:keyup.enter/tab/delete/esc/space/up/down/left/right
  1. Vue組件
  • 全局組件和局部組件
    單頁(yè)面應(yīng)用一般使用的都是局部組件。
  • 父子組件通訊-數(shù)據(jù)傳遞
//父組件
<template>
  <div class="hello">
    <Counter v-bind:num="num" v-on:incre="increment" v-on:decre="decrement"/>
    <span>{{`parent: ${num}`}}</span>
  </div>
</template>
<script>
import Counter from './Counter'
export default {
  data () {
    return {
      num: 10
    }
  },
  components: {
    Counter
  },
  methods: {
    increment() {
      this.num++
    },
    decrement() {
      this.num--
    }
  }
}
</script>

//子組件
<template>
  <div>
    <button @click="increment">+</button>
    <button v-on:click="decrement">-</button>
    <p><span>{{num}}</span></p>
  </div>
</template>
<script>
export default {
  props: ['num'],
  methods: {
    increment() {
      this.$emit('incre');
    },
    decrement() {
      this.$emit('decre')
    }
  }
}
</script>
  • Slot
    使用slot可以減少父組件props傳值的數(shù)量以及子組件$emit觸發(fā)父組件方法的數(shù)量洗搂。
 <modal v-bind:mdShow="mdShowCard" v-on:close="closeModelCard">
   <p slot="message">
     <svg class="icon-status-ok">
       <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#icon-cart"></use>
     </svg>
     <span>加入購(gòu)物車成功</span>
   </p>
   <div slot="btnGroup">
     <a class="btn btn--m" @click="mdShowCard=false">繼續(xù)購(gòu)物</a>
     <router-link class="btn btn--m btn--red" href="javascript:;" to="/cart">查看購(gòu)物車</router-link>
   </div>
 </modal>

2.3 路由 vue-router

2.3.1路由基礎(chǔ)介紹

  1. 路由
    根據(jù)不同的url地址展示不同的內(nèi)容或頁(yè)面消返。
  2. 后端路由
    服務(wù)器根據(jù)url地址返回不同頁(yè)面。
  3. 前端路由
    不同路由對(duì)應(yīng)不同內(nèi)容或頁(yè)面的任務(wù)交給前端來(lái)做耘拇。
  4. 前端路由使用場(chǎng)景
    單頁(yè)面應(yīng)用撵颊。
  5. 前端路由的優(yōu)缺點(diǎn)
    優(yōu)點(diǎn):路由跳轉(zhuǎn)用戶體驗(yàn)好嚼松。
    缺點(diǎn):不利于SEO探熔;瀏覽器前進(jìn)后退重新發(fā)送請(qǐng)求,沒(méi)有利用緩存村生;無(wú)法記住之前頁(yè)面的滾動(dòng)位置嘉涌。
  6. vue-router介紹
    vue-router官網(wǎng)
    (1) 跳轉(zhuǎn)組件
    <router-link></router-link>
    注釋: router-link就是一個(gè)封裝好的a標(biāo)簽妻熊,可以添加樣式夸浅。
    (2) js跳轉(zhuǎn)
    this.$router.push({path: ''})
    (3) 展示組件
    <router-view></router-view>
    注釋: vue-router是對(duì)historyAPI的封裝。

2.3.2. 動(dòng)態(tài)路由匹配

  1. 動(dòng)態(tài)路由介紹
模式 匹配路徑 $route.params
/user/:username /user/even {username: 'even'}
/user/:username/post/:post_id /user/even/post/123 {username: 'even', post_id: 123}
  1. 動(dòng)態(tài)路由的使用
//路由入口文件: scr/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import GoodList from '@/views/GoodList'
Vue.use(Router)
export default new Router({
  mode: 'history', //默認(rèn)值為hash
  routes: [
    {
      path: '/goods/:goodsId/user/:userName',
      name: 'GoodList',
      component: GoodList
    }
  ]
})
//src/views/GoodsList.vue文件
<template>
  <div>
    <div>這是商品列表頁(yè)面</div>
    <span>{{$route.params.goodsId}}</span>
    <span>{{$route.params.userName}}</span>
  </div>
</template>
<script>
export default {}
  • 使用vue-cli工具構(gòu)建的項(xiàng)目已經(jīng)嵌套vue-router固耘。
  • 路徑完全匹配模式(/goods/@@@/user/&&&)才能夠訪問(wèn)到該路由視圖题篷。
  • mode 默認(rèn)取值為hash,此時(shí)通過(guò)# + 路徑才能訪問(wèn)到厅目。如果取值為history番枚,則不用加#

2.3.3. 嵌套路由

  1. 嵌套路由的使用
//路由入口文件: scr/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import GoodList from '@/views/GoodList'
import Title from '../views/Title'
import Image from '../views/Image'

Vue.use(Router)

export default new Router({
  mode: 'history', //默認(rèn)值為hash
  routes: [
    {
      path: '/goods',
      name: 'GoodList',
      component: GoodList,
      children: [
        {
          path: 'title',
          name: 'title',
          component: Title
        },
        {
          path: 'img',
          name: 'img',
          component: Image
        }
      ]
    }
  ]
})
//src/views/GoodsList.vue文件
<template>
  <div>
    <div>這是商品列表頁(yè)面</div>
    <router-link to="/goods/title">
      顯示標(biāo)題子路由
    </router-link>
    <router-link to="/goods/img">
      顯示圖片子路由
    </router-link>
    <div>
      <router-view></router-view>
    </div>
  </div>
</template>
<script>
export default {}
</script>
//src/views/Image.vue文件
<template>
  <div>圖片子路由</div>
</template>
<script>
export default {}
</script>
//src/views/Title.vue文件
<template>
  <div>標(biāo)題子路由</div>
</template>
<script>
export default {}
</script>
  • children處注冊(cè)路由時(shí)使用相對(duì)于父路由的路徑即可损敷,在router-linkto屬性跳轉(zhuǎn)地址要使用完整路徑葫笼。
  • 從子路由的用法可知,路由的本質(zhì)并不是整個(gè)頁(yè)面的顯示/隱藏切換拗馒,而是頁(yè)面某個(gè)區(qū)域的顯示隱藏切換路星。

2.3.4. 編程式路由

  1. 編程式路由介紹
    使用js實(shí)現(xiàn)頁(yè)面的跳轉(zhuǎn)。
  • $router.push("name")
  • $router.push({path: "name"})
  • $router.push({path: "name?a=123})
  • $router.push({path: "name", query: {a: 123}})
  • $router.go(1/-1)
    注意: 對(duì)比區(qū)分query參數(shù)的傳遞與動(dòng)態(tài)路由params參數(shù)的傳遞诱桂。 query傳遞的是?a=1;b=2字段洋丐,通過(guò)$route.query.key的方式取值。動(dòng)態(tài)參數(shù)傳遞的是/a/b字段挥等,通過(guò)$route.params.key的方式取值友绝。
    總結(jié):①$route.query.key獲取的是當(dāng)前urlquery中的字段值,$route.params.key獲取的是當(dāng)前urlparams中的字段值肝劲。②使用 router-link組件跳轉(zhuǎn)和js跳轉(zhuǎn)都可以傳遞paramsquery迁客。
  1. 編程式路由的使用
//路由入口文件: scr/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import GoodList from '@/views/GoodList'
import Cart from '@/views/Cart'

Vue.use(Router)

export default new Router({
  mode: 'history', //默認(rèn)值為hash
  routes: [
    {
      path: '/goods',
      name: 'GoodList',
      component: GoodList
    },
    {
      path: '/cart',
      name: 'cart',
      component: Cart
    }
  ]
})
//src/views/GoodsList.vue文件
<template>
  <div>
    <div>這是商品列表頁(yè)面</div>
    <button @click="toCart">
      跳轉(zhuǎn)到購(gòu)物車
    </button>
  </div>
</template>
<script>
export default {
  methods: {
    toCart() {
      this.$router.push({path: "/cart", query: {a: 1}})
    }
  }
}
</script>
//src/views/Cart.vue文件
<template>
  <div>
    <div>這是購(gòu)物車頁(yè)面</div>
    <span>{{$route.query.a}}</span>
    <button @click="backToGoods">
      返回商品列表
    </button>
  </div>
</template>
<script>
export default {
  methods: {
    backToGoods() {
      this.$router.go(-1)
    }
  }
}
</script>

2.3.5. 命名路由和命名視圖

1.命名路由和命名視圖介紹
給路由定義不同的名字,根據(jù)名字進(jìn)行匹配辞槐。
給不同的router-view定義名字掷漱,通過(guò)名字進(jìn)行對(duì)應(yīng)組件的渲染。

  1. 命名路由的使用
//路由入口文件: scr/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import GoodList from '@/views/GoodList'
import Cart from '@/views/Cart'

Vue.use(Router)

export default new Router({
  mode: 'history', //默認(rèn)值為hash
  routes: [
    {
      path: '/goods',
      name: 'GoodList',
      component: GoodList
    },
    {
      path: '/cart/:cartId',
      name: 'cart',
      component: Cart
    }
  ]
})
//src/views/GoodsList.vue文件
<template>
  <div>
    <div>這是商品列表頁(yè)面</div>
    <router-link v-bind:to="{name: 'cart', params: {cartId:123}, query: {a:1}}">跳轉(zhuǎn)到購(gòu)物車頁(yè)面</router-link>
  </div>
</template>
<script>
export default {}
</script>
//src/views/Cart.vue文件
<template>
  <div>
    <div>這是購(gòu)物車頁(yè)面</div>
    <span>{{$route.params.cartId}}</span>
    <span>{{$route.query.a}}</span>
  </div>
</template>
<script>
export default {}
</script>
  1. 命名視圖
    Vue Router文檔-命名視圖

2.3.6 HTML5 History 模式

  1. vue-router默認(rèn)hash模式 —— 使用URLhash來(lái)模擬一個(gè)完整的 URL榄檬,于是當(dāng) URL 改變時(shí)卜范,頁(yè)面不會(huì)重新加載。
    如果不想要很丑的 hash鹿榜,我們可以用路由的 history 模式海雪,這種模式充分利用 history.pushState API 來(lái)完成 URL 跳轉(zhuǎn)而無(wú)須重新加載頁(yè)面。
const router = new VueRouter({
  mode: 'history',
  routes: [...]
})
  1. 當(dāng)你使用 history 模式時(shí)犬缨,URL 就像正常的 url喳魏,例如 http://yoursite.com/user/id,也好看怀薛!
    不過(guò)這種模式要玩好刺彩,還需要后臺(tái)配置支持。因?yàn)槲覀兊膽?yīng)用是個(gè)單頁(yè)客戶端應(yīng)用,如果后臺(tái)沒(méi)有正確的配置创倔,當(dāng)用戶在瀏覽器直接訪問(wèn) http://oursite.com/user/id 就會(huì)返回 404嗡害,這就不好看了。
    所以呢畦攘,你要在服務(wù)端增加一個(gè)覆蓋所有情況的候選資源:如果 URL 匹配不到任何靜態(tài)資源霸妹,則應(yīng)該返回同一個(gè)index.html頁(yè)面,這個(gè)頁(yè)面就是你 app 依賴的頁(yè)面知押。
    注釋:vue-router處理前端路由跳轉(zhuǎn)叹螟,后端路由處理ajax/fetch請(qǐng)求以及用戶訪問(wèn)url頁(yè)面。當(dāng)用戶直接訪問(wèn)某一個(gè)路由頁(yè)面url(http://oursite.com/user/id)時(shí)台盯,該請(qǐng)求會(huì)由服務(wù)器端進(jìn)行處理罢绽。
    注意:把服務(wù)器的url解析重定向到index.html的首頁(yè)里面即可。如果mode 取默認(rèn)值hash静盅,通過(guò)# + 路徑地址才能訪問(wèn)到良价,后臺(tái)是不識(shí)別錨點(diǎn),不會(huì)出現(xiàn)404的狀態(tài)蒿叠。
  2. 后端配置例子
    (1)原生 Node.js
const http = require('http')
const fs = require('fs')
const httpPort = 80

http.createServer((req, res) => {
  fs.readFile('index.htm', 'utf-8', (err, content) => {
    if (err) {
      console.log('We cannot open "index.htm" file.')
    }

    res.writeHead(200, {
      'Content-Type': 'text/html; charset=utf-8'
    })

    res.end(content)
  })
}).listen(httpPort, () => {
  console.log('Server listening on: http://localhost:%s', httpPort)
})

(2) 基于 Node.jsExpress
對(duì)于 Node.js/Express明垢,請(qǐng)考慮使用 connect-history-api-fallback 中間件

  1. 給個(gè)警告市咽,因?yàn)檫@么做以后痊银,你的服務(wù)器就不再返回 404 錯(cuò)誤頁(yè)面,因?yàn)閷?duì)于所有路徑都會(huì)返回index.html 文件魂务。為了避免這種情況曼验,你應(yīng)該在 Vue 應(yīng)用里面覆蓋所有的路由情況泌射,然后在給出一個(gè) 404 頁(yè)面粘姜。
const router = new VueRouter({
  mode: 'history',
  routes: [
    { path: '*', component: NotFoundComponent }
  ]
})

或者,如果你使用 Node.js 服務(wù)器熔酷,你可以用服務(wù)端路由匹配到來(lái)的 URL孤紧,并在沒(méi)有匹配到路由的時(shí)候返回 404,以實(shí)現(xiàn)回退拒秘。更多詳情請(qǐng)查閱 Vue 服務(wù)端渲染文檔号显。

2.4 請(qǐng)求數(shù)據(jù)

2.4.1 vue-resource

  1. vue-resource 的請(qǐng)求API是按照REST風(fēng)格設(shè)計(jì)的,它提供了7種請(qǐng)求API
  • get(url, [options])
  • head(url, [options])
  • delete(url, [options])
  • jsonp(url, [options])
  • post(url, [body], [options])
  • put(url, [body], [options])
  • patch(url, [body], [options])
  1. 發(fā)送請(qǐng)求時(shí)的options選項(xiàng)對(duì)象包含以下屬性
參數(shù) 類型 描述
url string 請(qǐng)求的URL
method string 請(qǐng)求的HTTP方法躺酒,例如:'GET', 'POST'或其他HTTP方法
body Object, FormData string request body
params Object 請(qǐng)求的URL參數(shù)對(duì)象
headers Object request header
timeout number 單位為毫秒的請(qǐng)求超時(shí)時(shí)間 (0 表示無(wú)超時(shí)時(shí)間)
before function(request) 請(qǐng)求發(fā)送前的處理函數(shù)押蚤,類似于jQuerybeforeSend函數(shù)
progress function(event) ProgressEvent回調(diào)處理函數(shù)
credientials boolean 表示跨域請(qǐng)求時(shí)是否需要使用憑證
emulateHTTP boolean 發(fā)送PUT, PATCH, DELETE請(qǐng)求時(shí)以HTTP POST的方式發(fā)送,并設(shè)置請(qǐng)求頭的X-HTTP-Method-Override
emulateJSON boolean request bodyapplication/x-www-form-urlencoded content type發(fā)送
  1. 全局?jǐn)r截器interceptors
Vue.http.interceptors.push((request, next) => {
        // ...
        // 請(qǐng)求發(fā)送前的處理邏輯
        // ...
    next((response) => {
        // ...
        // 請(qǐng)求發(fā)送后的處理邏輯
        // ...
        // 根據(jù)請(qǐng)求的狀態(tài)羹应,response參數(shù)會(huì)返回給successCallback或errorCallback
        return response
    })
})
  1. vue-resource使用示例
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue-resource</title>
  <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
  <link rel="stylesheet" >
  <script src="../../node_modules/vue/dist/vue.js"></script>
  <script src="../../node_modules/vue-resource/dist/vue-resource.js"></script>
</head>
<body>
<div id="app">
  <h2>vue-resource演示</h2>
  <a href="#" @click="sendGet">發(fā)送Get請(qǐng)求</a>
  <a href="#" @click="sendPost">發(fā)送Post請(qǐng)求</a>
  <a href="#" @click="sendJsonp">發(fā)送Jsonp請(qǐng)求</a>
  <a href="#" @click="sendHttp">全局函數(shù)</a>
  <p v-text="response"></p>
</div>

<script>

  new Vue({
    el:"#app",
    data:{
      response:''
    },
    http: {
      root: 'http://localhost:8050/imoocmall/'
    },
    mounted() {
      Vue.http.interceptors.push((request, next) => {
        console.log('request init.');
        next((response) => {
          console.log('response init.');
          return response
        })
      })
    },
    methods:{
      sendGet() {
        this.$http.get('package.json',{
          params:{
            userId: "101",
          },
          headers:{
            access_token:"abc"
          }
        }).then(res => {
          this.response = res.data;
        }).catch(err => {
          this.response = err;
        });
      },
      sendPost() {
        this.$http.post('package.json', {
          userId: '102'
        }, {
          headers: {
            access_token:"abcd"
          }
        }).then(res => {
          this.response = res.data;
        }).catch(err => {
          this.response = err;
        });
      },
      sendJsonp(){
        this.$http.jsonp("http://www.imooc.com/course/ajaxskillcourse?cid=796",{
          params:{
            userId:"1001"
          }
        }).then(res => {
          this.response = res.data;
        }).catch(err => {
          this.response = err;
        })
      },
      sendHttp() {
        this.$http({
          url:"package.json",
          method:"GET",
          params:{ userId:"103" },
          headers:{ token:"123" },
          timeout:50,
          before() {
            console.log("before init")
          }
        }).then(res => {
          this.response = res.data;
        });
      }
    }
  });
</script>
</body>
</html>

注釋: ①引入 vue-resource之后可以通過(guò)this.$http的方式使用揽碘。

2.4.2 Axios

  1. Axios簡(jiǎn)介
    Axios 是一個(gè)基于 promiseHTTP 庫(kù),可以用在瀏覽器和 node.js 中。
  2. 請(qǐng)求方法介紹
  • axios.request(config)
  • axios.get(url[, config])
  • axios.delete(url[, config])
  • axios.head(url[, config])
  • axios.post(url[, data[, config]])
  • axios.put(url[, data[, config]])
  • axios.patch(url[, data[, config]])
    注意: ·Axios· 請(qǐng)求方法中沒(méi)有jsonp請(qǐng)求雳刺。
  1. 執(zhí)行get請(qǐng)求
// 為給定 ID 的 user 創(chuàng)建請(qǐng)求
axios.get('/user?ID=12345')
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

// 可選地劫灶,上面的請(qǐng)求可以這樣做
axios.get('/user', {
    params: {
      ID: 12345
    }
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });
  1. 執(zhí)行 POST 請(qǐng)求
axios.post('/user', {
    firstName: 'Fred',
    lastName: 'Flintstone'
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });
  1. 執(zhí)行多個(gè)并發(fā)請(qǐng)求
function getUserAccount() {
  return axios.get('/user/12345');
}

function getUserPermissions() {
  return axios.get('/user/12345/permissions');
}

axios.all([getUserAccount(), getUserPermissions()])
  .then(axios.spread(function (acct, perms) {
    // 兩個(gè)請(qǐng)求現(xiàn)在都執(zhí)行完成
  }));
  1. Axios使用示例
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>axios</title>
  <link rel="stylesheet" >
  <script src="../../node_modules/vue/dist/vue.js"></script>
  <script src="../../node_modules/axios/dist/axios.js"></script>
</head>
<body>
<div id="app">
  <h2>vaxios演示</h2>
  <a href="#" @click="sendGet">發(fā)送Get請(qǐng)求</a>
  <a href="#" @click="sendPost">發(fā)送Post請(qǐng)求</a>
  <a href="#" @click="sendHttp">全局函數(shù)</a>
  <p v-text="response"></p>
</div>

<script>
  new Vue({
    el:"#app",
    data:{
      response:''
    },
    mounted() {
      axios.interceptors.request.use((req) => {
        console.log('request init.');
        return req;
      });
      axios.interceptors.response.use((res) => {
        console.log('response init.');
        return res;
      });
    },
    methods:{
      sendGet() {
        axios.get('../../package.json',{
          params:{
            userId: "101",
          },
          headers:{
            token:"abc"
          }
        }).then(res => {
          this.response = res.data;
        }).catch(err => {
          this.response = err;
        });
      },
      sendPost() {
        axios.post('../../package.json', {
          userId: '102'
          }, {
            headers: {
              token:"abcd"
            }
          }).then(res => {
          this.response = res.data;
        }).catch(err => {
          this.response = err;
        });
      },
      sendHttp() {
        axios({
          url:'../../package.json',
          method:"POST",
          data:{ userId:"103" },
          headers:{ token:"123" }
        }).then(res => {
          this.response = res.data;
        });
      }
    }
  });
</script>
</body>
</html>

注釋:①axios的參數(shù)傳遞方式與vue-resource基本相同。② 注意區(qū)分get請(qǐng)求與post請(qǐng)求的參數(shù)傳遞方式掖桦。

2.5 Vuex基本用法

2.5.1 Vuex介紹

  1. Vuex是一個(gè)專門為Vue.js應(yīng)用程序開發(fā)的狀態(tài)管理模式本昏。
  2. 當(dāng)我們構(gòu)建一個(gè)中大型的單頁(yè)應(yīng)用程序時(shí),Vuex可以更好的幫助我們?cè)诮M件外部統(tǒng)一管理狀態(tài)枪汪。

2.5.2 核心概念

State Getters Mutations Actions Modules

  1. State
    State唯一數(shù)據(jù)源涌穆,單一狀態(tài)樹。
// 創(chuàng)建一個(gè) Counter 組件
const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count () {
      return store.state.count
    }
  }
}
  1. Getters
    通過(guò)Getters可以派生出一些新的狀態(tài)雀久。
const store = new Vuex.Store({
  state: {
    todos: [
      { id: 1, text: '...', done: true },
      { id: 2, text: '...', done: false }
    ]
  },
  getters: {
    doneTodos: state => {
      return state.todos.filter(todo => todo.done)
    }
  }
})
  1. Mutations
    更改Vuexstore中狀態(tài)的唯一方法是提交mutation蒲犬。
const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    increment (state) {
      // 變更狀態(tài)
      state.count++
    }
  }
})

觸發(fā)mutation handler

store.commit('increment')
  1. Actions
    Action提交的是mutation,而不是直接改變狀態(tài)岸啡。
    Action可以包含任意異步操作原叮。
const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      context.commit('increment')
    }
  }
})

注釋:mutations中的方法必須是同步的,actions中的方法可以有異步操作巡蘸。

  1. Modules
    面對(duì)復(fù)雜的應(yīng)用程序奋隶,當(dāng)管理的狀態(tài)比較多時(shí),我們需要將Vuexstore對(duì)象分割成模塊(modules)悦荒。
const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})
store.state.a // -> moduleA 的狀態(tài)
store.state.b // -> moduleB 的狀態(tài)
  1. 概念關(guān)系圖


2.5.3 項(xiàng)目結(jié)構(gòu)

├── index.html
├── main.js
├── api
│   └── ... # 抽取出API請(qǐng)求
├── components
│   ├── App.vue
│   └── ...
└── store
    ├── index.js          # 我們組裝模塊并導(dǎo)出 store 的地方
    ├── actions.js        # 根級(jí)別的 action
    ├── mutations.js      # 根級(jí)別的 mutation
    └── modules
        ├── cart.js       # 購(gòu)物車模塊
        └── products.js   # 產(chǎn)品模塊

2.5.4 代碼示例

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Vuex</title>
  <script src="../../node_modules/vue/dist/vue.js"></script>
  <script src="../../node_modules/vuex/dist/vuex.min.js"></script>
</head>
<body>
<div id="app">
  <h2>{{msg}}</h2>
  <button @click="add">同步增加</button>
  <button @click="asyncAdd">異步增加</button>
  <counter></counter>
</div>
<script>
  const counter = {
    template: `
      <div>
         <h3>{{count}}<h3>
         <h3>{{squareCount}}</h3>
      </div>
    `,
    computed: {
      ...Vuex.mapState(['count']),  //mapState語(yǔ)法糖
      /*count() {
        return this.$store.state.count;
      },*/
      squareCount() {
        return this.$store.getters.squareCount;
      }
    }
  };
  const store =  new Vuex.Store({
    state: {
      count: 0
    },
    getters: {
      squareCount(state) {
        return state.count * state.count;
      }
    },
    mutations: {
      increment(state, num) {
        state.count += num;
      }
    },
    actions: {
      asyncIncrement(context, num) {
        setTimeout(() => {
          context.commit('increment', num);
        }, 1000);
      }
    }
  });
  new Vue({
    el: '#app',
    store,
    data: {
      msg: 'Vuex的使用'
    },
    components: {
      counter
    },
    methods: {
      add() {
        this.$store.commit('increment', 1);
      },
      asyncAdd() {
        this.$store.dispatch('asyncIncrement', 2)
      }
    }
  })
</script>
</body>
</html>

3. Vue生態(tài)圈

3.1 模擬mock數(shù)據(jù)

vue開發(fā)過(guò)程中唯欣,有時(shí)需要使用本地json模擬后臺(tái)接口數(shù)據(jù),測(cè)試前端頁(yè)面展示情況搬味。對(duì)于使用vue-cli工具構(gòu)建的項(xiàng)目境氢,封裝了express框架,我們可以通過(guò)攔截請(qǐng)求的方式使用mock數(shù)據(jù)碰纬。

  1. 創(chuàng)建mock數(shù)據(jù)json文件
  2. webpack.dev.conf.js文件中攔截請(qǐng)求
//imoocmall/build/webpack.dev.conf.js文件
var goodsData = require('../mock/goods.json')
devServer: {
     before (app) {
       app.get('/goods', function (req, res) {
         res.json(goodsData);
       })
     },
    //...
}
//..

注釋: 這里的app.get('/goods', (req, res) => {})就是express框架定義后端路由接口的寫法萍聊。

  1. 使用mock數(shù)據(jù)
axios.get('/goods',)
  .then(res => { 
    //...
})

3.2 圖片懶加載

使用vue-lazyload插件可以實(shí)現(xiàn)圖片懶加載。

  1. 安裝
    npm i vue-lazyload -d
  2. 引入
    src/main.js
import VueLazyload from 'vue-lazyload'
Vue.use(VueLazyload, {
  error: 'dist/error.png',
  loading: 'dist/loading.gif',
})
  1. 使用
<img  v-lazy="'/static/'+good.productImage" alt="">

3.3 滾動(dòng)加載

使用vue-infinite-scroll插件可以實(shí)現(xiàn)滾動(dòng)加載悦析。

  1. 安裝
    npm install vue-infinite-scroll --save
  2. 引入
    src/main.js
import infiniteScroll from 'vue-infinite-scroll'
Vue.use(infiniteScroll)
  1. 使用
<div v-infinite-scroll="loadMore" infinite-scroll-disabled="busy" infinite-scroll-distance="30">
   <img src="../assets/loading-spinning-bubbles.svg" >
</div>

var count = 0;
new Vue({
  el: '#app',
  data: {
    data: [],
    busy: false
  },
  methods: {
    loadMore: function() {
      this.busy = true;
      setTimeout(() => {
        for (var i = 0, j = 10; i < j; i++) {
          this.data.push({ name: count++ });
        }
        this.busy = false;
      }, 1000);
    }
  }
});

注釋:infinite-scroll-disabled表示滾動(dòng)加載是否禁用寿桨。

3.4 請(qǐng)求代理

  1. 開發(fā)過(guò)程中,前端服務(wù)與后端接口一般存在著跨域問(wèn)題强戴。vue-cli提供了proxyTable代理功能解決跨域問(wèn)題亭螟。
    注釋:① 開發(fā)環(huán)境前端服務(wù)端口8080(/config/index.js中的port: 8080)與后端服務(wù)端口(/server/bin/www中的var port = normalizePort(process.env.PORT || '3000');)不同,存在跨域骑歹,所有需要使用請(qǐng)求代理预烙。② 一般僅在開發(fā)環(huán)境中配置。
    注意:①跨域問(wèn)題只是web前端瀏覽器的行為道媚,在web前端請(qǐng)求不符合同源策略接口數(shù)據(jù)時(shí)出現(xiàn)扁掸。②后端node連接mongodb數(shù)據(jù)庫(kù)即使協(xié)議域名端口不同(不符合同源策略)欢嘿,也不存在跨域問(wèn)題。
  2. 修改/config/index.js 文件中的dev.proxyTable配置
proxyTable: {
      '/goods': {
        target: 'http://localhost:3000' 
      }
    }
}

此時(shí)也糊,當(dāng)我們請(qǐng)求 http://localhost:8888/goods 的時(shí)候,就等于請(qǐng)求了http://localhost:3000/goods炼蹦。
注意: '/goods'規(guī)則不僅能夠匹配'/goods'規(guī)則的路徑,還能夠匹配'/goods/a'狸剃、'/goods/a/b'等規(guī)則的路徑掐隐。

proxyTable: {
      '/api': {
        target: 'http://localhost:3000' ,
        pathRewrite: {
          '^/api':  ''
        }
      }
    }
}

此時(shí),當(dāng)我們請(qǐng)求 http://localhost:8888/api 的時(shí)候,就等于請(qǐng)求了http://localhost:3000钞馁。

參考資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末虑省,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子僧凰,更是在濱河造成了極大的恐慌探颈,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件训措,死亡現(xiàn)場(chǎng)離奇詭異伪节,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)绩鸣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門怀大,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人呀闻,你說(shuō)我怎么就攤上這事化借。” “怎么了捡多?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵蓖康,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我垒手,道長(zhǎng)蒜焊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任淫奔,我火速辦了婚禮山涡,結(jié)果婚禮上堤结,老公的妹妹穿的比我還像新娘唆迁。我一直安慰自己,他們只是感情好竞穷,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布唐责。 她就那樣靜靜地躺著,像睡著了一般瘾带。 火紅的嫁衣襯著肌膚如雪鼠哥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音朴恳,去河邊找鬼抄罕。 笑死,一個(gè)胖子當(dāng)著我的面吹牛于颖,可吹牛的內(nèi)容都是我干的呆贿。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼森渐,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼做入!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起同衣,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤竟块,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后耐齐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體浪秘,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年埠况,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了秫逝。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡询枚,死狀恐怖违帆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情金蜀,我是刑警寧澤刷后,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站渊抄,受9級(jí)特大地震影響尝胆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜护桦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一含衔、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧二庵,春花似錦贪染、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至因妙,卻和暖如春痰憎,著一層夾襖步出監(jiān)牢的瞬間票髓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工铣耘, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留洽沟,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓蜗细,卻偏偏與公主長(zhǎng)得像玲躯,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子鳄乏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355