购物车案例,v-model进阶,与后端交互,vue生命周期,vue组件

购物车案例

1 基本购物车

js的变量只要发生变化,html页面中使用该变量的地方,就会重新渲染
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
<!--    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>-->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.10"></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 id="app">
    <div class="container-fluid " >
        <div class="row">
            <div class="col-md-6 col-md-offset-3">
                <h3 class="text-center">购物车案例</h3>
                <table class="table table-hover">
                  <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>总价格是:{{getPrice()}}</p>
                <hr>
                <p>选中了:{{checkGroup}}</p>
            </div>
        </div>
    </div>

</div>

</body>
<script>
    var vm = new Vue({
        el:'#app',
        data:{
            goodList : [
                {id:'1',name:'辣条',price:5,number:9},
                {id:'2',name:'烤肠',price:11.1,number:8},
                {id:'3',name:'麻辣烫',price:20.2,number:5},
                {id:'4',name:'关东煮',price:4,number:4},
                {id:'5',name:'烤冷面',price:8.8,number:3},
                {id:'6',name:'臭豆腐',price:6.6,number:9},
            ],
            checkGroup :[]
        },
        methods:{
            getPrice(){
                //通过checkGroup中的对象算出总价格
                var total = 0
                for(item of this.checkGroup){
                    total += this.price * this.number
                }
                return total

            }
        }
    })
</script>
</html>

image

2.购物车全选与全不选

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!--    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>-->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.10"></script>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"
          integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
    <!--    <style>-->
    <!--    #app{-->
    <!--       background-image: url("1.jpg");-->
    <!--       background-repeat: no-repeat; cursor: hand; width: 800px; height: 800px;-->
    <!--    }-->
    <!--  </style>-->
</head>
<body>
<div id="app">
    <div class="container-fluid ">
        <div class="row">
            <div class="col-md-6 col-md-offset-3">
                <h3 class="text-center">购物车案例</h3>
                <table class="table table-hover">
                    <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="handleCheckOne"></td>
                    </tr>
                    </tbody>
                </table>
                <hr>
                <p>总价格是:{{getPrice()}}</p>
                <hr>
                <p>选中了:{{checkGroup}}</p>
            </div>
        </div>
    </div>

</div>

</body>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            goodList: [
                {id: '1', name: '辣条', price: 5, number: 9},
                {id: '2', name: '烤肠', price: 11.1, number: 8},
                {id: '3', name: '麻辣烫', price: 20.2, number: 5},
                {id: '4', name: '关东煮', price: 4, number: 4},
                {id: '5', name: '烤冷面', price: 8.8, number: 3},
                {id: '6', name: '臭豆腐', price: 6.6, number: 9},
            ],
            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 = []
                }
            },
            handleCheckOne() {
                if (this.checkGroup.length == this.goodList.length) {
                    this.checkAll = true
                } else {
                    this.checkAll = false
                }
            }
        }
    })
</script>
</html>

image

image

3.购物车商品数量加减操作

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!--    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>-->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.10"></script>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"
          integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
    <!--    <style>-->
    <!--    #app{-->
    <!--       background-image: url("1.jpg");-->
    <!--       background-repeat: no-repeat; cursor: hand; width: 800px; height: 800px;-->
    <!--    }-->
    <!--  </style>-->
</head>
<body>
<div id="app">
    <div class="container-fluid ">
        <div class="row">
            <div class="col-md-6 col-md-offset-3">
                <h3 class="text-center">购物车案例</h3>
                <table class="table table-hover">
                    <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 @click="handleDown(item)"> - </button>
                            {{item.number}}
                            <button @click="item.number++"> + </button>
                        </td>
                        <td><input type="checkbox" v-model="checkGroup" :value="item" @change="handleCheckOne"></td>
                    </tr>
                    </tbody>
                </table>
                <hr>
                <p>总价格是:{{getPrice()}}</p>
                <hr>
                <p>选中了:{{checkGroup}}</p>
            </div>
        </div>
    </div>

</div>

</body>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            goodList: [
                {id: '1', name: '辣条', price: 5, number: 9},
                {id: '2', name: '烤肠', price: 11.1, number: 8},
                {id: '3', name: '麻辣烫', price: 20.2, number: 5},
                {id: '4', name: '关东煮', price: 4, number: 4},
                {id: '5', name: '烤冷面', price: 8.8, number: 3},
                {id: '6', name: '臭豆腐', price: 6.6, number: 9},
            ],
            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 = []
                }
            },
            handleCheckOne() {
                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>

image

4.额外的小知识点

在Python中:
	不可变类型:数字,字符串,元组
    可变类型:列表,字典,集合
    --可变类型当参数传到函数中,在函数中修改会影响原来的函数
    --不可变类型当参数传到函数中,在函数中修改不会影响原来的函数

# 面试题:函数参数传递是值传递还是引用传递?
	# 在Python中没有值类型和引用类型的叫法----->因为Python中一切皆对象,对象都是地址引用的,函数参数传递是值传递,引用传递是其他的算法的方法,Python中没有这两个

v-model进阶

lazy:等待input框的数据绑定时区焦点之后再变化
number:数字开头,只保留数字,后面的字母不保留;字母开头的,都保留
trim:去除首位的空格
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
<!--    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>-->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.10"></script>
</head>
<body>
<div id="app">
  <h3>v-model进阶</h3>
  <h4>lazy</h4>
  <input type="text" v-model.lazy="name1">----->{{name1}}
  <h4>number</h4>
  <input type="text" v-model.number="name2">----->{{name2}}
  <h4>number</h4>
  <input type="text" v-model.number="name4">----->{{name4}}
  <h4>trim</h4>
  <input type="text" v-model.trim="name3">----->{{name3}}
</div>
</body>
<script>
    var vm = new Vue({
        el:'#app',
        data:{
          name1:'',
          name2:'',
          name3:'',
          name4:'',
        }
    })
</script>
</html>

image

与后端交互

1.跨域问题

# 跨域问题
	跨域问题指的是不同站点之间,使用 ajax 无法相互调用的问题。跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。

img

上面的问题我们把它理顺一下可以变成:
	一个网页请求另外一个网页的资源被CORS策略给阻止了,原因XMLHttpRequest的请求不存在。主要原因----->>>CORS策略阻止了它!!
# 跨域的原因是什么?
	跨域只存在于浏览器之间,这是因为浏览器存在有一个同源策略。
# 同源策略	
    同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。所以xyz.com下的js脚本采用ajax读取abc.com里面的文件数据是会被拒绝的。同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。
	同源政策的目的:是为了保证用户信息的安全,防止恶意的网站窃取数据。
# 解决跨域
跨域的解决方案 JSONP,代理服务器和CORS。
通俗理解后端代码处理---->只需要在响应头中加入允许即可

2.jquery的Ajax与后端交互

html:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.10"></script>
</head>
<body>
<div id="app">
  <button @click="handleCheck">点击我向后端发送请求,加载用户信息</button>
  <div v-if="age!=0">
    <p>用户名:{{name}}</p>
    <p>年龄:{{age}}</p>
  </div>
  <div v-else>
    暂无用户信息
  </div>
</div>
</body>
<script>
    var vm = new Vue({
        el:'#app',
        data:{
          name:'',
          age:0
        },
       methods :{
          handleCheck(){
            // 发送ajax的请求
              $.ajax({
                  url:'http://127.0.0.1:5000',
                  type:'get',
                  success:data =>{
                      this.name = data.name
                      this.age = data.age
                  }
              })
          }
       }
    })
</script>
</html>
flask写的后端:
from flask import Flask, jsonify, make_response

app = Flask(__name__)
@app.route('/')
def index():
    res = make_response(jsonify({'name':'臭张昕','age':33}))
    # 把这个key和value加入到响应头,就没有跨域问题了
    res.headers['Access-Control-Allow-Origin'] = '*'
    return res

if __name__ == '__main__':
    app.run()
django写的后端:
URL:
from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('text/', views.index)
]
view:
from django.shortcuts import render,HttpResponse
from django.http import JsonResponse
# Create your views here.

def index(request):
    user_dict = {'name':'张昕','age':22}
    res = JsonResponse(user_dict)
    res.headers['Access-Control-Allow-Origin'] = '*'
    return res

image

2.fetch发送ajax请求

# fetch 提供了一个 JavaScript 接口,用于访问和操纵 HTTP 管道的一些具体部分,例如请求和响应
	-新的发送ajax 接口
    -用起来比较方便
    -支持promise写法[最新的异步写法]
    -解决了原生的XMLHttpRequest兼容性的问题
    -不是所有浏览器都支持
    -主流现在是用axios[第三方]发送请求
# XMLHttpRequest: 原生js提供的
	-比较老,不同浏览器需要做一些兼容性的处理,写起来比较麻烦
    -jq基于它做了封装
flask:
from flask import Flask, jsonify, make_response

app = Flask(__name__)
@app.route('/')
def index():
    res = make_response(jsonify({'code': 100, 'msg': '成功', 'data': {'name': '彭于晏', 'age': 19, 'gender': 'male'}}))
    # 把这个key和value加入到响应头,就没有跨域问题了
    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</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.10"></script>
  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
  <button @click="handleCheck">点击我向后端发送请求,加载用户信息</button>
  <div v-if="age!=0">
    <p>用户名:{{name}}</p>
    <p>年龄:{{age}}</p>
  </div>
  <div v-else>
    暂无用户信息
  </div>

</div>

</body>
<script>
    var vm = new Vue({
        el:'#app',
        data:{
          name:'',
          age:0

        },
       methods :{
          handleCheck(){
            // axios
              fetch.get('http://127.0.0.1:5000').then(response     =>response.json()).then(res => {
                // res是对象,真正的数据(想要body体内容),在res.data中
                      console.log(res)
                      this.name = res.data.data.name
                      this.age = res.data.data.age
              })
          }
       }
    })
</script>
</html>

3.axios发送ajax请求

# Axios 是一个基于 promise 的 HTTP 库,还是基于XMLHttpRequest封装的
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.10"></script>
  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
  <button @click="handleCheck">点击我向后端发送请求,加载用户信息</button>
  <div v-if="age!=0">
    <p>用户名:{{name}}</p>
    <p>年龄:{{age}}</p>
  </div>
  <div v-else>
    暂无用户信息
  </div>

</div>

</body>
<script>
    var vm = new Vue({
        el:'#app',
        data:{
          name:'',
          age:0

        },
       methods :{
          handleCheck(){
            // axios
              axios.get('http://127.0.0.1:5000').then(res =>{
                // res是对象,真正的数据(想要body体内容),在res.data中
                      console.log(res)
                      this.name = res.data.data.name
                      this.age = res.data.data.age
              })
          }
       }
    })
</script>
</html>

4 小电影案列

image

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.10"></script>
  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
  <h3>热映电影</h3>
  <ul>
    <li v-for="item in dataList">
           <h3>名字:{{item.name}}</h3>
            <h3>导演:{{item.director}}</h3>
            <h3>类型:{{item.category}}</h3>
            <p>简介:{{item.synopsis}}</p>
            <img :src="item.poster" alt="" height="300px" width="200px">
    </li>
  </ul>

</div>

</body>
<script>
    var vm = new Vue({
        el:'#app',
        data:{
          dataList:[]

        },
       methods :{
          handleCheck(){
            // axios
              axios.get('http://127.0.0.1:5000/film').then(res =>{
                this.dataList = res.data.data.films
              })
          }
       },
        created(){
            axios.get('http://127.0.0.1:5000/film').then(res =>{
                this.dataList = res.data.data.films
              })
        }
    })
</script>
</html>
import json

from flask import Flask, jsonify, make_response

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


@app.route('/film')
def film():
    with open('/film.json','r',encoding='utf-8') as f:
        res_dict = json.load(f)
        res = make_response(jsonify(res_dict))
        res.headers['Access-Control-Allow-Origin'] = '*'  # 把这个key和value加入到响应头,就没有跨域问题了
        return res

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

image

vue生命周期

1.bedoreCreate   创建Vue实例之前调用,data,el都没有
2.created        创建Vue实例成功后调用(可以在此处发送异步请求后端数据),data有了,el没有的
3.beforeMount    渲染DOM之前调用 ,data有了,el没有
4.mounted(用得最多)    渲染DOM之后调用
这时候可以向后端发送数据了
5.beforeUpdate      重新渲染之前调用(数据更新等操作时,控制DOM重新渲染)
6.updated           重新渲染完成之后调用
7.beforeDestroy     销毁之前调用
8.destroyed         销毁之后调用

image

1 组件向后端发送请求,获取数据,应该放在 created 写,此时data已经有数据了

2 destroyed做一些资源清理性的工作

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
</head>
<body>
<div id="app">
    <button @click="handleShow">点我组件显示和消失</button>
    <Child v-if="show"></Child>
</div>
<script>
    // 创建一个组件
    Vue.component('Child',{
        template: `
            <div id="app">
                <h1>{{name}}</h1>
                <button @click="handleClick">点我看美女</button>
            </div>
        `,
        data(){
            return{
                name:'所以请继续加油'
            }
        },
        methods:{
            handleClick(){
                alert('美女')
            }
        },
        beforeCreate() {
            console.log('beforeCreate')
        },

        created() {
            console.log('created')
        },
        beforeMount() {
            console.log('beforeMount')
        },
        mounted() {
            //用的最多,向后端加载数据,创建定时器等
            console.log("页面已被vue实例渲染, data, methods已更新");
            console.log('mounted')
            this.t = setInterval(function () {
                console.log('今天学的很累,但是很充实,继续加油!!')
            }, 3000)
        },
        beforeUpdate() {
            console.log('beforeUpdate')
        },
        updated() {
            console.log('updated')
        },
        beforeDestroy() {
            console.log('created')
        },
        destroyed() {
            //组件销毁,清理定时器
            clearInterval(this.t)
            this.t = null
            console.log('destoryed')
        },
    })
    var vm = new Vue({
        el: '#app',
        data: {
            show:true,
        },
        methods: {
            handleShow(){
                this.show=!this.show
            }
        }

    })
</script>
</body>
</html>

image

# 延时任务
    setTimeout(()=>{
       console.log('3s后执行我')
    },3000)
# 定时任务
   setInterval(()=>{
     console.log('hello')
   },3000)

# 什么场景下用定时任务?
1 实时跟后端交互  基于http+定时任务 (websocket协议:服务端主动推送消息,手机app的消息推送)

2 秒杀场景:先提交秒杀请求,每隔3s,查询是否秒到

img

vue组件

# 组件化开发的好处:重用代码
# 组件分类
	-全局组件:在任意组件中都可以使用
    -局部组件:只能在当前组件中使用

小知识点

	深拷贝和浅拷贝是针对复杂数据类型(对象及数组)来说的,浅拷贝只拷贝一层,而深拷贝是层层拷贝。
浅拷贝:
    浅拷贝只拷贝基本类型的数据,而符合类型的数据只复制指向其的指针,而不复制对象本身,新旧对象还是共享同一块内存。
深拷贝:
深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。