Vue2的路由和異步請(qǐng)求方式
1.路由
1.1路由的作用
在傳統(tǒng)的Web應(yīng)用中個(gè),每個(gè)URL對(duì)應(yīng)網(wǎng)站中的一個(gè)頁面;但在SPA(單頁面應(yīng)用中),由于只有一個(gè)頁面,如果要實(shí)現(xiàn)不同URL在相同頁面顯示不同的路由,就需要根據(jù)URL來跟換Web組件,這需要額外的路由技術(shù)來實(shí)現(xiàn)。

例如以下三個(gè)頁面,頭部和底部都是相同的,而中間需要根據(jù)URL的不同,顯示不同的中間組件,這時(shí)就需要路由。

1.2使用CLI3創(chuàng)建帶路由功能的Vue2項(xiàng)目(案例)
(1)創(chuàng)建vue項(xiàng)目
vue create funnyshop‐vue2
(2)選擇手動(dòng)設(shè)置特性(Manually select features)

(3)添加路由特性選項(xiàng)

(4)使用歷史模式路由等特性項(xiàng)目特性

1.3 路由使用入門
1.3.1 項(xiàng)目路由規(guī)劃
根據(jù)功能結(jié)構(gòu),我們可以把手機(jī)微商界面分割為若干個(gè)子組件。

具體子組件功能如下所示
組件名稱 | 功能描述 |
HeaderPart | 網(wǎng)頁頭部的導(dǎo)航和搜索框 |
FooterPart | 頁面底部的導(dǎo)航 |
ProductList | 產(chǎn)品列表 |
Login | 登錄 |
Cart | 購物車 |
ProductDetail | 產(chǎn)品詳情 |
(1)在index.html頁面中導(dǎo)入全局樣式(可選)
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="UTF‐8">
<title>Document</title>
<meta name="viewport" content="width=device‐width, initial‐scale=1.0, maximum‐scale=1.0, minimum‐scale=1.0, user‐scalable=no"
<link rel="stylesheet" href="<%= BASE_URL %>css/base.css" rel="external nofollow" >
<link rel="stylesheet" href="<%= BASE_URL %>css/page.css" rel="external nofollow" >
</head>
<body>
<div id="app"></div>
</body>
</html>(2)項(xiàng)目根組件App.vue
在項(xiàng)目根組件中導(dǎo)入公共子組件(headerpart、footerpart)和根據(jù)路由加載的部分(routerview)
<template>
<div class="pageWrapper">
<header‐part />
<div class="pageBreak"></div>
<router‐view></router‐view>
<div class="pageBreak"></div>
<footer‐part />
</div>
</template>
<script>
import HeaderPart from './components/HeaderPart.vue'
import FooterPart from './components/FooterPart.vue'
export default {
name:"app",
components:{HeaderPart, FooterPart}
}
</script>其中不是我們定義的組件,而是vue的路由組件,只是一個(gè)占位符,用于顯示不同url下所 需要加載的變化部分。
1.3.2 路由映射定義
帶router的vue2項(xiàng)目創(chuàng)建后,src目錄下會(huì)多出一個(gè)名為“router.js”的文件,該文件用于定義路由規(guī)則, 也就是不同的URL路徑下所要加載的Vue子組件對(duì)應(yīng)關(guān)系和參數(shù)傳遞規(guī)則。
import Vue from 'vue'
import Router from 'vue‐router'
import ProductList from './components/ProductList.vue'
import Login from './components/Login.vue'
import ProductDetail from './components/ProductDetail.vue'
import Cart from './components/Cart.vue'
Vue.use(Router)
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/',
name: 'home',
component: ProductList
},
{
path: '/product‐list',
name: 'product‐list',
component: ProductList
},
{
path:'/login',
name:'login',
component: Login
},
{
path:'/product/:id',
name:'product',
component: ProductDetail
},
{
path:'/cart',
name:'cart',
component: Cart
},
]
})routes配置中的每一項(xiàng)代表一條路由規(guī)則。
path是URL路徑,可以定義路徑參數(shù)(如“/product/:id”中的id);name是路由名稱,用于引用; component指定加載的組件名稱。
完成組件劃分(*.vue)和路由映射(router.js)后,應(yīng)用就可以根據(jù)路由規(guī)則顯示不同的頁面內(nèi)容了。
1.3.3 通過路由連接(替代<a>)切換頁面內(nèi)容
傳統(tǒng)的超鏈接<a href="...">會(huì)使頁面發(fā)生同步跳轉(zhuǎn),在SPA應(yīng)用中只有一張頁面,內(nèi)容的切換全部是異 步方式的。
(1)通過<router-link> 組件實(shí)現(xiàn)“跳轉(zhuǎn)”
routerlink是一個(gè)路由組件,可以理解為異步的跳轉(zhuǎn)連接標(biāo)簽(<a>)
routerlink的to屬性可以設(shè)置切換的URL。to后面可以設(shè)置“靜態(tài)的URL”或者綁定“一個(gè)路由項(xiàng)對(duì)象”,例 如下面的兩個(gè)示例,前者設(shè)置URL,后者綁定一個(gè)定義了的路由對(duì)象。
<router‐link to="/login">登錄</router‐link>
<router‐link :to="{name:'cart'}">購物車</router‐link>。(2)通過推送路由變更$router.push(),從而實(shí)現(xiàn)“跳轉(zhuǎn)”
配置好路由的項(xiàng)目中,我們可以在任意Vue組件內(nèi)部,通過this.$router訪問路由對(duì)象,通過 $router.push()方法,我們可以向路由推送跳轉(zhuǎn),實(shí)現(xiàn)組件的切換。
this.$router.push({name:"product‐list", query:{"name":val}});1.3.4 路由參數(shù)的獲取
(1)路徑參數(shù)與獲取 我們?cè)诼酚捎成渲校╮outer.js)定義了以下一項(xiàng):
{ path:'/product/:id', name:'product', component: ProductDetail }也就是在跳轉(zhuǎn)到ProductDetail組件時(shí),我們會(huì)傳入名為id的路徑參數(shù)。
例如,在產(chǎn)品列表中有以下路由連接,點(diǎn)擊后實(shí)際的URL可能為 “/product/5”,其中5是id參數(shù)。
<router‐link :to="{name:'product',params:{id:item.id}}">產(chǎn)品1連接</router‐link>這時(shí),我們可以在目標(biāo)組件ProductDetail中,通過 “$route.params.參數(shù)名” 獲取到路徑參數(shù)值:
let id = this.$route.params.id;
(2)查詢字符串參數(shù)的獲取
路徑參數(shù)是URL路徑的一部分,通常只能用于傳遞必要參數(shù)(一定要提供的參數(shù)),對(duì)于可選參數(shù)就應(yīng) 該使用查詢字符串的方式來傳遞,例如:“search?name=abc&page=101”。
對(duì)于查詢字符串參數(shù),我們可以通過以下方式傳遞。
searchByProductName(e){
var val = e.target.value;
this.$router.push({name:"product‐list", query:{"name":val}});
}上述路由推送會(huì)產(chǎn)生類似這樣的URL:“productlist?name=xxxx” 這時(shí),我們可以在目標(biāo)組件ProducList中,通過“$router.query.參數(shù)名”獲取查詢字符串參數(shù)值。
let searchName = this.$route.query.name
2 異步請(qǐng)求
2.1 后端RESTful Web服務(wù)和代理
(1)后端RESTful Web服務(wù)
SPA一般都采用前后端分離的開發(fā)方式。后端可以使用任何的服務(wù)器端Web技術(shù),諸如JavaEE、 PHP、Node.js、Python等等,后端提供基于RESTful風(fēng)格的Web服務(wù),接收前端請(qǐng)求并返回JSON格式 的數(shù)據(jù)。
這里使用基于Spring Boot的MVC技術(shù)提供后端服務(wù),具體細(xì)節(jié)略去,僅在這里描述所提供的服務(wù)接 口。
URL | 功能 |
http://localhost:9090/api/products/latest | 獲取最新的4種產(chǎn)品,返回JSON格式數(shù)據(jù) |
http://localhost:9090/api/products/1 | 獲取id=1的商品明細(xì)信息 |
http://localhost:9090/api/products?name=青瓷 | 模糊查詢名稱中包含“青瓷”的產(chǎn)品信息,返回 JSON格式數(shù)據(jù) |
具體請(qǐng)求效果如下圖所示。

(2)服務(wù)的代理
作為前后端分離的項(xiàng)目,后端和前端往往不是運(yùn)行在同一個(gè)服務(wù)器中的。例如上述開發(fā)中,后端的 JavaEE服務(wù)是運(yùn)行在Tomcat服務(wù)器(Spring Boot內(nèi)嵌的容器)中的,而前端則是使用Node.js提供的測(cè) 試服務(wù)器。前者域名為“localhost:9090”,而后者是“localhost:3000”。這時(shí),如果前端通過AJAX技術(shù)請(qǐng) 求后端數(shù)據(jù),就會(huì)遇到JavaScript請(qǐng)求不能跨域執(zhí)行的問題而無法請(qǐng)求。要解決這個(gè)問題,要么就需要 使用jsonp協(xié)議(跨域JSON協(xié)議),要么就要把前后端兩個(gè)服務(wù)器通過代理服務(wù)器代理到同一個(gè)域名之 下。在實(shí)際部署中,我們可以通過Nginx等靜態(tài)資源服務(wù)器實(shí)現(xiàn)代理,而在開發(fā)中Vue項(xiàng)目可以直接配置 后端代理,把lcoalhost:9090的域名請(qǐng)求代理到localhost:3000域名之下。
在項(xiàng)目根目錄下添加 “vue.config.js” 文件,這時(shí)vue項(xiàng)目的配置文件,在其中可以設(shè)置開發(fā)服務(wù)器的端 口 “port” 和后端Web服務(wù)的代理“proxy”。
module.exports = {
devServer: {
port: 3000,
proxy: {
'/api': {
target: 'http://localhost:9090', // target host
},
}
}
};如上所示,當(dāng)我們請(qǐng)求 “localhost:3000/api/xxx” 時(shí),請(qǐng)求被代理到了 “http://localhost:9090/api/xxx”, 這樣前后端就不存在跨域問題了。
2.2 使用 axois 組件請(qǐng)求后端數(shù)據(jù)
(1)Promise與fetch API
傳統(tǒng)的靜態(tài)網(wǎng)頁是通過XMLHttpRequest對(duì)象實(shí)現(xiàn)對(duì)后端數(shù)據(jù)的異步請(qǐng)求的(例如jQuery的$.ajax),請(qǐng) 求成功后需要執(zhí)行回調(diào)函數(shù)。
這種傳統(tǒng)的回調(diào)在復(fù)雜的使用環(huán)境中往往會(huì)一個(gè)接一個(gè)的嵌套,讓代碼陷入難以維護(hù)的“Callback地 獄”。新一代的JavaScript(ES6),不再建議使用XMLHttpRequest,而是用一種叫Promise的方式組織 代碼,讓我們不用陷入到回調(diào)的連環(huán)套中,而是用平面的方式來處理所有回調(diào)。新一代的瀏覽器中都支 持一個(gè)名為fetch的API方法,可以實(shí)現(xiàn)Promise方式的請(qǐng)求。

(2)axios組件
fetch API雖然基于Promise已經(jīng)很好用了,但fetch功能還是過于原始,在實(shí)際應(yīng)用中我們可能還需要一 些攔截器等擴(kuò)展模塊。
為此 vue 的作者推薦我們使用一個(gè)名為 axios 的JavaScript擴(kuò)展包來實(shí)現(xiàn)后臺(tái)請(qǐng) 求功能。axios有良好的Promise和攔截器機(jī)制。
2.3 axios的使用
axios的詳細(xì)使用請(qǐng)參考互聯(lián)網(wǎng) https://www.npmjs.com/package/axios,這里只是簡(jiǎn)單介紹。
(1)為Vue項(xiàng)目添加axios
在項(xiàng)目根目錄中執(zhí)行以下Node指令:
vue add axios
(2)axios基本用法
Method | Api |
Get | axios.get(url).then(successCallback).catch(errorHandler) |
Post | axios.post(url, data).then(successCallback).catch(errorHandler) |
Put | axios.put(url, data).then(successCallback).catch(errorHandler) |
Delete | axios.delete(url).then(successCallback).catch(errorHandler) |
(3)axios的攔截器
axios可以在(組件的)請(qǐng)求或相應(yīng)處理的之前插入攔截器,統(tǒng)一處理異步請(qǐng)求中的公共問題。
例如我們可以在react程序入口“index.js”中添加如下代碼,統(tǒng)一在請(qǐng)求發(fā)出前添加jwt請(qǐng)求頭,或者在響 應(yīng)出錯(cuò)時(shí)定位到頁面。
import axios from 'axios';
//請(qǐng)求前處理
axios.interceptors.request.use(
config => {
const token = window.localStorage.getItem("jwt‐token");
if(token)
config.headers={'Authorization': 'Bearer '+token};
return config;
},
error=>{
return Promise.reject(error);
}
);
//響應(yīng)前處理
axios.interceptors.response.use(
response => {
return response;
},
error => {
const httpCode = error.response.status;
if(httpCode>=400 && httpCode<600){
window.location.href="/error" rel="external nofollow" ;
}
return Promise.reject(error);
}
);2.4 在項(xiàng)目中實(shí)現(xiàn)請(qǐng)求
下面演示了ProductList組件中如何向后端請(qǐng)求商品信息。
<template>
<div class="contentWrapper">
<h4 class="contentTitle">新品上架:</h4>
<div class="productListWrapper">
<div class="productWrapper" v‐for="(item,i) in products" :key="i">
<router‐link :to="{name:'product',params:{id:item.id}}">
<img :src="'images/content/'+item.id+'‐1.jpg'" alt=""/>
</router‐link>
<div class="productInfoWrapper">
<span class="productTitle">{{item.name}}</span>
<a class="purchaseButton">¥{{item.unitPrice}} 購買</a>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'product‐list',
data(){
return {
products:[]
};
},
mounted(){
this.fetchData();
},
methods:{
fetchData(){
if(this.$route.query.name){
this.axios.get("/api/products?name="+this.$route.query.name).then(res=>this
}else{
this.axios.get("/api/products/latest").then(res=>this.products=res.data);
}
}
}
}
</script>總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- vue3 onMounted異步函數(shù)同步請(qǐng)求async/await實(shí)現(xiàn)
- vue函數(shù)input輸入值請(qǐng)求時(shí)延遲1.5秒請(qǐng)求問題
- Vue路由切換和Axios接口取消重復(fù)請(qǐng)求詳解
- vue路由切換時(shí)取消之前的所有請(qǐng)求操作
- vue路由攔截器和請(qǐng)求攔截器知識(shí)點(diǎn)總結(jié)
- vue路由導(dǎo)航守衛(wèi)和請(qǐng)求攔截以及基于node的token認(rèn)證的方法
- vue-resource請(qǐng)求實(shí)現(xiàn)http登錄攔截或者路由攔截的方法
- vue請(qǐng)求函數(shù)和路由的安裝使用過程
相關(guān)文章
vue3的setup語法如何自定義v-model為公用hooks
這篇文章主要介紹了vue3的setup語法如何自定義v-model為公用hooks,文章分為兩個(gè)部分介紹,簡(jiǎn)單介紹vue3的setup語法如何自定義v-model和如何提取v-model語法作為一個(gè)公用hooks2022-07-07
vue實(shí)現(xiàn)文件流形式的導(dǎo)出下載全過程
Vue項(xiàng)目中下載返回的文件流操作包括:使用Axios請(qǐng)求文件流數(shù)據(jù)、設(shè)置響應(yīng)類型為'blob'、創(chuàng)建下載鏈接并觸發(fā)下載,關(guān)鍵步驟是使用Blob對(duì)象和URL.createObjectURL生成下載鏈接2025-12-12
vue如何設(shè)置描點(diǎn)跳轉(zhuǎn)到對(duì)應(yīng)頁面
這篇文章主要介紹了vue如何設(shè)置描點(diǎn)跳轉(zhuǎn)到對(duì)應(yīng)頁面問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05
vue項(xiàng)目main.js使用方法詳細(xì)介紹
這篇文章主要給大家介紹了關(guān)于vue項(xiàng)目main.js使用方法的相關(guān)資料,main.js文件是程序的入口文件,加載各種公共組件,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-09-09
Vue中使用vue-plugin-hiprint插件進(jìn)行打印的功能實(shí)現(xiàn)
hiprint 是一個(gè)web 打印的js組件,無需安裝軟件,支持windows,macOS,linux 系統(tǒng),支持移動(dòng)端,PC端瀏覽器,angular,vue,react 等 分頁預(yù)覽,打印,操作簡(jiǎn)單,運(yùn)行快速,本文介紹了Vue中使用vue-plugin-hiprint插件進(jìn)行打印,需要的朋友可以參考下2025-04-04
Vue3?localStorage讀取數(shù)組并賦值的問題及解決
這篇文章主要介紹了Vue3?localStorage讀取數(shù)組并賦值的問題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-06-06
vue項(xiàng)目中導(dǎo)入swiper插件的方法
這篇文章主要介紹了vue項(xiàng)目中導(dǎo)入swiper插件的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-01-01

