路由
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
在项目根组件中导入公共子组件(headerpart、footerpart)和根据路由加载的部分(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>
(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.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:“productlist?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/login | username,password | POST | 登录 |
| http://localhost:9090/account/delete/id | 请求头Authorization auth_token | DELETE | 删除用户 |
| http://localhost:9090/account/sms/code | mobile | POST | 发送短信验证码 |
| http://localhost:9090/account/register/{code} | user对象参数 | POST | 用户注册 |
订单服务
| URL | 参数 | 类型 | 功能 |
|---|---|---|---|
| http://localhost:9090/orders | order对象 | 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
| 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) |
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){});