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()
img

这里可以看出:前端向后端成功发送了请求,后端也成功响应了,但是前端却报错了

这是因为:跨域问题的存在,浏览器检测到前端和后端不是来自同一个,所以认为这是不安全的,所以就拦截了该资源的传递

想要解决这个问题,就要实现: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()
img

版本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()
img

二、使用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>
img

三、前后端交互之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>

img

四、计算属性

计算属性是基于它们的依赖进行缓存的

计算属性只有在它的相关依赖发生改变时才会重新求值

计算属性就像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>
img

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

五、虚拟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算法

img

虚拟DOM数据渲染图示

img

3.具体实现

① 把树按照层级分解

img

② 按照key值比较

img

③ 通过组件进行比较

img
<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>
posted @ 2023-02-16 20:59  莫~慌  阅读(117)  评论(0编辑  收藏  举报