vue---day04(购物车案例,带全选全不选按钮,商品的数量带加减按钮,v-model进阶,各种方法用ajax与后端交互,)

昨日回顾

# 1 v-for 可以循环的 类型 
# 2 js的循环方式
	-基于索引的循环 (i=0;i<10;i++)
    -in  循环出来的是索引
    -of  基于迭代的,循环出来就是值
    -数组.each(item=>{})
    -ajax  forEach 循环

    
# 3 key值的解释  :key='唯一值'
# 4 数组对象的检测与更新
	Vue.set()
    
    
# 5 input:事件
	-change
    -blur
    -focus
    -click
    -input
    
    
# 6 v-model  input标签上
# 7 过滤案例
	-1 数组的.filter((item)=>{ return true})
	-2 字符串的 indexOf  判断子字符串是否在字符串中,如果在大于等于0,如果不在,等于-1
    -3 箭头函数
    	var f=item=>item+xxx
# 8 事件修饰符
	-once
    -stop
    -self
    -prevent
    
# 9 按键事件,按键修饰符
	@keyup='函数'
    @keyup.enter='函数'
    
    
# 10 表单控制
	-radio  :字符串类型  多个radio使用v-model绑定,选中某个会把 value 赋值给这个变量
    -chekbox 
    	-单选:布尔类型
        -多选:数组中

.
.
.
.
.

今日内容

1 购物车案例

1.1 基本购物车

# js的变量只要发生变化,html页面中使用该变量的地方,就会重新渲染!!!这就是vue的特性
# 只要页面中变量对应的数据发生变化,页面会重新渲染,但渲染只渲染使用该变量的地方
# 插值里面可以放函数,函数里面使用了的变量如果发生改变,函数会重新运行,
# 用到该函数的地方就会重新加载!!!
-------------------------------------
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="js/vue.js"></script>
    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"
          integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
</head>
<body>
<div class="app">
    <div class="container-fluid">
        <div class="row">
            <div class="col-md-6 col-md-offset-3">
                <h1>购物车案例</h1>

                <table class="table table-bordered">
                    <thead>
                    <tr>
                        <th>商品编号</th>
                        <th>商品名字</th>
                        <th>商品价格</th>
                        <th>商品数量</th>
                        <th>选择</th>
                    </tr>
                    </thead>
                    <tbody>
                    <tr v-for="item in goodList">
                        <th scope="row">{{item.id}}</th>
                        <td>{{item.name}}</td>
                        <td>{{item.price}}</td>
                        <td>{{item.number}}</td>
                        <td><input type="checkbox" v-model="checkGroup" :value="item" @change="handleChange"></td>
                    </tr>
                    </tbody>
                </table>
                <hr>
                <p>选中商品:{{checkGroup}}</p>

                <p>总价格:{{aaa}}</p>
            </div>

        </div>

    </div>


</div>
</body>

<script>
    var vm = new Vue({
        el: '.app',
        data: {
            goodList: [
                {id: '1', name: '钢笔', price: 20.1, number: 2},
                {id: '2', name: '饼干', price: 4, number: 1},
                {id: '3', name: '辣条', price: 5, number: 5},
            ],
            checkGroup: [],
            aaa:''
        },
        methods: {
            handleChange() {
                // 通过checkgroup里面的对象,计算出总价格
                var total = 0
                for (item of this.checkGroup) {
                    total += item.price * item.number
                }
                this.aaa = total

            }
        },
    })
</script>
</html>
-------------------------------------
或者这样,不要change事件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="js/vue.js"></script>
    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"
          integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
</head>
<body>
<div class="app">
    <div class="container-fluid">
        <div class="row">
            <div class="col-md-6 col-md-offset-3">
                <h1>购物车案例</h1>

                <table class="table table-bordered">
                    <thead>
                    <tr>
                        <th>商品编号</th>
                        <th>商品名字</th>
                        <th>商品价格</th>
                        <th>商品数量</th>
                        <th>选择</th>
                    </tr>
                    </thead>
                    <tbody>
                    <tr v-for="item in goodList">
                        <th scope="row">{{item.id}}</th>
                        <td>{{item.name}}</td>
                        <td>{{item.price}}</td>
                        <td>{{item.number}}</td>
                        <td><input type="checkbox" v-model="checkGroup" :value="item"></td>
                    </tr>
                    </tbody>
                </table>
                <hr>
                <p>选中商品:{{checkGroup}}</p>
                <p>总价格:{{getPrice()}}</p>
            </div>

        </div>

    </div>


</div>
</body>

<script>
    var vm = new Vue({
        el: '.app',
        data: {
            goodList: [
                {id: '1', name: '钢笔', price: 20.1, number: 2},
                {id: '2', name: '饼干', price: 4, number: 1},
                {id: '3', name: '辣条', price: 5, number: 5},
            ],
            checkGroup: [],
        },
        methods: {
            getPrice() {
                // 通过checkgroup里面的对象,计算出总价格
                var total = 0
                for (item of this.checkGroup) {
                    total += item.price * item.number
                }
                return total
            }
        },
    })
</script>
</html>

-------------------------------------

.

代码总结:
每一条商品的信息组成一个字典,将字典放到数组里面,先通过v-for循环拿到每一个字典对象
然后通过checkbox的value属性绑定为字典对象,就可以在选中多选框的时候,从checkbox的
v-model绑定的变量名对应的数组中,拿到对应的字典对象
可以给多选框绑定一个change事件,也可以不用change事件

只要页面中变量对应的数据发生变化,页面会重新渲染,但渲染只渲染使用该变量的地方
js的变量只要发生变化,html页面中使用该变量的地方,就会重新渲染,这就是vue的特性

所以变量checkGroup 一旦变化,使用变量checkGroup的地方就会重新渲染
所以利用插值语法{{getPrice()}}获得的总价格,会随着数组的变化,同时变化

.
.
.
.
.

1.2 带全选全不选按钮

代码要点:
给全选按钮绑定一个change事件,如何实现当点击全选按钮后,所有的多选框都被选中?
还是利用Vue数据的双向绑定原理,只要将多选框的v-model对应的变量名checkGroup对应的
数组里面,添加对应的数据,勾就自动打上了,所以多选,只需要往checkGroup对应的数组里面
添加所有对应的数据,页面上所有的勾就打上了,就不用手动再去点了

优化点:
当全选后,当随机取消一个商品选中按钮后,按理说全选的按钮,应该也自动被取消选中
当所有商品的按钮被选中后,全选按钮也应该自动被选中

所以需要给每一个checkbox按钮都绑定一个change事件,并判断checkGroup对应的数组
是否等于全部的数据,如果等于了,应该让变量名checkAll对应的值由原来的false变为true,
这样全选框里面的钩子就自动被勾上了!!!否则应该让变量名checkAll对应的值为false!!!

-----------------------------------------
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"
          integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
</head>
<body>
<div class="app">
    <div class="container-fluid">
        <div class="row">
            <div class="col-md-6 col-md-offset-3">
                <h1>购物车案例</h1>

                <table class="table table-bordered">
                    <thead>
                    <tr>
                        <th>商品编号</th>
                        <th>商品名字</th>
                        <th>商品价格</th>
                        <th>商品数量</th>
                        <th>全选/全不选 <input type="checkbox" v-model="checkAll" @change="handleCheckAll"></th>
                    </tr>
                    </thead>
                    <tbody>
                    <tr v-for="item in goodList">
                        <th scope="row">{{item.id}}</th>
                        <td>{{item.name}}</td>
                        <td>{{item.price}}</td>
                        <td>{{item.number}}</td>
                        <td><input type="checkbox" v-model="checkGroup" :value="item" @change="handelCheckOne"></td>
                    </tr>
                    </tbody>
                </table>
                <hr>
                <p>选中商品:{{checkGroup}}---{{checkAll}}</p>
                <p>总价格:{{getPrice()}}</p>
            </div>

        </div>

    </div>


</div>
</body>
<script>
    var vm = new Vue({
        el: '.app',
        data: {
            goodList: [
                {id: '1', name: '钢笔', price: 20.1, number: 2},
                {id: '2', name: '饼干', price: 4, number: 1},
                {id: '3', name: '辣条', price: 5, number: 5},
            ],
            checkGroup: [],
            checkAll: false,
        },
        methods: {
            getPrice() {
                // 通过checkGroup里面的对象,计算出总价格
                var total = 0
                for (item of this.checkGroup) {
                    total += item.price * item.number
                }
                return total
            },

            handleCheckAll() {
                // 先判断是全选还是全不选,全选就把所有数据放进去,全不选,就把数组置为空
                if (this.checkAll) {
                    this.checkGroup = this.goodList
                } else {
                    this.checkGroup = []
                }
            },

            handelCheckOne() {
                // 通过判断多选框绑定的数组的长度是否与全部数据的goodList数组长度一致
                // 如果一致,说明用户全选了,否则说明用户没有全选!!
                if (this.checkGroup.length == this.goodList.length) {
                    this.checkAll = true
                } else {
                    this.checkAll = false
                }
            }
        }

    })
</script>
</html>

.
.
.
.
.
.

1.3 商品的数量带加减按钮

代码思路:
正常给商品添加数量前,应该先去数据库查一下库存,商品添加的数量不能大于库存的数量
不需要每点一次按钮,都去查一次数据库,而是打开该页面的时候,
就应该隐藏一个商品的库存还剩多少的标签,这样当添加数量大于库存的量时,就不给往上加了!!

同理商品的数量最少是1,如果数量是0,应该根据id号,将该条商品的信息从for循环的数组里面的
pop掉就行了

------------------------------
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"
          integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
</head>
<body>
<div class="app">
    <div class="container-fluid">
        <div class="row">
            <div class="col-md-6 col-md-offset-3">
                <h1>购物车案例</h1>

                <table class="table table-bordered">
                    <thead>
                    <tr>
                        <th>商品编号</th>
                        <th>商品名字</th>
                        <th>商品价格</th>
                        <th>商品数量</th>
                        <th>全选/全不选 <input type="checkbox" v-model="checkAll" @change="handleCheckAll"></th>
                    </tr>
                    </thead>
                    <tbody>
                    <tr v-for="item in goodList">
                        <th scope="row">{{item.id}}</th>
                        <td>{{item.name}}</td>
                        <td>{{item.price}}</td>

                        <td>
                            <button class="btn btn-success" @click="handleDown(item)">-</button>
                            {{item.number}}
                            <button class="btn btn-warning" @click="item.number++">+</button>
                        </td>

                        <td><input type="checkbox" v-model="checkGroup" :value="item" @change="handelCheckOne"></td>
                    </tr>
                    </tbody>
                </table>
                <hr>
                <p>选中商品:{{checkGroup}}---{{checkAll}}</p>
                <p>总价格:{{getPrice()}}</p>
            </div>

        </div>

    </div>


</div>
</body>
<script>
    var vm = new Vue({
        el: '.app',
        data: {
            goodList: [
                {id: '1', name: '钢笔', price: 20.1, number: 2},
                {id: '2', name: '饼干', price: 4, number: 1},
                {id: '3', name: '辣条', price: 5, number: 5},
            ],
            checkGroup: [],
            checkAll: false,
        },
        methods: {
            getPrice() {
                // 通过checkGroup里面的对象,计算出总价格
                var total = 0
                for (item of this.checkGroup) {
                    total += item.price * item.number
                }
                return total
            },

            handleCheckAll() {
                // 先判断是全选还是全不选,全选就把所有数据放进去,全不选,就把数组置为空
                if (this.checkAll) {
                    this.checkGroup = this.goodList
                } else {
                    this.checkGroup = []
                }
            },

            handelCheckOne() {
                // 通过判断多选框绑定的数组的长度是否与全部数据的goodList数组长度一致
                // 如果一致,说明用户全选了,否则说明用户没有全选!!
                if (this.checkGroup.length == this.goodList.length) {
                    this.checkAll = true
                } else {
                    this.checkAll = false
                }
            },

            // 注意这里要把字典对象当参数传到函数里面来,不然不知道要减哪一个!!
            handleDown(item) {
                if(item.number>1){
                  item.number--
                }else{alert('太少了,不够减了')}
            }
        }
    })
</script>
</html>

.
.
.
.
.

1.4 可变类型与不可变类型

# python
	-不可变类型:数字,字符串,元组
	-可变类型:列表,字典,集合
	-python中没有值类型和引用类型的叫法
	【因为python一切皆对象,对象都是地址都是引用】

	-可变类型当参数传到函数中,在函数中修改会影响原来的
	-不可变类型当参数传到函数中,在函数中修改不会影响原来的
---------------------------------------------
换句话说:如果是不可变数据类型,当参数传到函数里面后,在函数里面修改该参数,
外部的不会受影响,

但如果是可变数据类型,当参数传到函数里面后,在函数里面修改该参数,会影响外部的
---------------------------------------------
# python 函数参数传递是值传递还是引用传递? 这个问题不应该有


# js 传入了item 对象,在函数中修改,会影响了原来的
	-js中 数组与对象都是引用类型
---------------------------------------------
在其他语言中叫值类型与引用类型
引用类型的数据,传到函数里面,数据修改就会影响原来的
值类型的数据,传到函数里面,数据修改不会影响原来的
---------------------------------------------
# python 一切皆对象,对象皆引用

# 没有值与引用的说法,所以才有了可变与不可变类型

# python 中所有的变量名绑定的都是内存地址,内存地址绑定最终的值!!!
---------------------------------------------
# 在其他语言中,值类型的数据是变量名直接绑定值,
# 引用类型的数据是变量名先绑定内存地址,内存地址再绑定最终的值!!

.
.
.
.
.

2 v-model进阶

lazy:等待input框的数据绑定时,失去焦点之后再变化
number:数字开头,只保留数字,后面的字母不保留;字母开头,都保留
trim:去除首位的空格

.
.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>
</head>
<body>
<div class="app">
    <h1>lazy</h1>
    <input type="text" v-model.lazy="myText">---->{{myText}}
    <h1>number</h1>
    <input type="text" v-model.number="myNumber">---->{{myNumber}}
    <h1>trim</h1>
    <input type="text" v-model.trim="myTrim">---->{{myTrim}}

</div>
</body>
<script>
    var vm = new Vue({
        el: '.app',
        data: {
            myText: '',
            myNumber: '',
            myTrim: ''
        },

    })
</script>
</html>

.
.
.
.
.
.

3 用ajax与后端交互

# 同源策略:是指协议,域名,端口都要相同,其中有一个不同都会产生跨域;这是浏览器最基本的安全策略!!

# 跨域:指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对javascript 施加的安全限制。

# 跨越问题
浏览器的原因,只要向不是地址栏中的 [域:地址和端口]发送请求,拿的数据,
会被浏览器给拦截了(后端执行了,只是数据回来的时候,浏览器发现并拦截了)

-------------------------------------------
# 处理跨域问题
跨源资源共享标准新增了一组HTTP首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源

后端代码处理----只需要在响应头中加入允许即可!!!

.
.

3.1 用jqery发送ajax请求

# flask文件,模拟django创一个项目
# 用flask解决跨域问题

from flask import Flask, jsonify, make_response

app = Flask(__name__)


@app.route('/')
def index():
    print('执行了')
    res = make_response(jsonify({'name': '彭于晏', 'age': 19, 'gender': 'male'}))
    res.headers['Access-Control-Allow-Origin'] = '*'
    # 把这个key和value加入到响应头,就没有跨域问题了
    return res


if __name__ == '__main__':
    app.run()

.
.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script>

    <link rel="stylesheet" href="./js/bootstrap.min.css">


</head>
<body>
<div class="app">
    <h1>点击加载用户信息</h1>
    <button @click="handleClick" class="btn btn-danger">点我</button>
    <div v-if="userInfo.name">
        <p>用户名:{{userInfo.name}}</p>
        <p>年龄:{{userInfo.age}}</p>
        <p>性别:{{userInfo.gender}}</p>
    </div>


</div>
</body>
<script>

    var vm = new Vue({
        el: '.app',
        data: {
            userInfo: {}
        },
        methods: {
            handleClick() {
                // jquery 发生ajax请求

                let _this = this
                $.ajax({
                    url: 'http://127.0.0.1:5000',
                    type: 'get',
                    success: function (data111) {
                        console.log(data111)
                        _this.userInfo = data111 }

                    // 如果用箭头函数,就没有this指向问题了
                    // success: (data111) => {
                    //     this.userInfo = data111 }
                })
            }
        }
    })

</script>
</html>
------------------------------------
或者这样写
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="js/vue.js"></script>

    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js">

    </script><link rel="stylesheet" href="./bootstrap-3.4.1-dist/css/bootstrap.min.css">
</head>
<body>
    <div class="app">
        <h1>后端交互测试</h1>
        <button @click="handleClick" class="btn btn-success">点击展示信息</button>
        <br>
        <div v-if="age!=0">
            <p>姓名:{{ name }}</p>
            <p>年龄:{{ age }}</p>
            <p>姓名:{{ gender }}</p>
        </div>

        <div v-else>
            暂无信息
        </div>
    </div>
</body>
<script>
    var vm = new Vue({
        el:'.app',
        data:{'name':'',age:0,gender:'未知'},
        methods:{
            handleClick(){
                $.ajax({
                    url:'http://127.0.0.1:5000',
                    type:'get',
                    success:data111=>{
                        console.log(data111)
                        this.name=data.name
                        this.age=data.age
                        this.gender=data.gender
                    }
                })
            }
        }
    })
</script>
</html>

.
.
.

3.1.2 用django与drf解决跨域问题

from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('collection/', views.CollectionView.as_view()),
    path('collection888/', views.CollectionView888.as_view()),
]
----------------------
# django解决跨域问题
class CollectionView888(APIView):
    def get(self, request):
        print(request.query_params)
        back_dict = {'name': 'ikun', 'age': 20, 'gender': '男'}

        obj = JsonResponse(back_dict)   # 用django原生的JsonResponse返回字典
        obj['Access-Control-Allow-Origin'] = '*'
        # 需要通过对象点的方式往响应头里面放东西,解决跨域问题

        return obj
        # 把这个key和value加入到响应头,就没有跨域问题了
------------------------
# html代码和上面的一样的
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script>

    <link rel="stylesheet" href="./js/bootstrap.min.css">


</head>
<body>
<div class="app">
    <h1>点击加载用户信息</h1>
    <button @click="handleClick" class="btn btn-danger">点我</button>
    <div v-if="userInfo.name">
        <p>用户名:{{userInfo.name}}</p>
        <p>年龄:{{userInfo.age}}</p>
        <p>性别:{{userInfo.gender}}</p>
    </div>


</div>
</body>
<script>

    var vm = new Vue({
        el: '.app',
        data: {
            userInfo: {}
        },
        methods: {
            handleClick() {
                // jquery  发送ajax请求
                let _this = this
                $.ajax({
                    url: 'http://127.0.0.1:8077/collection888/',
                    type: 'get',
                    success: function (data111) {
                        _this.userInfo = data111 }

                })
            }
        }
    })

</script>
</html>

.
.

# drf解决跨域问题

class CollectionView(APIView):
    def get(self, request):
        print(request.query_params)
        back_dict = {'name': 'ikun', 'age': 20, 'gender': '男'}

        return Response(back_dict, headers={'Access-Control-Allow-Origin': '*'})
        # 把这个key和value加入到响应头,就没有跨域问题了

.
.
.
.
.

3.2 用fetch发送ajax请求

# fetch 提供了一个 JavaScript 接口,用于访问和操纵 HTTP 管道的一些具体部分,
# 例如请求和响应

-新的发送ajax 接口
-用起来比较方便
-支持promise写法(最新的异步写法)
-解决了原生的XMLHttpRequest兼容性的问题,但也不是所有浏览器都支持

-主流现在是用axios[第三方]发送ajax请求!!!
---------------------------------------------
---------------------------------------------
# XMLHttpRequest: 原生js提供的发生ajax的接口
-比较老,不同浏览器需要做一些兼容性的处理,写起来比较麻烦
-所以jquery基于它做了封装,屏蔽了浏览器的区分,只需要$.ajax({}) 就可以发生ajax请求

--------------------------------------------

# axios发送ajax请求,
--------------------------------------------

.
.

# fetch发送ajax请求
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script>

    <link rel="stylesheet" href="./js/bootstrap.min.css">

    <!--         <link rel="stylesheet" href="./bootstrap-3.4.1-dist/css/bootstrap.min.css">-->


</head>
<body>
<div class="app">
    <h1>点击加载用户信息</h1>
    <button @click="handleClick" class="btn btn-danger">点我</button>
    <div v-if="userInfo.name">
        <p>用户名:{{userInfo.name}}</p>
        <p>年龄:{{userInfo.age}}</p>
        <p>性别:{{userInfo.gender}}</p>
    </div>


</div>
</body>
<script>

    var vm = new Vue({
        el: '.app',
        data: {
            userInfo: {}
        },
        methods: {
            handleClick() {
  // fetch发送ajax请求,后端返回的json格式的字符串被行参response先转成字典对象
                fetch('http://127.0.0.1:5000').then(response => response.json()).then(res => {
                    this.userInfo = res
                })
            }
        }
    })

</script>
</html>

.
.
.
.
.

3.3 用 axios发送ajax请求


# 以后在vue上,基本都用它,第三方的模块
# Axios 是一个基于promise的 HTTP库,还是基于XMLHttpRequest封装的
----------------------------
#  cdn引入
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

# 或者下载下来本地引入

----------------------------
# Axios官网文档      http://www.axios-js.com/zh-cn/docs/

.
.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>
    <script src="./js/axios.js"></script>

</head>
<body>
<div class="app">
    <h1>点击加载用户信息</h1>
    <button @click="handleClick">点我</button>
    <div v-if="age!=0">
        <p>用户名:{{name}}</p>
        <p>年龄:{{age}}</p>
        <p>性别:{{gender}}</p>
    </div>
    <div v-else>
        无用户信息
    </div>


</div>
</body>
<script>
    var vm = new Vue({
        el: '.app',
        data: {
            name: '',
            age: 0,
            gender: '未知'
        },
        methods: {
            handleClick() {
                //1  axios
                axios.get('http://127.0.0.1:5000/').then(res => {
            // res是对象,有点特殊,真正的数据(放在请求体里的内容),在res.data中
                    console.log(res)
                    this.name = res.data.data.name
                    this.age = res.data.data.age
                    this.gender = res.data.data.gender


                })


            }
        }

    })
</script>
</html>

Axios 发送ajax请求 then 里面就是个异步回调函数加箭头函数的结合体
res是行参接收的是类似于request对象,我们想要的数据(响应体的内容),在res.data中
image
.
假如后端是这样返回数据的:
res = make_response(jsonify({'code': 100, 'msg': '成功', 'data': {'name': 'lqz', 'age': 19, 'gender': 'male'}}))
那么就要从res.data.data 里面拿相应体的内容了
image
image
.
.
.
.
.
卖座电影网爬取点数据,放到我们的项目里面去
image
.
image
.
image
.
image
.

3.4 小电影

https://m.maizuo.com/v5/#/films/nowPlaying   卖座电影网爬取点数据

想要实现的功能是,向后端发送请求,后端把数据读出来,返回给前端
-----------------------
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>

    <link rel="stylesheet" href="./js/bootstrap.min.css">

    <script src="./js/axios.js"></script>


</head>
<body>
<div class="app">
    <h1>热映电影</h1>
    <button @click="handleClick" class="btn btn-danger">点我</button>
    <div>
        <div v-for="item in dataList">
            <h2>电影名字:{{item.name}}</h2>

            <h2>电影演员:</h2>
            <span v-for="name22 in item.actors">
                        {{name22.name}}
                </span>

            <h3>电影导演:{{item.director}}</h3>
            <h3>标签:{{item.category}}</h3>
            <div>简介:{{item.synopsis}}</div>
            <img :src="item.poster" alt="" height="400px" width="400px">
            <hr>
            <hr>
        </div>
    </div>


</div>
</body>
<script>

    var vm = new Vue({
        el: '.app',
        data: {
            dataList: [],
        },
        methods: {
            handleClick() {
                // Axios 发送ajax请求
                axios.get('http://127.0.0.1:8077/collection/').then(res => {
                    // res是行参接收的是类似于request对象,我们想要的数据(响应体的内容),在res.data中
                    // res.data拿响应体内容,在点data拿响应体里面data键对应的值,同理继续点films键,拿里面的值!!
                    // 电影的信息都在films键对应的数组里面!!!
                    this.dataList = res.data.data.films
                })
            }
        }
    })

</script>
</html>

.
.

# 后端代码

from rest_framework.response import Response
from rest_framework.views import APIView
import json


class CollectionView(APIView):
    def get(self, request):
        with open('app01/film.json', 'r', encoding='utf-8', )as f:
            back_dict = json.load(f)
        return Response(back_dict, headers={'Access-Control-Allow-Origin': '*'})

image
.
.
.
.
.

4 vue生命周期

image

---------------------------------------------

# 从vue实例创建开始,到实例被销毁,总共经历了8个生命周期钩子[只要写了就会执行]函数
	-钩子:反序列化验证---》钩子函数
	-学名[专门名字]---》面向切面编程(AOP)
	-OOP:面向对象编程

----------------------------------------------
----------------------------------------------

# 8个生命周期钩子函数

beforeCreate	  创建Vue实例(生成Vue对象)之前调用
created 	  创建Vue实例(生成Vue对象)成功后调用(可以在此处发送异步请求后端数据)
-------------------------------------

beforeMount 	  渲染DOM(挂载管理的标签)之前调用
mounted	          渲染DOM(挂载管理的标签)之后调用
-------------------------------------

beforeUpdate 	重新渲染之前调用(数据更新等操作时,控制DOM重新渲染)
updated	        重新渲染(重新挂载管理的标签)完成之后调用

# 当Vue对象里面的data里面的变量数据再发生变化的时候,会再次执行beforeUpdate与updated钩子函数

------------------------------------

beforeDestroy	  销毁Vue对象(关了页面才会销毁Vue对象)之前调用
destroyed   	  销毁Vue对象之后调用

-----------------------------------
# 一般不会将加载页面的ajax请求的代码放在mounted钩子函数里面,因为执行到mounted钩子函数时,
# 页面已经挂载了,el对应的标签及data里面对应的数据都已经在页面上渲染好了,
# ajax从后端拿到数据后,如果改了data里面的变量对应的值,就会导致页面的局部用到数据的
# 地方又重新刷新了一遍,就会耗费额外的资源,所以一般加载页面的ajax请求放在created钩子函数里面

--------------------------------------------
# 重点:

	-1  用的最多的,在created钩子函数里面,发送ajax请求---有的人放在mounted中发送ajax请求,加载数据,重新加载页面

	-2  beforeDestroy钩子函数用的比较多,比如应用场景:
		-组件一创建,created中启动一个定时器
		-组件被销毁,beforeDestroy销毁定时器

---------------------------------------------

image
.
页面发生变化就会自动执行,beforeUpdate与updated钩子函数
image
.
.
.
.

利用created钩子函数的小案例

# 利用created钩子函数,就可以直接取消掉点击按钮,当Vue对象生成后,
# el管理的标签被挂载前,执行created钩子函数时,运行handleClick函数,发生ajax请求
# 获取后端数据

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>

    <link rel="stylesheet" href="./js/bootstrap.min.css">

    <script src="./js/axios.js"></script>


</head>
<body>
<div class="app">
    <h1>热映电影</h1>

    <div>
        <div v-for="item in dataList">
            <h2>电影名字:{{item.name}}</h2>

            <h2>电影演员:</h2>
            <span v-for="name22 in item.actors">
                        {{name22.name}}
                </span>

            <h3>电影导演:{{item.director}}</h3>
            <h3>标签:{{item.category}}</h3>
            <div>简介:{{item.synopsis}}</div>
            <img :src="item.poster" alt="" height="400px" width="400px">
            <hr>
            <hr>
        </div>
    </div>


</div>
</body>
<script>

    var vm = new Vue({
        el: '.app',
        data: {
            dataList: [],
        },
        methods: {
            handleClick() {
                // Axios 发送ajax请求
                axios.get('http://127.0.0.1:8077/collection/').then(res => {
                    this.dataList = res.data.data.films
                })
            }
        },

        // created:function(){}  简写为
        created() {
            this.handleClick() }
    })

</script>
</html>

.
.

利用子组件演示生命周期钩子函数的执行顺序 的小案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>

    <link rel="stylesheet" href="./js/bootstrap.min.css">

    <script src="./js/axios.js"></script>


</head>
<body>
<div class="app">

    <h1>组件的生命周期钩子演示</h1>

    <hr>
    <button @click="handleClick">点击显示组件,再点隐藏组件</button>

    <hr>
    <!--注意子组件属性上所用的变量show可不是子组件里面的变量,而是根组件vm里面的变量,因为整个class="app"的div标签都是被vm所管理-->
    <child v-if="show"></child>


</div>
</body>
<script>

    // 如何创建一个子组件(自定义标签),在根组件vm中使用
    Vue.component('child', {
        template: `
          <div>
          <button>后退</button>
          <span style="font-size: 40px">组件首页{{name}}</span>
          <button @click="handleChange">改名字</button>
          </div>`,
        // 里面写html内容,必须包在一个标签中,并且标签外面要用模板字符串的引号引起来

        data() {
            // 组件里面的data必须是方法,返回对象,在对象里面定义一些变量
            // 组件可以用多次,如果组件里面的data也像vm里面的data一样对应的是一个字典,每一个键对应一个值,是引用类型
            // 组件被多次使用的过程中,一旦改了键对应的值,所有用组件的地方都会收到影响!!
            // 但如果写成函数return 出去的这种形式,组件被使用多次,每次return里面的变量的改变,都不会影响其他用该组件的地方
            // 这样每次使用组件的时候,该组件都可以有自己的数据
            return {name: '刘清政'}
        },

        methods: {
            handleChange(){
                this.name = 'Handsome Liu'
            }
        },
        // 在子组件里面使用8个钩子函数
        beforeCreate() {
            console.group('当前状态:beforeCreate')
            console.log('当前el状态:', this.$el)
            console.log('当前data状态:', this.$data)
            console.log('当前name状态:', this.name)
        },
        created() {
            console.group('当前状态:created')
            console.log('当前el状态:', this.$el)
            console.log('当前data状态:', this.$data)
            console.log('当前name状态:', this.name)
        },

        beforeMount() {
            console.group('当前状态:beforeMount')
            console.log('当前el状态:', this.$el)
            console.log('当前data状态:', this.$data)
            console.log('当前name状态:', this.name)
        },
        mounted() {
            console.group('当前状态:mounted')
            console.log('当前el状态:', this.$el)
            console.log('当前data状态:', this.$data)
            console.log('当前name状态:', this.name)
        },
        beforeUpdate() {
            console.group('当前状态:beforeUpdate')
            console.log('当前el状态:', this.$el)
            console.log('当前data状态:', this.$data)
            console.log('当前name状态:', this.name)
        },
        updated() {
            console.group('当前状态:updated')
            console.log('当前el状态:', this.$el)
            console.log('当前data状态:', this.$data)
            console.log('当前name状态:', this.name)
        },

        // 如果写在Vue实例上,下面两个钩子函数的执行是看不到的
        // 使用组件演示8个生命周期钩子函数,利用v-if,来实现Vue对象的删除效果!!!
        beforeDestroy() {
            console.group('当前状态:beforeDestroy')
            console.log('当前el状态:', this.$el)
            console.log('当前data状态:', this.$data)
            console.log('当前name状态:', this.name)
        },
        destroyed() {
            console.group('当前状态:destroyed')
            console.log('当前el状态:', this.$el)
            console.log('当前data状态:', this.$data)
            console.log('当前name状态:', this.name)
        },

    })


    // 根组件
    var vm = new Vue({
        el: '.app',
        data: {
            show: false
        },
        methods: {
            handleClick() {
                this.show = !this.show }
        },

    })

</script>
</html>

首先一开始页面数据没有改变得时候,正常走了子组件里面的4个钩子函数
image
.
当我们通过子组件里面点击事件,修改了子组件里面变量名对应的值,对应的局部页面发生变化,
局部页面渲染前触发beforeUpdate,渲染后触发updated 钩子函数的执行
image
.
当我们点击根组件里面标签,通过点击事件,来让子组件的v-if的值等于false,来使子组件删除,
这样就触发子组件里面的beforeDestroy 与 destroyed 钩子函数的执行
image
.
.
.
.

beforeDestroy钩子函数的应用场景

------------------------------------------

beforeDestroy钩子函数用的比较多,比如应用场景:
	-组件一创建,created中启动一个定时器
	-组件被销毁,beforeDestroy销毁定时器
------------------------------------------
比如打开一些网站后,网站边上有个在线客服的聊天框,其实这玩意就是一个组件,
你打开聊天框后,定时器就启动了,你输入一些信息,客服会自动回你一些信息,原因就是

其实你输入信息点击发送,其实就是朝后端发送ajax请求,注意客服给你发的信息是不能主动
发给你的,客服给你发的消息是发送到了服务器上了,那我怎么收到客服的消息的了

其实是在后台隐藏了一个不停的朝后端查询对方有没有回消息的操作,每隔几秒钟就会查询一次,如果有消息就会返回。
因为http协议的特性决定了,必须是基于请求响应,是不能直接收到消息的!!!
能主动推消息的协议是websocket协议,在线聊天用websocket协议最好,
但用http协议也能解决在线聊天

就是起一个定时的轮询,过一会儿往后端发送一个请求,过一会儿往后端发送一个请求,如果有消息就带会来,没有就拉倒,

所以聊天框一打开(组件一创建出来)的时候,就起一个定时器,不停的向后端发请求,这样只要后端有消息了,就能拿回来了,
------------------------------------------
在子组件里面created钩子函数里面,设置一个循环定时任务,这样每隔3秒钟,就会有打印一个'hello world'的效果了

        data() {
            // 子组件里面的data必须是方法,返回对象,在对象里面定义一些变量
            return {name: '刘清政', t: null}
        },

        methods: {
            handleChange() {
                this.name = 'Handsome Liu' }
        },

        created() {
            // 启动定时器,每个3秒向后端发送请求,模拟ajax请求回调拿到的后端消息
            this.t = setInterval(()=>{
                console.log('hello world')
            },3000)
        },


在子组件里面,beforeDestroy钩子函数里面,销毁循环定时器,
这样当子组件销毁了,循环定时器就也销毁了!!!
beforeDestroy() {
            // 销毁循环定时器
            clearInterval(this.t)
            this.t = null
        },

------------------------------------------
let t = setTimeout(函数名或者写个箭头函数, 时间)
# 开启一个定时任务,对应毫秒后执行函数!!

let s = setInterval(函数名或者写个箭头函数, 3000)
# 开启一个循环定时任务 每隔3000毫秒执行一次函数

clearTimeout(t)  # 取消定时任务

------------------------------------------
------------------------------------------

# 实现实时聊天效果可以使用的方法(在线聊天室)
	1 基于http协议
		-轮询:循环定时器+ajax   http
		-长轮询:定时器+ajax  http

	2 基于websocket协议:服务端主动发消息给客户端


	django中如何继承websocket,见链接https://zhuanlan.zhihu.com/p/371500343

# web版的微信就是基于http协议实现在线聊天,打开聊天框后,就会开启循环定时任务,不停的往后端的服务器发生请求,如果有,就拿回对方刚发的消息

------------------------------------------
http底层是基于tcp协议,websocket底层也是基于tcp协议

http协议与websocket协议,属于应用层的协议

tcp与udp协议属于传输层的协议

------------------------------------------

.
.
.
.

js里面的promise风格简述

 axios.get('http://127.0.0.1:8077/collection/').then(res => {
      this.dataList1 = res.data.data.films
          axios.get('http://127.0.0.1:8088/collection/').then(res => {
              this.dataList2 = res.data.data.films
                  axios.get('http://127.0.0.1:8099/collection/').then(res => {
                      this.dataList3 = res.data.data.films
                                                                              })
                                                                      })
                                                                })

--------------------------------
# 假如3个ajax请求是并列串行的,分别向不同的地址去请求数据,没有问题
# 但是如果套在一起,第一个ajax请求代码走完才能走第二个ajax,第二个走完走第三个
# 代码执行上没有问题,但是可以用promise风格去优化一下
# promise风格具体怎么用,有空再学!

.
.
.
.
.

5 vue组件

# 组件化开发的好处:重用代码
# 组件分类
	-全局子组件:在任意组件中都可以使用
	-局部子组件:定义在某个组件中,只能在当前定义的组件中使用
-------------------------------------------
全局子组件示例:
关键字:   Vue.component('全局子组件名',{})


Vue.component('全局子组件名', {
        template: `
          <div>
          <span >子组件1 首页{{ name }}</span>
          <button @click="handleChange">改名字</button>
          </div>`,

        data() {
            return {name: '刘清政',} },
        methods: {
            handleChange() {
                this.name = 'Handsome Liu'
            }
        },
    })

--------------------------------------------
局部子组件,必须要定义在其他的组件内  示例:
可以定义在根组件里面,也可以定义在其他的全局子组件里面
在组件内部写关键字components:{'局部组件名':{就和写全局子组件的语法一样了}}

    var vm = new Vue({
        el: '.app',
        data: {},
        methods: {},
        components: {
            // 局部组件可以写多个
            'lqz': {
                template: `
                    <div>
                    <h1>局部子组件1----局部组件中的变量对应的值:  {{age}}</h1>
                    </div>
                `,
                data() {
                    return {
                        age:19
                    }
                },
                method: {},
            },
            'jason': {
                template: `
                    <div>
                    <h1>局部子组件2----局部组件中的变量对应的值:  {{gender}}</h1>
                    </div>
                `,
                data() {
                    return {
                        gender:'男'
                    }
                },
            }
        }
    })

--------------------------------------------

image
.
.
.
.

定义全局子组件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>

    <link rel="stylesheet" href="./js/bootstrap.min.css">

    <script src="./js/axios.js"></script>


</head>
<body>
<div class="app">

    <h1>组件</h1>
    <hr>
    <child></child>

    <child2></child2>

</div>
</body>
<script>

    //全局子组件(自定义标签),在任意组件中都可以使用
    Vue.component('child', {
        template: `
          <div>
          <button>后退</button>
          <span style="font-size: 40px">子组件1 首页{{ name }}</span>
          <button @click="handleChange">改名字</button>
          <child2></child2>
          <hr>
          </div>`,


        data() {
            return {name: '刘清政',}
        },

        methods: {
            handleChange() {
                this.name = 'Handsome Liu'
            }
        },

    })


    Vue.component('child2', {
        template: `
          <div>
          <button>子组件2,后退</button>
          </div>`,
    })


    // 根组件
    var vm = new Vue({
        el: '.app',
        data: {},
        methods: {},
    })

</script>
</html>

可以看出全局子组件,可以放在根组件里面,也可以放在子组件里面!!!
image
.
.
.
.

定义局部组件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>

    <link rel="stylesheet" href="./js/bootstrap.min.css">

    <script src="./js/axios.js"></script>


</head>
<body>
<div class="app">
    <h1>组件</h1>
    <hr>
    <child></child>
    <hr>
    <lqz></lqz>
    <hr>
    <jason></jason>

</div>
</body>
<script>
    //全局子组件(自定义标签),在任意组件中都可以使用
    Vue.component('child', {
        template: `
          <div>
          <button>后退</button>
          <span style="font-size: 40px">全局子组件1 首页{{ name }}</span>
          <button @click="handleChange">改名字</button>
          <jason></jason>
          <lqz></lqz>
          <hr>
          </div>`,
        // 局部组件只能在定义的组件中使用
        data() {
            return {name: '刘清政',}
        },
        methods: {
            handleChange() {
                this.name = 'Handsome Liu'
            }
        },
    })

    // 根组件
    var vm = new Vue({
        el: '.app',
        data: {},
        methods: {},
        components: {
            // 局部组件可以写多个
            'lqz': {
                template: `
                    <div>
                    <h1>局部子组件1----局部组件中的变量对应的值:  {{age}}</h1>
                    </div>
                `,
                data() {
                    return {
                        age:19
                    }
                },
                method: {},
            },
            'jason': {
                template: `
                    <div>
                    <h1>局部子组件2----局部组件中的变量对应的值:  {{gender}}</h1>
                    </div>
                `,
                data() {
                    return {
                        gender:'男'
                    }
                },
            }
        }
    })
</script>
</html>

可以看出局部子组件,只能用在定义的组件里面,不能用在其他的组件里面!!!!
用在其他的组件里面,该局部子组件也显示不出来!!!
image
image
.
.
还可以用一个变量名先接收一下局部组件的代码,这样在在组件内部,定义子组件的时候
局部组件的名字就可以直接对变量名了!!!components: { 'lqz': foo,}
还有更简单的写法,就是直接components: {foo}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>

    <link rel="stylesheet" href="./js/bootstrap.min.css">

    <script src="./js/axios.js"></script>


</head>
<body>
<div class="app">
    <h1>组件</h1>
    <hr>
    <child></child>
    <hr>
    <lqz></lqz>
    <!-- 如果局部组件里面直接写成foo 那此处的局部组件名就需要改成  <foo></foo>    -->
    <hr>


</div>
</body>
<script>
    //全局子组件(自定义标签),在任意组件中都可以使用
    Vue.component('child', {
        template: `
          <div>
          <button>后退</button>
          <span style="font-size: 40px">全局子组件1 首页{{ name }}</span>
          <button @click="handleChange">改名字</button>
          <hr>
          </div>`,

        // 局部组件只能在定义的组件中使用
        data() {
            return {name: '刘清政',}
        },
        methods: {
            handleChange() {
                this.name = 'Handsome Liu'
            }
        },
    })


    var foo = {
        template: `
          <div>
          <h1>局部子组件1----局部组件中的变量对应的值:  {{ age }}</h1>
          </div>
        `,
        data() {
            return {age: 19}
        },
        method: {},
    }

    // 根组件
    var vm = new Vue({
        el: '.app',
        data: {},
        methods: {},
        components: {
            // 局部组件可以写多个
            'lqz': foo,
            // foo   如果直接写foo,那么原来写局部组件名'lqz'的地方就改成foo就行了!!
        }
    })
</script>
</html>

.
.

补充

# 1 之前前后端交互,使用xml格式
# 2 后来json 格式出现,前后端交互,主流都是json格式
	-可能觉得不安全
	-前后端加密解密方式

# 4 目前有些比json更安全,高效,节约空间的编码格式,后期可能前后端交互使用某种

.
.
.
.

作业

drf如何往响应头里面写东西
django如何往响应头里面写东西
# 购物车带删除,有库存校验
# 小电影案例---》后端用django,解决跨域问题
# 整理一下vue生命周期

---------------------------------
# 对象当参数传递,在函数中修改对象,会不会影响原来的
# 深浅拷贝
# 搜索什么是跨域
posted @   tengyifan  阅读(78)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示