Vue前后端交互
一、基于jQuery的ajax前后端交互模式
版本1 - 出现了跨域问题
前端:index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue与后端交互 - 出现了跨域问题</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<button @click="handleClick">加载数据</button>
</div>
</body>
<script>
let vm = new Vue({
el: '#box',
data: {},
methods: {
handleClick() {
$.ajax({
url: 'http://127.0.0.1:5000/', // 发送请求的url,本地的5000端口,是flask的默认端口
method: 'get',
success: (data) => {
console.log(data)
}
})
}
}
})
</script>
</html>
后端:main.py
from flask import Flask # 这里用轻量级的Flask框架来测试
app = Flask(__name__)
@app.route('/')
def index():
print('请求来了')
return 'Hello World'
if __name__ == '__main__':
app.run()
这里可以看出:前端向后端成功发送了请求,后端也成功响应了,但是前端却报错了
这是因为:
跨域问题
的存在,浏览器检测到前端和后端不是来自同一个域
,所以认为这是不安全的,所以就拦截了该资源的传递想要解决这个问题,就要实现:CORS,也就是 跨域资源共享
版本2 - 解决了跨域问题
前端:index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue与后端交互 - 解决了跨域问题</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<button @click="handleClick">加载数据</button>
<p>加载的数据:{{myText}}</p>
</div>
</body>
<script>
let vm = new Vue({
el: '#box',
data: {
myText: ''
},
methods: {
handleClick() {
$.ajax({
url: 'http://127.0.0.1:5000/',
method: 'get',
success: (data) => {
console.log(data)
this.myText = data
}
})
}
}
})
</script>
</html>
后端:main.py
from flask import Flask, make_response
app = Flask(__name__)
@app.route('/')
def index():
print('请求来了')
res = make_response('Hello World')
res.headers['Access-Control-Allow-Origin'] = '*' # 访问控制允许的源 设置为全部
return res
if __name__ == '__main__':
app.run()
版本3 - 后端读取json文件传到前端
json文件:file.json
{
"name": "Darker",
"age": "18",
"gender": "male"
}
前端:index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue与后端交互 - json</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<button @click="handleClick">加载数据</button>
<p>加载的数据:{{myText}}</p>
</div>
</body>
<script>
let vm = new Vue({
el: '#box',
data: {
myText: ''
},
methods: {
handleClick() {
$.ajax({
url: 'http://127.0.0.1:5000/',
method: 'get',
success: (data) => {
console.log(data)
this.myText = data
}
})
}
}
})
</script>
</html>
后端:main.py
import json
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/')
def index():
print('请求来了')
with open('file.json', mode='rt', encoding='utf-8') as f:
dic = json.load(f)
res = jsonify(dic)
res.headers['Access-Control-Allow-Origin'] = '*'
return res
if __name__ == '__main__':
app.run()
二、使用fetch前后端交互
1.简介
① fetch介绍
提供了一个 JavaScript 接口,用于访问和操纵 HTTP 管道的一些具体部分,例如请求和响应
它还提供了一个全局 fetch()
方法,该方法提供了一种简单,合理的方式来跨网络异步获取资源
② fetch基本格式
fetch('http://example.com/movies.json')
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(myJson);
});
③fetch请求参数
- method(String):HTTP请求方法,默认为GET(GET、POST、PUT、DELETE)
- body(String):HTTP的请求参数
- headers(Object):HTTP的请求头,默认为{}
2.示例
json文件:file.json
{
"name": "Darker",
"age": "18",
"gender": "male"
}
后端:main.py
import json
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/')
def index():
print('请求来了')
with open('file.json', mode='rt', encoding='utf-8') as f:
dic = json.load(f)
res = jsonify(dic)
res.headers['Access-Control-Allow-Origin'] = '*'
return res
if __name__ == '__main__':
app.run()
前端:index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue与后端交互 - fetch</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<button @click="handleClick">加载数据</button>
<p>加载的数据:</p>
<ul>
<li >姓名:{{name}}</li>
<li >年龄:{{age}}</li>
<li >性别:{{gender}}</li>
</ul>
</div>
</body>
<script>
let vm = new Vue({
el: '#box',
data: {
name:'',
age: '',
gender: ''
},
methods: {
handleClick() {
fetch('http://127.0.0.1:5000/').then(response => {
return response.json()
}).then(json => {
console.log('从后端获取的json数据', json) // success 获取的数据
this.name = json.name
this.age = json.age
this.gender = json.gender
}).catch(ex => {
console.log('出现了异常', ex) // 抛出异常
})
}
}
})
</script>
</html>
三、前后端交互之axios
1.简介
① Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中
② axios官网:http://www.axios-js.com/
2. axios的响应结果
- data:实际响应回来的数据
- headers:响应头信息
- status:响应状态码
- statusText:响应状态信息
3.示例(电影小案例)
json文件:film.json(这里只是一部分,原代码太多了...)
https://m.maizuo.com/v5/?co=mzmovie#/films/nowPlaying
后端:main.py
import json
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/film')
def index():
print('请求来了')
with open('film.json', mode='rt', encoding='utf-8') as f:
dic = json.load(f)
res = jsonify(dic)
res.headers['Access-Control-Allow-Origin'] = '*'
return res
if __name__ == '__main__':
app.run()
前端:index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue与后端交互</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.0/axios.min.js"></script>
</head>
<body>
<div id="box">
<button @click="handleClick">加载电影数据</button>
<p>加载的数据:</p>
<ul>
<li v-for="item in dataList">
<p>电影:{{item.name}}</p>
<p>导演:{{item.director}}</p>
<img :src="item.poster" alt="">
</li>
</ul>
</div>
</body>
<script>
let vm = new Vue({
el: '#box',
data: {
dataList: []
},
methods: {
handleClick() {
axios.get("http://127.0.0.1:5000/film/").then(res => {
console.log(res.data.data.films) // axios 自动包装data属性 res.data
this.dataList = res.data.data.films
}).catch(err => {
console.log(err);
})
}
}
})
</script>
</html>
四、计算属性
计算属性是基于它们的依赖进行缓存的
计算属性只有在它的相关依赖发生改变时才会重新求值
计算属性就像
Python
中的property
,可以把方法/函数
伪装成属性
1.通过计算属性实现名字首字母大写
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首字母大写</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<!--大段的代码写在这里不好,使用计算属性-->
模板插值:
{{myText.substring(0,1).toUpperCase()+myText.substring(1)}}
<p>普通方法:{{getNameMethod()}}</p>
<!--区别是在同一个页面中使用多次计算属性,不会多次执行-->
<p>计算属性:{{getName}}</p>
<!--普通方法要加括号-->
</div>
</body>
<script>
var vm = new Vue({
el: '#box',
data: {
myText: 'darker',
},
computed: {
getName() { // 依赖的状态改变了,会重新计算
return this.myText.substring(0, 1).toUpperCase() + this.myText.substring(1)
}
},
methods: {
getNameMethod() {
return this.myText.substring(0, 1).toUpperCase() + this.myText.substring(1)
}
}
})
</script>
</html>
2.通过计算属性重写过滤案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>通过计算属性重写过滤案例</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<p><input type="text" v-model="myText" placeholder="请输入要筛选的内容:"></p>
<ul>
<li v-for="data in newList">{{data}}</li>
</ul>
</div>
</body>
<script>
var vm = new Vue({
el: '#box',
data: {
myText: '',
dataList: ['a', 'at', 'atom', 'be', 'beyond', 'cs', 'csrf'],
},
computed: {
newList() {
return this.dataList.filter(item => {
return item.indexOf(this.myText) > -1 // 返回索引大于1的元素:>-1 就表示包含在其中
})
}
}
})
</script>
</html>
五、虚拟DOM 与diff算法 key的作用
1.Vue2.0 v-for 中 :key 有什么用呢?
其实呢不只是vue,react中在执行列表渲染时也会要求给每个组件添加key这个属性
key简单点来说就是唯一标识,就像ID一样唯一性
要知道,vue和react都实现了一套虚拟DOM,使我们可以不直接操作DOM元素
,只操作数据
便可以重新渲染页面
而隐藏在背后的原理便是其高效的Diff算法
- 分层级比较:只做同层级的对比
- 通过key值比较:出现新的key就插入同组(循环中,尽量加
key
,让key值唯一) - 通过组件/标签进行比较:然后进行替换
2.虚拟DOM的diff算法
虚拟DOM数据渲染图示
3.具体实现
① 把树按照层级分解
② 按照key值比较
③ 通过组件进行比较
<div id="box">
<div v-if="isShow">111</div>
<p v-else>222</p>
<!--
{tag:div,value:111}
{tag:p,value:222}
直接不比较,直接删除div,新增p
-->
<div v-if="isShow">111</div>
<div v-else>222</div>
<!--
{tag:div,value:111}
{tag:div,value:222}
比较都是div,只替换文本内容
-->
</div>