路由

133 阅读6分钟

路由

1.1 路由的作用

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

1.2路由的标签

<template>
  <div id="app">
    <div id="nav">
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link>
    </div>
    <router-view/>
  </div>
</template>

是一个组件,该组件用于设置一个导航链接,切换不同 HTML 内容。 to 属性为目标地址, 即要显示的内容。

相当于占位符,用于显示路由匹配的组件,

1.3路由的配置

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'

Vue.use(VueRouter)

  const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About'
  }
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router

1.4路由的挂载

import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

使用路由构建funnyshop项目

2.1创建项目funnyshop

(1)使用命令创建项目

手动创建,选择核心插件(Babel, Router, Linter/Formatter)

vue create funnyshop

(2)项目的核心组件

组件名称组件作用
HeaderPart网页头部的导航和搜索框
FooterPart页面底部的导航
ProductList产品列表
Login登录
Register注册
ProductDetail产品详情
Cart购物车
Orders订单列表

(3)在index.html页面中导入全局样式(可选)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title>funnyshop</title>
    <link rel="stylesheet" href="<%=BASE_URL%>css/page.css"/>
    <link rel="stylesheet" href="<%=BASE_URL%>css/base.css"/>
  </head>
  <body>
  
    <div id="app"></div>    
  </body>
</html>

(4)项目的根组件App.vue

在项目根组件中导入公共子组件(header­part、footer­part)和根据路由加载的部分(router­view)

<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>

(5)路由映射定义

带router的vue2项目创建后,src目录下会多出一个名为“router”的文件夹,下面包含一个"index.js"文件,该文件用于定义路由规则,也就是不同的URL路径下所要加载的Vue子组件对应关系和参数传递规则。

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '@/components/ProductList'
import ProductDetail from '@/components/ProductDetail'
import ProductList from '@/components/ProductList'
import Login from '@/components/Login'
import Register from '@/components/Register'
import Cart from '@/components/Cart'
import Order from '@/components/Order'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'home',
    component:  Home   
  },
  {
    path: '/list',
    name: 'list',
    component:  ProductList
  },
  {
    path: '/login',
    name: 'login',
    component: Login
  },
  {
     path:'/order',
     name:'order',
     component: Order
  },
  {
    path: '/register',
    name: 'register',
    component: Register
  },
  {
    path:'/product/:id',
    name:'product',
    component: ProductDetail
  },{
    path:'/cart',
    name:'cart',
    component: Cart
  }
]

const router = new VueRouter({
  mode:'history',
  base: process.env.BASE_URL,
  routes
})

export default router

路由详解

3.1路由切换

<router‐link to="/login">登录</router‐link>
<router‐link :to="{name:'cart'}">购物车</router‐link>

3.2.路由动态参数

一个“路径参数”使用冒号 : 标记。当匹配到一个路由时,参数值会被设置到 this.$route.params,可以在每个组件内使用。

//路由定义
{ path:'/product/:id', name:'product', component: ProductDetail }
//路由链接
<router‐link :to="{name:'product',params:{id:item.id}}">产品1连接</router‐link>
//获取路由参数
let id = this.$route.params.id;

3.3.动态切换路由

通过推送路由变更$router.push(),从而实现“跳转”

在配置好路由的项目中,我们可以在任意Vue组件内部,通过this.router访问路由对象,通过router访问路由对象,通过 router.push()方法,我们可以向路由推送跳转,实现组件的切换。

this.$router.push({name:"product‐list", query:{"name":val}});

3.4.路由中查询字符串参数的获取

路径参数是URL路径的一部分,通常只能用于传递必要参数(一定要提供的参数),对于可选参数就应该使用查询字符串的方式来传递,例如:“search?name=abc&page=1”。 对于查询字符串参数,我们可以通过以下方式传递。

searchByProductName(e){
var val = e.target.value;
this.$router.push({name:"product‐list", query:{"name":val}});
}

上述路由推送会产生类似这样的URL:“product­list?name=xxxx”这时,我们可以在目标组件ProducList中,通过“$router.query.参数名”获取查询字符串参数值。

let searchName = this.$route.query.name

异步请求数据

4.1后端RESTful Web服务和代理

1)后端RESTful Web服务 SPA一般都采用前后端分离的开发方式。后端可以使用任何的服务器端Web技术,诸如JavaEE、PHP、Node.js、Python等等,后端提供基于RESTful风格的Web服务,接收前端请求并返回JSON格式的数据。

产品服务Product

URL功能
http://localhost:9090/products显示所有商品信息
http://localhost:9090/products?name=青花显示名字中包含“青花"的商品信息
http://localhost:9090/products/latest最新的4个商品信息
http://localhost:9090/products/{id}展示商品id=1的商品详情信息

用户服务Account

URL参数类型功能
http://localhost:9090/account/loginusername,passwordPOST登录
http://localhost:9090/account/delete/id请求头Authorization auth_tokenDELETE删除用户
http://localhost:9090/account/sms/codemobilePOST发送短信验证码
http://localhost:9090/account/register/{code}user对象参数POST用户注册

订单服务

URL参数类型功能
http://localhost:9090/ordersorder对象POST插入订单
http://localhost:9090/orders?username=accp用户名GET查询某个用户的所有订单
http://localhost:9090/orders/details/{orderId}订单编号GET查询订单详情

4.2服务的代理

作为前后端分离的项目,后端和前端往往不是运行在同一个服务器中的。例如上述开发中,后端的 JavaEE服务是运行在Tomcat服务器(Spring Boot内嵌的容器)中的,而前端则是使用Node.js提供的测 试服务器。前者域名为“localhost:9090”,而后者是“localhost:8080”。这时,如果前端通过AJAX技术请 求后端数据,就会遇到JavaScript请求不能跨域执行的问题而无法请求。要解决这个问题,要么就需要 使用jsonp协议(跨域JSON协议),要么就要把前后端两个服务器通过代理服务器代理到同一个域名之 下。在实际部署中,我们可以通过Nginx等静态资源服务器实现代理,而在开发中Vue项目可以直接配置 后端代理,把lcoalhost:9090的域名请求代理到localhost:3000域名之下。 在项目根目录下添加 “vue.config.js” 文件,这时vue项目的配置文件,在其中可以设置开发服务器的端 口 “port” 和后端Web服务的代理“proxy”。

module.exports={
    devServer:{
        port: 3000,
        proxy: {
            '/api':{
                target: 'http://localhost:9090',
                pathRewrite: {
                    '^/api':'' //如果本身的路径中有api则无需此设置
                }
            },
        }
    }
}

如上所示,当我们请求 “localhost:3000/api/xxx” 时,请求被代理到了 “http://localhost:9090/xxx”,这样前后端就不存在跨域问题了

4.3使用axios组件请求后台数据

(1)Promise与fetch API

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

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理

(1)构造Promise对象

 const promise = new Promise(function (resolve, reject) {
        //异步执行代码:
        var flag = true;
        if (flag) {
            resolve('执行成功');
        } else {
            reject('系统出错');
        }
    });
    promise.then(function (value) {
        console.log(value);
    }, function (error) {
        console.error(error);
    });

resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”,在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”,在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

(2)使用timeout模拟异步示例

function doExecute() {
        return new Promise(function (resolve, reject) {
            //执行异步处理
            var result = 0;
            setTimeout(function () {
                result = parseInt(Math.random() * 100);
                if (result % 2 == 0) {
                    resolve({ msg: '执行成功', data: result });
                } else {
                    reject({ msg: '程序出错发了', data: result });
                }
            }, 1000);

        })
    };
   //异步执行之后
    doExecute().then(resp => {
        console.log(resp);
    }, err=> {
        console.error(err);
    })

新一代的浏览器中都支持一个名。为fetch的API方法,可以实现Promise方式的请求。

(2)axios组件

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

(3) axios的使用

axios的详细使用请参考互联网 www.npmjs.com/package/axi…

vue add axios
MethodApi
GETaxios.get(url).then(successCallback).catch(errorHandler)
POSTaxios.post(url, data).then(successCallback).catch(errorHandler)
PUTaxios.put(url, data).then(successCallback).catch(errorHandler)
DELETEaxios.delete(url).then(successCallback).catch(errorHandler)

GET传参:

POST/PUT传参

(1)使用json对象传参(在服务器端控制器要求@RequestBody)----默认方式

axios.post(url,{username:'accp',password:'123'}).then(function(data){});

(2)使用URLSearchParams传参---表单传参

let param = new URLSearchParams();

param.append('username', this.username);

param.append('password', this.password);

axios.post(url,param).then(function(data){});