Vue基础入门-02
配套源码下载 传送门
1 购物车案例
要求实现功能:
- 能够增加商品,随意调整购买件数
- 计算出商品价格,病假算出总价
- 总价随购买件数自动调整
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<table border="1" width="30%">
<tr>
<th>编号</th>
<th>名称</th>
<th>价格</th>
<th>购买数量</th>
<th>小计</th>
</tr>
<tr v-for="(item,index) in books">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.price}}</td>
<td><input type="button" value="+" @click="add(index)"> {{item.count}} <input type="button" value="-" @click="low(index)"></td>
<td>{{(item.price * item.count).toFixed(2)}}</td>
</tr>
</table>
<h2>总价格为:{{sum().toFixed(2)}}</h2>
<h2>总价格为:{{sum().toFixed(2)}}</h2>
添加书籍:<br>
id:<input type="text" v-model="book.id">
name:<input type="text" v-model="book.name">
price:<input type="text" v-model="book.price">
count:<input type="text" v-model="book.count">
<button @click="addBook">添加</button>
</div>
<script src="statics/vue.js"></script>
<script>
const app = new Vue({
el:"#app",
data:{
books:[
{
id:101,
name:"追风筝的人",
price:19.9,
count:2,
},
{
id:102,
name:"时间简史",
price:34.6,
count:1,
}
],
book:{}
},
methods:{
add(index){
this.books[index].count++
},
low(index){
if(this.books[index].count < 1){
alert('无法再下降!!!')
return false
}
this.books[index].count--
},
addBook(){
if(!this.book.id){
alert('请输入编号!!!')
return false
}
if(!this.book.name){
alert('请输入书名!!!')
return false
}
if(!this.book.price){
alert('请输入价格!!!')
return false
}
if(!(this.book.count>0)){
alert('请输入正确的数量!!!')
return false
}
this.books.push(this.book)
this.book = {}
},
sum(){
console.log("调用了methods sum")
let sum = 0
for(let i=0;i<this.books.length;i++){
sum += this.books[i].count * this.books[i].price
}
return sum
},
},
computed:{
}
})
</script>
</body>
</html>
代码演示:
2 computed 计算属性
- 作用:
- 用来在vue实例中完成相关业务计算工作
- 某个数据渲染页面时如果该数据需要经过业务处理之后再渲染就可以使用
computed
- 好处:
- 提升vue运行性能
- 主要使用
computed
进行计算相关处理会将第一次计算结果进行缓存,便于页面多次使用 - 使用缓存,不会重复调用方法,当vue的对象值发生变化后才会再次进行计算
- 使用:
{{属性名}}
在上一节的购物车案例中,计算总价格sum
函数是用methods实现的,按照Vue的思想,应该使用computed
计算属性,因为可能不止一次展示此数据。
// 是计算属性,所以不需要()
<h2>总价格为:{{sum.toFixed(2)}}</h2>
computed:{
sum(){
console.log("调用了computed sum")
let sum = 0
for(let i=0;i<this.books.length;i++){
sum += this.books[i].count * this.books[i].price
}
return sum
}
computed 和 methods 对比:
我们同时调用两次sum
的计算购物车的总价格:
使用computered
:
使用methods
:
3 事件修饰符
Vue的事件修饰符有5个:
修饰符 | 作用 |
---|---|
.stop(常用) | 阻止事件的冒泡,阻止事件继续传播 |
.prevent | 阻止事件原来默认事件 |
.capture | 捕获监听器,可理解为改变冒泡的顺序 |
.self | 只在事件本身的元素及以上触发,不在子元素的事件链中 |
.once | 只触发一次 |
示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<div style="width: 300px; height: 300px;background-color:pink;" @click="grandparent">
<div style="width: 200px; height: 200px;background-color:skyblue;" @click="parent">
<div style="width: 100px; height: 100px;background-color:green;"@click="child"></div>
</div>
</div>
</div>
<script src="statics/vue.js"></script>
<script>
new Vue({
el:'#app',
methods:{
grandparent(){
console.log("grandparent")
},
parent(){
console.log("parent")
},
child(){
console.log("child")
}
}
})
</script>
</body>
</html>
3.1 .stop
在使用.stop
之前,我们先来理解什么是事件冒泡?
当子元素(事件源)事件触发,事件会沿着包含关系,依次往上级传递,每一级都可以感知到事件,直到触发根元素(根源),就像冒泡泡那样向上传递到水面为止。
事件冒泡具体例子:
我们分别为grandparent
、parent
和child
添加对应的点击事件。
点击child
的时候,会向上传递,三个事件都会触发到点击事件。
如果我们只想触发child
事件的时候,我们只需将改成@click.stop="child
,下面看看演示效果!
3.2 .prevent
.prevent
为阻止元素的默认事件,一般有a
、submit
这些标签原生带有自己的默认事件。
例如下面这个例子,究竟是执行谁呢?
<a href="https://www.baidu.com" @click="child">点击页面</a>
答案是两个都会执行,当我们点击链接之后,会首先触发点击事件child
,接着再去访问链接百度。
如果我们只想触发child
事件的时候,我们只需将改成@click.prevent="child
,下面看看演示效果!
我们发现并没有跳转到百度页面,而只执行了点击事件child
3.3 .self
.self
只接受自己的点击事件,而不接受冒泡的事件。
例如下面这个例子:我们在parent的点击事件上加上.self
,则它只接受它本身的点击事件。冒泡的事件则将其跳过。
下面来看演示示例:
我们可以看到当我们点击child
时,冒泡将parent
事件跳过,而去执行grandparent
,而我们点击parent
的时候,它将自己的点击事件接受了,并向上冒泡。
3.4 .once
.once 带有此修饰符的事件只会触发一次
这个不用解释了,很容易理解。
4 axios
4.1 简单介绍
- axios是前端的异步请求库 类似于JQuery的ajax技术
- ajax用于页面发起异步请求到后端服务,并将后端服务相应数据渲染到页面上
- JQuery推荐使用ajax技术,vue则推荐axios
- 总之,axios就是用来在前端页面发起一个异步请求,请求之后页面不动,响应回来刷新页面局部
4.2 基本使用
4.2.1 引入axios的JS文件
<script src="statics/axios.js"></script>
4.2.2 解决跨域问题
package com.cycyong.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
// 设置允许跨域的路径
registry.addMapping("/**")
// 设置允许跨域请求的域名
.allowedOriginPatterns("*")
// 是否允许cookie
.allowCredentials(true)
// 设置允许的请求方式
.allowedMethods("GET", "POST", "DELETE", "PUT")
// 设置允许的header属性
.allowedHeaders("*")
// 跨域允许时间
.maxAge(3600);
}
}
4.2.3 发送GET请求
前端:
axios.get("http://localhost:8081/demo/get?username=cycyong&password=123456")
.then(function (resp){
console.log(resp)
console.log(resp.data)
})
.catch(function (error){
console.log(error)
})
后端:
@GetMapping("/demo/get")
public String demo1(@RequestParam("username") String username,
@RequestParam("password") String password){
System.out.println(username);
System.out.println(password);
return "OK_GET";
}
运行结果:
4.2.4 发送POST请求
前端:
axios.post("http://localhost:8081/demo/post",{username:"cycyong",password:"123456"})
.then(function (resp) {
console.log(resp)
console.log(resp.data)
})
.catch(function (error) {
console.log(error)
})
后端:
package com.cycyong.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private String username;
private String password;
}
@PostMapping("/demo/post")
public String demo2(@RequestBody User user){
System.out.println(user);
return "OK_POST";
}
运行结果:
4.3 创建实例发送请求
创建一个默认实例:
更多参数设置可参照官方文档 传送门
const instance = axios.create({
// 基础地址
baseURL:'http://localhost:8081',
// 请求超时的毫秒数
timeout:5000,
// 自定义请求头
headers:{'X-Custom-Header': 'foobar'}
})
这样配置之后,我们在写请求的时候就稍微变简单了!!!
GET请求:
instance.get("/demo/get?username=cycyong&password=123456")
.then(function (resp) {
console.log(resp.data)
})
.catch(function (error) {
console.log(error)
})
POST请求:
instance.post("/demo/post",{username:"cyc",password:"123"})
.then(function (resp) {
console.log(resp.data)
})
.catch(function (error) {
console.log(error)
})
4.4 拦截器
4.4.1 作用
用来将axios中共有的参数,响应公共处理交给拦截器处理,减少axios发送请求时产生的代码冗余。
4.4.2 拦截器类型
- 请求拦截器
- 响应拦截器
4.4.3 请求拦截器的使用
使用案例,在每一个的请求后面加上token
instance.interceptors.request.use(function (config) {
console.log(config)
if(config.url.indexOf("?")===-1){
config.url +='?token=123456'
}else{
config.url +='&token=123456'
}
return config;
})
运行结果:
4.4.4 响应拦截器的使用
使用案例,请求响应错误汇总
instance.interceptors.response.use(function (response) {
console.log(response)
if(response.status===500){
alert('服务器异常!')
}
return response;
})