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>

拓展:
微信扫码登录流程

posted @ 2023-06-07 20:57  星空看海  阅读(361)  评论(0编辑  收藏  举报