Vue与后端交互
目录
一 与后端交互三种方式
# 后端写了一堆接口
# 前端会了
# 前后端要打通----> 从前端发送ajax---> 核心:使用js发送http请求,接收返回
-原生js,可以开启ajax,但是原生js开启,比较麻烦,需要做浏览器兼容,有坑(基本不写)
-jq,写了个兼容所有浏览器的 $.ajax(),不仅仅有ajax,还封装了很多dom操作
-如果vue中使用它,不合适
-axios:第三方的ajax包(咱们用)
-fetch: 原生js发送ajax请求,有的浏览器也不兼容
使用flask写个后端
# pip3 install flask
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/')
def index():
print('来了,老弟')
# 前后端分离后,一定会出跨域---> 后面要解决的重点
# 在响应头中加入:Access-Control-Allow-Origin ,就就可以解决跨域
res = jsonify({'name': '彭于晏', 'age': 19})
res.headers = {'Access-Control-Allow-Origin': '*'}
return res
if __name__ == '__main__':
app.run()
1.1 使用jq的ajax
前端的:index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>使用jq的ajax与后端交互</title>
<script src="./js/vue.js"></script>
<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
</head>
<body>
<div id="app">
<button @click="handleLoad">点我加载数据</button>
<hr>
您的名字是:{{name}},您的年龄是:{{age}}
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
name: '',
age: '',
},
methods: {
// 请求发送成功,后端执行了,但是被浏览器拦截了,因为有跨域问题
// 当前地址,如果向非浏览器地址栏中得地址发送请求,就会出现跨域
// 1 ajax请求方式 1 jquery的ajax
handleLoad() {
var _this = this
$.ajax({
url: 'http://127.0.0.1:5000', // 5000是flask的默认端口
type: 'get',
success: function (data) {
// console.log(data)
// console.log(typeof data) // 是字符串格式
var res = JSON.parse(data) // 反序列化成对象形式
// 替换掉页面上的变量
_this.name = res.name
_this.age = res.age
}
})
}
}
})
</script>
</html>
1.2 使用fetch
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>使用js原生的fetch与后端进行数据交互</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
<button @click="handleLoad">点我加载数据</button>
<button @click="handleLoad2">点我加载数据2</button>
<hr>
您的名字是:{{name}},您的年龄是:{{age}}
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
name: '',
age: '',
},
methods: {
// 2 使用js原生的fetch(目前也不用)
handleLoad() {
var _this = this
// fetch(请求地址).then(匿名函数,这个匿名函数返回json格式数据).then(匿名函数)
fetch('http://127.0.0.1:5000').then(function (response) {
// console.log(response); // 返回response对象
return response.json();
}).then(function (res) {
console.log(res); // 对象:{age: 19, name: '彭于晏'}
_this.name = res.name
_this.age = res.age
})
},
handleLoad2(){
// 简写,使用箭头函数
fetch('http://127.0.0.1:5000').then(response => response.json()).then(res => {
console.log(res)
this.name = res.name
this.age = res.age
})
}
}
})
</script>
</html>
1.3 使用axios(以后用这个)
axios的文档:http://www.axios-js.com/zh-cn/docs/
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>使用axios与后端进行数据交互</title>
<script src="./js/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<button @click="handleLoad">点我加载数据</button>
<button @click="handleLoad2">点我加载数据2</button>
<hr>
您的名字是:{{name}},您的年龄是:{{age}}
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
name: '',
age: '',
},
methods: {
// 3 使用axios ,以后都用它
handleLoad() {
var _this = this
// axios.请求方式(请求地址).then(匿名函数),匿名函数接收一个参数,参数是后端符合response格式的对象
axios.get('http://127.0.0.1:5000').then(function (res) {
console.log(res.data)
_this.name = res.data.name
_this.age = res.data.age
})
},
handleLoad2() {
// 简写,使用箭头函数
axios.get('http://127.0.0.1:5000').then(res => {
console.log(res.data)
this.name = res.data.name
this.age = res.data.age
})
}
}
})
</script>
</html>
二 箭头函数
# es6 的语法
1 函数写法变简单
2 箭头函数没有自己的this,在箭头函数中使用this,就是它上一层的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>箭头函数</title>
</head>
<body>
</body>
<script>
// 1. 无参数,无返回值
// var f = function () {
// console.log('我是匿名函数')
// }
// var f = () => {
// console.log('我是匿名函数1')
// }
// f()
// 2. 有一个参数,没有返回值,箭头函数可以省略括号
// var f = function (name) {
// console.log('我是匿名函数', name)
// }
// var f = name => {
// console.log('我是匿名函数1', name)
// }
// f('lqz')
// 3. 多个参数,没有返回值,箭头函数不能省略括号
// var f = function (name, age) {
// console.log('我是匿名函数', name, age)
// }
// var f = (name, age) => {
// console.log('我是匿名函数1', name, age)
// }
// f('lqz', 19)
// 4. 多个参数,一个返回值, 箭头函数简写:省了return和大括号
// var f = function (name, age) {
// return name + 'nb'
// }
// var f = (name, age) => name + 'nb'
// var res = f('lqz1', 19)
// console.log(res)
// 5. 一个参数,一个返回值
var f = name => name + 'nb'
var res = f('lqz')
console.log(res)
</script>
</html>
三 加载电影案例
后端
# 使用flask写个服务端
from flask import Flask, jsonify
import json
app = Flask(__name__)
@app.route('/files/')
def films():
# 读取文件中的数据
with open('filme.json', 'rt', encoding='utf-8') as f:
data = json.load(f)
res = jsonify(data)
res.headers = {'Access-Control-Allow-Origin': '*'}
return res
if __name__ == '__main__':
app.run()
前端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>电影数据案例</title>
<script src="./js/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<button @click="handleLoad">加载电影数据</button>
<hr>
<ul>
<li v-for="item in dataList">
<h3>电影名字:{{item.name}}</h3>
<h3>导演:{{item.director}}</h3>
<p>电影介绍:{{item.synopsis}}</p>
<p>图片:
<!--图片src(路径)用属性指令获取-->
<img :src="item.poster" alt="" height="300px">
</p>
</li>
</ul>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
dataList: []
},
methods: {
handleLoad() {
axios.get('http://127.0.0.1:5000/files/').then(res => {
console.log(res.data.data.films)
this.dataList = res.data.data.films
})
}
}
})
</script>
</html>
四 使用Django写后端
后端
路由
from django.urls import path
from app01 import views
urlpatterns = [
path('index/', views.UserView.as_view()),
path('film/', views.FileView.as_view()),
]
视图层
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
import json
class UserView(APIView):
def get(self, request):
print('index----')
data = {'name': '彭于晏', 'age': 19}
obj = Response({'data': data})
obj['Access-Control-Allow-Origin'] = '*'
return obj
class FileView(APIView):
def get(self, request):
print('film----')
with open('filme.json', 'rt', encoding='utf-8') as f:
data = json.load(f)
print('读取文件成功')
obj = Response({'data': data})
obj['Access-Control-Allow-Origin'] = '*'
return obj
数据案例前端:index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>使用axios与后端进行数据交互</title>
<script src="./js/vue.js"></script>
<script src="./js/axios.js"></script>
</head>
<body>
<div id="app">
<button @click="handleLoad">点我加载数据</button>
<button @click="handleLoad2">点我加载数据2</button>
<hr>
您的名字是:{{name}},您的年龄是:{{age}}
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
name: '',
age: '',
},
methods: {
// 3 使用axios ,以后都用它
handleLoad() {
var _this = this
// axios.请求方式(请求地址).then(匿名函数),匿名函数接收一个参数,参数是后端符合response格式的对象
axios.get('http://127.0.0.1:8000/index/').then(function (res) {
console.log(res.data.data)
_this.name = res.data.data.name
_this.age = res.data.data.age
})
},
handleLoad2() {
// 简写,使用箭头函数
axios.get('http://127.0.0.1:8000/index/').then(res => {
console.log(res.data.data)
this.name = res.data.data.name
this.age = res.data.data.age
})
}
}
})
</script>
</html>
电影案例前端:file.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>电影数据案例</title>
<script src="./js/vue.js"></script>
<script src="./js/axios.js"></script>
</head>
<body>
<div id="app">
<button @click="handleLoad">加载电影数据</button>
<hr>
<ul>
<li v-for="item in dataList">
<h3>电影名字:{{item.name}}</h3>
<h3>导演:{{item.director}}</h3>
<p>电影介绍:{{item.synopsis}}</p>
<p>图片:
<!--图片src(路径)用属性指令获取-->
<img :src="item.poster" alt="" height="300px">
</p>
</li>
</ul>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
dataList: []
},
methods: {
handleLoad() {
axios.get('http://127.0.0.1:8000/film/').then(res => {
console.log(res.data.data.data.films)
this.dataList = res.data.data.data.films
})
}
}
})
</script>
</html>
五 计算属性
- 计算属性是基于它们的依赖变量进行缓存的
- 计算属性只有在它的相关依赖变量发生改变时才会重新求值,否则不会变(函数只要页面变化,就会重新运算)
- 计算属性就像Python中的property,可以把方法/函数伪装成属性
- 计算属性,必须有返回值
1.通过计算属性实现名字首字母大写
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>计算属性</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
<h1>实现输入input中后名字首字母大写</h1>
<!--先用字符串的切分substring,使用toUpperCase转换成大写,再跟剩下的字符拼在一起-->
<input type="text" v-model="username"> ----> {{username.substring(0, 1).toUpperCase() + username.substring(1)}}
<br>
<h2>函数:</h2>
<!--大段的代码写在这里不好,使用函数-->
<input type="text" v-model="username1">--->{{getUpperCase()}}
<br>
<input type="text" v-model="age"> ----> {{age}}
<!--只要页面改变,页面就会刷新,函数就会执行-->
<h2>通过计算属性实现:--> 当属性用</h2>
<!--需要写成方法,可以将方法伪装成属性,直接当成属性使用-->
<!--只有在它的相关依赖变量发生改变时才会重新求值,否则不会变-->
<input type="text" v-model="name"> ---> {{getName}}
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
username: '',
username1: '',
age: '',
name: '',
},
methods: {
getUpperCase() {
console.log('函数我执行了')
return this.username1.substring(0, 1).toUpperCase() + this.username1.substring(1)
}
},
// 使用计算属性
computed: {
getName() {
// 计算属性,必须有返回值
console.log('计算属性执行了')
return this.name.substring(0, 1).toUpperCase() + this.name.substring(1)
}
}
})
</script>
</html>
2.通过计算属性重写过滤案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>使用计算属性写过滤案例</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="search">
<hr>
<ul>
<li v-for="item in newDataList">{{item}}</li>
</ul>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
search: '',
dataList: ['a', 'at', 'atom', 'atomic', 'be', 'beyond', 'cs', 'csrf'],
},
computed: {
newDataList() {
return this.dataList.filter(i => i.indexOf(this.search) >= 0)
}
}
})
</script>
</html>
3.通过计算属性重写购物车案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>购物车案例使用计算属性</title>
<script src="./js/vue.js"></script>
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css">
</head>
<body>
<div id="app">
<div class="container-fluid">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<h1 class="text-center">购物车</h1>
<table class="table table-bordered">
<thead>
<tr>
<th>商品id</th>
<th>商品名称</th>
<th>商品价格</th>
<th>商品数量</th>
<!--设置个checkbox单选框 -->
<!--选中checkAll为true,不选中checkAll为false-->
<!--绑定change事件,checkGroup变量变满值-->
<th>全选/全不选 <input type="checkbox" v-model="checkAll" @change="handleCheckAll"></th>
<th>删除操作</th>
</tr>
</thead>
<tbody>
<tr v-for="good in good_list">
<th scope="row">{{good.id}}</th>
<td>{{good.name}}</td>
<td>{{good.price}}</td>
<!--数量前后加个按钮-->
<td>
<!--点击事件需要改变商品数量值,要先把值传入-->
<button class="btn" @click="handleReduce(good)">-</button>
{{good.number}}
<!--加个click事件-->
<button class="btn link btn-sm" @click="good.number++">+</button>
</td>
<!-- 选择框后,value值定义商品对象, -->
<td><input type="checkbox" :value="good" v-model="checkGroup" @change="handleChangeOne"></td>
<td>
<button class="btn btn-danger" @click="handleDelete(good)">删除</button>
</td>
</tr>
<tr class="text-left">
<!-- <td colspan="4">总价:{{getPrice()}}</td>-->
<td colspan="4">总价:{{price}}</td>
</tr>
</tbody>
</table>
<hr>
选中了:{{checkGroup}}
<br>
全选/全不选的值:{{checkAll}}
</div>
</div>
</div>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
good_list: [
{id: 1, name: '钢笔', price: 12, number: 2},
{id: 2, name: '脸盆', price: 20, number: 20},
{id: 3, name: '毛笔', price: 6, number: 9},
{id: 4, name: '圆珠笔', price: 8, number: 5},
{id: 5, name: '铅笔', price: 1, number: 3},
],
checkGroup: [],
checkAll: false,
},
methods: {
handleCheckAll() {
// console.log(this.checkAll) // 布尔值,选中是true,不选中false
// 全选中:对钩都打上,js中得含义是:checkGroup变量满值
if (this.checkAll) {
this.checkGroup = this.good_list // 全选
} else {
this.checkGroup = [] // 全不选
}
},
// 给每一个循环中的checkbox框,增加一个change事件,只要一个没有选中,就把checkAll的值变为false
handleChangeOne() {
// 判断 checkGroup的长度,是否等于good_list长度
if (this.checkGroup.length === this.good_list.length) {
this.checkAll = true
} else {
this.checkAll = false
}
},
handleReduce(good) {
// 不能减到底,商品数量肯定要大于1
if (good.number > 1) {
good.number--
} else {
alert('太少了,不能再减少了')
}
},
handleDelete(good) {
// console.log(this.good_list.indexOf(good))
this.good_list.splice(this.good_list.indexOf(good), 1)
// console.log(this.good_list)
}
},
computed: {
// 总价使用计算属性
price() {
// 根据checkGroup选中的对象,计算
// 使用of 循环checkGroup,拿出价格*数量,累加,最后返回
var total = 0
for (item of this.checkGroup) {
total += item.number * item.price
}
return total
}
}
})
</script>
</html>
六 监听(侦听)属性
- 属性如果发生变化,就会执行某个函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>监听属性/侦听属性</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
<h1>监听属性</h1>
<input type="text" v-model="username"> ---> {{username}}
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
username:'',
},
watch:{
// 如果 username 发生改变,这个函数就会运行
// 再定义一个 username 方法
username(newValue, oldValue){
console.log('老值', oldValue)
console.log('新值', newValue)
console.log('我发生变化了')
}
}
})
</script>
</html>
拓展:
微信扫码登录流程