翼度科技»论坛 编程开发 JavaScript 查看内容

Vue2的路由和异步请求方式

11

主题

11

帖子

33

积分

新手上路

Rank: 1

积分
33
1.路由


1.1路由的作用

在传统的Web应用中个,每个URL对应网站中的一个页面;但在SPA(单页面应用中),由于只有一个页面,如果要实现不同URL在相同页面显示不同的路由,就需要根据URL来跟换Web组件,这需要额外的路由技术来实现。

例如以下三个页面,头部和底部都是相同的,而中间需要根据URL的不同,显示不同的中间组件,这时就需要路由。


1.2使用CLI3创建带路由功能的Vue2项目(案例)

(1)创建vue项目
  1. vue create funnyshop‐vue2
复制代码
(2)选择手动设置特性(Manually select features)

(3)添加路由特性选项

(4)使用历史模式路由等特性项目特性


1.3 路由使用入门

1.3.1 项目路由规划
根据功能结构,我们可以把手机微商界面分割为若干个子组件。

具体子组件功能如下所示
组件名称
功能描述
HeaderPart
网页头部的导航和搜索框
FooterPart
页面底部的导航
ProductList
产品列表
Login
登录
Cart
购物车
ProductDetail
产品详情
(1)在index.html页面中导入全局样式(可选)
  1. <!DOCTYPE HTML>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF‐8">
  5. <title>Document</title>
  6.     <meta name="viewport" content="width=device‐width, initial‐scale=1.0, maximum‐scale=1.0, minimum‐scale=1.0, user‐scalable=no"
  7.     <link rel="stylesheet" href="<%= BASE_URL %>css/base.css" rel="external nofollow" >
  8.     <link rel="stylesheet" href="<%= BASE_URL %>css/page.css" rel="external nofollow" >
  9. </head>
  10. <body>
  11.     <div id="app"></div>
  12. </body>
  13. </html>
复制代码
(2)项目根组件App.vue
在项目根组件中导入公共子组件(header­part、footer­part)和根据路由加载的部分(router­view)
  1. <template>
  2.     <div class="pageWrapper">
  3.         <header‐part />
  4.         <div class="pageBreak"></div>
  5.         <router‐view></router‐view>
  6.         <div class="pageBreak"></div>
  7.         <footer‐part />
  8.     </div>
  9. </template>
  10. <script>
  11. import HeaderPart from './components/HeaderPart.vue'
  12. import FooterPart from './components/FooterPart.vue'
  13. export default {
  14.     name:"app",
  15.     components:{HeaderPart, FooterPart}
  16. }
  17. </script>
复制代码
其中不是我们定义的组件,而是vue的路由组件,只是一个占位符,用于显示不同url下所 需要加载的变化部分。
1.3.2 路由映射定义
带router的vue2项目创建后,src目录下会多出一个名为“router.js”的文件,该文件用于定义路由规则, 也就是不同的URL路径下所要加载的Vue子组件对应关系和参数传递规则。
  1. import Vue from 'vue'
  2. import Router from 'vue‐router'
  3. import ProductList from './components/ProductList.vue'
  4. import Login from './components/Login.vue'
  5. import ProductDetail from './components/ProductDetail.vue'
  6. import Cart from './components/Cart.vue'
  7. Vue.use(Router)
  8. export default new Router({
  9.     mode: 'history',
  10.     base: process.env.BASE_URL,
  11.     routes: [
  12.     {
  13.         path: '/',
  14.         name: 'home',
  15.         component: ProductList
  16.     },
  17.     {
  18.         path: '/product‐list',
  19.         name: 'product‐list',
  20.         component: ProductList
  21.     },
  22.     {
  23.         path:'/login',
  24.         name:'login',
  25.         component: Login
  26.     },
  27.     {
  28.         path:'/product/:id',
  29.         name:'product',
  30.         component: ProductDetail
  31.     },
  32.     {
  33.         path:'/cart',
  34.         name:'cart',
  35.         component: Cart
  36.     },
  37.   ]
  38. })
复制代码
routes配置中的每一项代表一条路由规则。
path是URL路径,可以定义路径参数(如“/product/:id”中的id);name是路由名称,用于引用; component指定加载的组件名称。
完成组件划分(*.vue)和路由映射(router.js)后,应用就可以根据路由规则显示不同的页面内容了。
1.3.3 通过路由连接(替代<a>)切换页面内容
传统的超链接<a href="...">会使页面发生同步跳转,在SPA应用中只有一张页面,内容的切换全部是异 步方式的。
(1)通过<router-­link> 组件实现“跳转”
router­link是一个路由组件,可以理解为异步的跳转连接标签(<a>)
router­link的to属性可以设置切换的URL。to后面可以设置“静态的URL”或者绑定“一个路由项对象”,例 如下面的两个示例,前者设置URL,后者绑定一个定义了的路由对象。
  1. <router‐link to="/login">登录</router‐link>
  2. <router‐link :to="{name:'cart'}">购物车</router‐link>。
复制代码
(2)通过推送路由变更$router.push(),从而实现“跳转”
配置好路由的项目中,我们可以在任意Vue组件内部,通过this.$router访问路由对象,通过 $router.push()方法,我们可以向路由推送跳转,实现组件的切换。
  1. this.$router.push({name:"product‐list", query:{"name":val}});
复制代码
1.3.4 路由参数的获取
(1)路径参数与获取 我们在路由映射中(router.js)定义了以下一项:
  1. { path:'/product/:id', name:'product', component: ProductDetail }
复制代码
也就是在跳转到ProductDetail组件时,我们会传入名为id的路径参数。
例如,在产品列表中有以下路由连接,点击后实际的URL可能为 “/product/5”,其中5是id参数。
  1. <router‐link :to="{name:'product',params:{id:item.id}}">产品1连接</router‐link>
复制代码
这时,我们可以在目标组件ProductDetail中,通过 “$route.params.参数名” 获取到路径参数值:
  1. let id = this.$route.params.id;
复制代码
(2)查询字符串参数的获取
路径参数是URL路径的一部分,通常只能用于传递必要参数(一定要提供的参数),对于可选参数就应 该使用查询字符串的方式来传递,例如:“search?name=abc&page=101”。
对于查询字符串参数,我们可以通过以下方式传递。
  1. searchByProductName(e){
  2.     var val = e.target.value;
  3.     this.$router.push({name:"product‐list", query:{"name":val}});
  4. }
复制代码
上述路由推送会产生类似这样的URL:“product­list?name=xxxx” 这时,我们可以在目标组件ProducList中,通过“$router.query.参数名”获取查询字符串参数值。
  1. let searchName = this.$route.query.name
复制代码
2 异步请求


2.1 后端RESTful Web服务和代理

(1)后端RESTful Web服务
SPA一般都采用前后端分离的开发方式。后端可以使用任何的服务器端Web技术,诸如JavaEE、 PHP、Node.js、Python等等,后端提供基于RESTful风格的Web服务,接收前端请求并返回JSON格式 的数据。
这里使用基于Spring Boot的MVC技术提供后端服务,具体细节略去,仅在这里描述所提供的服务接 口。
URL
功能
http://localhost:9090/api/products/latest
获取最新的4种产品,返回JSON格式数据
http://localhost:9090/api/products/1
获取id=1的商品明细信息
http://localhost:9090/api/products?name=青瓷
模糊查询名称中包含“青瓷”的产品信息,返回
JSON格式数据
具体请求效果如下图所示。

(2)服务的代理
作为前后端分离的项目,后端和前端往往不是运行在同一个服务器中的。例如上述开发中,后端的 JavaEE服务是运行在Tomcat服务器(Spring Boot内嵌的容器)中的,而前端则是使用Node.js提供的测 试服务器。前者域名为“localhost:9090”,而后者是“localhost:3000”。这时,如果前端通过AJAX技术请 求后端数据,就会遇到JavaScript请求不能跨域执行的问题而无法请求。要解决这个问题,要么就需要 使用jsonp协议(跨域JSON协议),要么就要把前后端两个服务器通过代理服务器代理到同一个域名之 下。在实际部署中,我们可以通过Nginx等静态资源服务器实现代理,而在开发中Vue项目可以直接配置 后端代理,把lcoalhost:9090的域名请求代理到localhost:3000域名之下。
在项目根目录下添加 “vue.config.js” 文件,这时vue项目的配置文件,在其中可以设置开发服务器的端 口 “port” 和后端Web服务的代理“proxy”。
  1. module.exports = {
  2.     devServer: {
  3.         port: 3000,
  4.         proxy: {
  5.             '/api': {
  6.                 target: 'http://localhost:9090', // target host
  7.             },
  8.         }
  9.     }
  10. };
复制代码
如上所示,当我们请求 “localhost:3000/api/xxx” 时,请求被代理到了 “http://localhost:9090/api/xxx”, 这样前后端就不存在跨域问题了。

2.2 使用 axois 组件请求后端数据

(1)Promise与fetch API
传统的静态网页是通过XMLHttpRequest对象实现对后端数据的异步请求的(例如jQuery的$.ajax),请 求成功后需要执行回调函数。
这种传统的回调在复杂的使用环境中往往会一个接一个的嵌套,让代码陷入难以维护的“Callback地 狱”。新一代的JavaScript(ES6),不再建议使用XMLHttpRequest,而是用一种叫Promise的方式组织 代码,让我们不用陷入到回调的连环套中,而是用平面的方式来处理所有回调。新一代的浏览器中都支 持一个名为fetch的API方法,可以实现Promise方式的请求。

(2)axios组件
fetch API虽然基于Promise已经很好用了,但fetch功能还是过于原始,在实际应用中我们可能还需要一 些拦截器等扩展模块。
为此 vue 的作者推荐我们使用一个名为 axios 的JavaScript扩展包来实现后台请 求功能。axios有良好的Promise和拦截器机制。

2.3 axios的使用

axios的详细使用请参考互联网 https://www.npmjs.com/package/axios,这里只是简单介绍。
(1)为Vue项目添加axios
在项目根目录中执行以下Node指令:
  1. 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可以在(组件的)请求或相应处理的之前插入拦截器,统一处理异步请求中的公共问题。
例如我们可以在react程序入口“index.js”中添加如下代码,统一在请求发出前添加jwt请求头,或者在响 应出错时定位到页面。
  1. import axios from 'axios';
  2. //请求前处理
  3. axios.interceptors.request.use(
  4.     config => {
  5.         const token = window.localStorage.getItem("jwt‐token");
  6.         if(token)
  7.             config.headers={'Authorization': 'Bearer '+token};
  8.         return config;
  9.     },
  10.     error=>{
  11.         return Promise.reject(error);
  12.     }
  13. );
  14. //响应前处理
  15. axios.interceptors.response.use(
  16.     response => {
  17.         return response;
  18.     },
  19.     error => {
  20.         const httpCode = error.response.status;
  21.         if(httpCode>=400 && httpCode<600){
  22.             window.location.href="/error" rel="external nofollow" ;
  23.         }
  24.         return Promise.reject(error);
  25.     }
  26. );
复制代码
2.4 在项目中实现请求

下面演示了ProductList组件中如何向后端请求商品信息。
  1. <template>
  2.         <div class="contentWrapper">
  3.             <h4 class="contentTitle">新品上架:</h4>
  4.             <div class="productListWrapper">
  5.                 <div class="productWrapper" v‐for="(item,i) in products" :key="i">
  6.                     <router‐link :to="{name:'product',params:{id:item.id}}">
  7.                         <img :src="'images/content/'+item.id+'‐1.jpg'" alt=""/>
  8.                     </router‐link>
  9.                 <div class="productInfoWrapper">
  10.                     <span class="productTitle">{{item.name}}</span>
  11.                     <a class="purchaseButton">¥{{item.unitPrice}} 购买</a>
  12.                 </div>
  13.             </div>
  14.           </div>
  15.         </div>
  16. </template>

  17. <script>
  18. export default {
  19.     name: 'product‐list',
  20.     data(){
  21.         return {
  22.             products:[]
  23.         };
  24.     },
  25.     mounted(){
  26.         this.fetchData();
  27.     },
  28.     methods:{
  29.         fetchData(){
  30.             if(this.$route.query.name){
  31.                 this.axios.get("/api/products?name="+this.$route.query.name).then(res=>this
  32.             }else{
  33.                 this.axios.get("/api/products/latest").then(res=>this.products=res.data);
  34.             }
  35.         }
  36.     }
  37. }
  38. </script>
复制代码
总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

来源:https://www.jb51.net/javascript/323498joc.htm
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具