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

昨日内容回顾

# 1 v-for 可以循环的类型

# 2 js的循环方式
    -基于索引的循环 (i=0;i<10;i++)
    -in 循环出来的是索引
    -of 基于迭代的,循环出来就是值
    -数组.each(item=>{})  # jq遍历
    -ajax forEach 循环
    
# 3 key值的解释 :key='唯一值'

# 4 数组对象的检测与更新
    Vue.set()
    
# 5 input:事件
    click  点击事件
    input  当输入框进行输入的时候 触发事件
    change 当元素的值发生改变时 触发事件
    blur   当输入框失去焦点时候 触发事件
    focus  当获得焦点 触发事件
    
# 6 v-model input标签上
    双向数据绑定
    
# 7 过滤案例
   -1 数组的.filter((item)=>{return true})
   -2 字符串的 indexOf 判断子字符串是否在字符串中,如果在大于等于0,如果不在,等于-1
   -3 箭头函数
       var f=item=>item+xxx
    
# 8 事件修饰符
    .stop 
    只处理自己的事件,子控件冒泡的事件不处理(阻止事件冒泡)
    .self
    只处理自己的事件,子控件冒泡的事件不处理
    .prevent
    阻止a链接的跳转
    .once
    事件只会触发一次(适用于抽奖页面)
    
# 9 按键事件
    @keyup='函数'  按了键盘某个键,就会触发函数的执行
#   按键修饰符
    @keyup.enter='函数'  只有某个按键被按下才触发
    
# 10 表单控制
    -radio:字符串类型 多个radio使用v-model绑定,选中某个会把 value 赋值给这个变量
    -chekbox
       单选:布尔类型
       多选:数组中

今日内容

  • 购物车案例

  • v-model进阶

  • 与后端交互

  • vue生命周期

  • vue组件

1 购物车案例

1.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.1/jquery.js"></script>
    <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>选择</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:2850,number:2},
                {id:'2',name:'无尽之刃',price:3000,number:3},
                {id:'3',name:'星蚀',price:3600,number:1},
                {id:'4',name:'黑色切割者',price:3200,number:6},
                {id:'5',name:'贪欲九头蛇',price:3150,number:4},
            ],
            checkGroup:[]
        },
        methods:{
            getPrice(){
                // 通过checkGroup里面的对象,计算出总价格
                var total = 0
                for (item of this.checkGroup){
                    total +=item.price * item.number
                }
                return total
            }
        }
    })
</script>
</html>

image-20230216184517653

1.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.1/jquery.js"></script>
    <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="handleCheckOne"></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:2850,number:2},
                {id:'2',name:'无尽之刃',price:3000,number:3},
                {id:'3',name:'星蚀',price:3600,number:1},
                {id:'4',name:'黑色切割者',price:3200,number:6},
                {id:'5',name:'贪欲九头蛇',price:3150,number:4},
            ],
            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(){
                // console.log('一个被点了')
                if (this.checkGroup.length==this.goodList.length){
                    this.checkAll=true
                }else {
                    this.checkAll=false
                }
            }
        }
    })
</script>
</html>

image-20230216185847150

1.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.1/jquery.js"></script>
    <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 @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>选中商品:{{checkGroup}}---{{checkAll}}</p>
                    <p>总价格:{{getPrice()}}</p>
                </div>
            </div>
        </div>
    </div>
</body>
<script>
    var vm = new Vue({
        el:'.app',
        data:{
            goodList:[
                {id:'1',name:'破败王者之刃',price:2850,number:2},
                {id:'2',name:'无尽之刃',price:3000,number:3},
                {id:'3',name:'星蚀',price:3600,number:1},
                {id:'4',name:'黑色切割者',price:3200,number:6},
                {id:'5',name:'贪欲九头蛇',price:3150,number:4},
            ],
            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(){
                // console.log('一个被点了')
                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-20230216193646622

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>

image-20230216194042495

3 与后端交互

# 跨域问题
	-浏览器的原因,只要向不是地址栏中的 [域:地址和端口]发送请求,拿的数据,浏览器就给拦截了
    
    
# 处理跨域问题
	-后端代码处理----》只需要在响应头中加入允许即可   

3.1 Vue与django后端交互

前端

<!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:8000/collection/',
                    type:'get',
                    success:data=>{
                        console.log(data)
                        this.name=data.name
                        this.age=data.age
                        this.gender=data.gender
                    }
                })
            }
        }
    })
</script>
</html>

视图层

from django.shortcuts import render

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


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

路由层

from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('collection/', views.CollectionView.as_view()),
]

image-20230216213424078

跨域问题:
	浏览器原因,只要向不是地址栏中的[域:地址和端口]发送请求,拿到的数据就会被浏览器拦截

处理跨域问题
	后端通过在响应头中加入允许即可
	CORS:服务器设置HTTP响应头中Access-Control-Allow-Origin值,解除跨域限制

视图层中添加请求头

from django.shortcuts import render

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


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加入到响应头,就没有跨域问题了

image-20230216213637539

image-20230216213654449

3.2 fetch发送ajax请求

# fetch 提供了一个 JavaScript 接口,用于访问和操纵 HTTP 管道的一些具体部分,例如请求和响应
	-新的发送ajax 接口
    -用起来比较方便
    -支持promise写法[最新的异步写法]
    -解决了原生的XMLHttpRequest兼容性的问题
    -不是所有浏览器都支持
    -主流现在是用axios[第三方]发送请求
# XMLHttpRequest: 原生js提供的
	-比较老,不同浏览器需要做一些兼容性的处理,写起来比较麻烦
    -jq基于它做了封装
       
 # 发送ajax请求
<!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>点击加载用户信息</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  fetch
                fetch('http://127.0.0.1:5000/').then(response => response.json()).then(res => {
                    // 对象
                    console.log(res)
                    this.name = res.name
                    this.age = res.age
                    this.gender = res.gender
                })
            }
        }
    })
</script>
</html>

3.3 axios发送ajax请求

官网

http://axios-js.com/

CDN使用

<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>  //cdn引入

下载

/* axios v0.21.0 | (c) 2020 by Matt Zabriskie */
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.axios=t():e.axios=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t,n){"use strict";function r(e){var t=new i(e),n=s(i.prototype.request,t);return o.extend(n,i.prototype,t),o.extend(n,t),n}var o=n(2),s=n(3),i=n(4),a=n(22),u=n(10),c=r(u);c.Axios=i,c.create=function(e){return r(a(c.defaults,e))},c.Cancel=n(23),c.CancelToken=n(24),c.isCancel=n(9),c.all=function(e){return Promise.all(e)},c.spread=n(25),e.exports=c,e.exports.default=c},function(e,t,n){"use strict";function r(e){return"[object Array]"===R.call(e)}function o(e){return"undefined"==typeof e}function s(e){return null!==e&&!o(e)&&null!==e.constructor&&!o(e.constructor)&&"function"==typeof e.constructor.isBuffer&&e.constructor.isBuffer(e)}function i(e){return"[object ArrayBuffer]"===R.call(e)}function a(e){return"undefined"!=typeof FormData&&e instanceof FormData}function u(e){var t;return t="undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(e):e&&e.buffer&&e.buffer instanceof ArrayBuffer}function c(e){return"string"==typeof e}function f(e){return"number"==typeof e}function p(e){return null!==e&&"object"==typeof e}function d(e){if("[object Object]"!==R.call(e))return!1;var t=Object.getPrototypeOf(e);return null===t||t===Object.prototype}function l(e){return"[object Date]"===R.call(e)}function h(e){return"[object File]"===R.call(e)}function m(e){return"[object Blob]"===R.call(e)}function y(e){return"[object Function]"===R.call(e)}function g(e){return p(e)&&y(e.pipe)}function v(e){return"undefined"!=typeof URLSearchParams&&e instanceof URLSearchParams}function x(e){return e.replace(/^\s*/,"").replace(/\s*$/,"")}function w(){return("undefined"==typeof navigator||"ReactNative"!==navigator.product&&"NativeScript"!==navigator.product&&"NS"!==navigator.product)&&("undefined"!=typeof window&&"undefined"!=typeof document)}function b(e,t){if(null!==e&&"undefined"!=typeof e)if("object"!=typeof e&&(e=[e]),r(e))for(var n=0,o=e.length;n<o;n++)t.call(null,e[n],n,e);else for(var s in e)Object.prototype.hasOwnProperty.call(e,s)&&t.call(null,e[s],s,e)}function E(){function e(e,n){d(t[n])&&d(e)?t[n]=E(t[n],e):d(e)?t[n]=E({},e):r(e)?t[n]=e.slice():t[n]=e}for(var t={},n=0,o=arguments.length;n<o;n++)b(arguments[n],e);return t}function C(e,t,n){return b(t,function(t,r){n&&"function"==typeof t?e[r]=S(t,n):e[r]=t}),e}function j(e){return 65279===e.charCodeAt(0)&&(e=e.slice(1)),e}var S=n(3),R=Object.prototype.toString;e.exports={isArray:r,isArrayBuffer:i,isBuffer:s,isFormData:a,isArrayBufferView:u,isString:c,isNumber:f,isObject:p,isPlainObject:d,isUndefined:o,isDate:l,isFile:h,isBlob:m,isFunction:y,isStream:g,isURLSearchParams:v,isStandardBrowserEnv:w,forEach:b,merge:E,extend:C,trim:x,stripBOM:j}},function(e,t){"use strict";e.exports=function(e,t){return function(){for(var n=new Array(arguments.length),r=0;r<n.length;r++)n[r]=arguments[r];return e.apply(t,n)}}},function(e,t,n){"use strict";function r(e){this.defaults=e,this.interceptors={request:new i,response:new i}}var o=n(2),s=n(5),i=n(6),a=n(7),u=n(22);r.prototype.request=function(e){"string"==typeof e?(e=arguments[1]||{},e.url=arguments[0]):e=e||{},e=u(this.defaults,e),e.method?e.method=e.method.toLowerCase():this.defaults.method?e.method=this.defaults.method.toLowerCase():e.method="get";var t=[a,void 0],n=Promise.resolve(e);for(this.interceptors.request.forEach(function(e){t.unshift(e.fulfilled,e.rejected)}),this.interceptors.response.forEach(function(e){t.push(e.fulfilled,e.rejected)});t.length;)n=n.then(t.shift(),t.shift());return n},r.prototype.getUri=function(e){return e=u(this.defaults,e),s(e.url,e.params,e.paramsSerializer).replace(/^\?/,"")},o.forEach(["delete","get","head","options"],function(e){r.prototype[e]=function(t,n){return this.request(u(n||{},{method:e,url:t,data:(n||{}).data}))}}),o.forEach(["post","put","patch"],function(e){r.prototype[e]=function(t,n,r){return this.request(u(r||{},{method:e,url:t,data:n}))}}),e.exports=r},function(e,t,n){"use strict";function r(e){return encodeURIComponent(e).replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}var o=n(2);e.exports=function(e,t,n){if(!t)return e;var s;if(n)s=n(t);else if(o.isURLSearchParams(t))s=t.toString();else{var i=[];o.forEach(t,function(e,t){null!==e&&"undefined"!=typeof e&&(o.isArray(e)?t+="[]":e=[e],o.forEach(e,function(e){o.isDate(e)?e=e.toISOString():o.isObject(e)&&(e=JSON.stringify(e)),i.push(r(t)+"="+r(e))}))}),s=i.join("&")}if(s){var a=e.indexOf("#");a!==-1&&(e=e.slice(0,a)),e+=(e.indexOf("?")===-1?"?":"&")+s}return e}},function(e,t,n){"use strict";function r(){this.handlers=[]}var o=n(2);r.prototype.use=function(e,t){return this.handlers.push({fulfilled:e,rejected:t}),this.handlers.length-1},r.prototype.eject=function(e){this.handlers[e]&&(this.handlers[e]=null)},r.prototype.forEach=function(e){o.forEach(this.handlers,function(t){null!==t&&e(t)})},e.exports=r},function(e,t,n){"use strict";function r(e){e.cancelToken&&e.cancelToken.throwIfRequested()}var o=n(2),s=n(8),i=n(9),a=n(10);e.exports=function(e){r(e),e.headers=e.headers||{},e.data=s(e.data,e.headers,e.transformRequest),e.headers=o.merge(e.headers.common||{},e.headers[e.method]||{},e.headers),o.forEach(["delete","get","head","post","put","patch","common"],function(t){delete e.headers[t]});var t=e.adapter||a.adapter;return t(e).then(function(t){return r(e),t.data=s(t.data,t.headers,e.transformResponse),t},function(t){return i(t)||(r(e),t&&t.response&&(t.response.data=s(t.response.data,t.response.headers,e.transformResponse))),Promise.reject(t)})}},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t,n){return r.forEach(n,function(n){e=n(e,t)}),e}},function(e,t){"use strict";e.exports=function(e){return!(!e||!e.__CANCEL__)}},function(e,t,n){"use strict";function r(e,t){!s.isUndefined(e)&&s.isUndefined(e["Content-Type"])&&(e["Content-Type"]=t)}function o(){var e;return"undefined"!=typeof XMLHttpRequest?e=n(12):"undefined"!=typeof process&&"[object process]"===Object.prototype.toString.call(process)&&(e=n(12)),e}var s=n(2),i=n(11),a={"Content-Type":"application/x-www-form-urlencoded"},u={adapter:o(),transformRequest:[function(e,t){return i(t,"Accept"),i(t,"Content-Type"),s.isFormData(e)||s.isArrayBuffer(e)||s.isBuffer(e)||s.isStream(e)||s.isFile(e)||s.isBlob(e)?e:s.isArrayBufferView(e)?e.buffer:s.isURLSearchParams(e)?(r(t,"application/x-www-form-urlencoded;charset=utf-8"),e.toString()):s.isObject(e)?(r(t,"application/json;charset=utf-8"),JSON.stringify(e)):e}],transformResponse:[function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(e){}return e}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,maxBodyLength:-1,validateStatus:function(e){return e>=200&&e<300}};u.headers={common:{Accept:"application/json, text/plain, */*"}},s.forEach(["delete","get","head"],function(e){u.headers[e]={}}),s.forEach(["post","put","patch"],function(e){u.headers[e]=s.merge(a)}),e.exports=u},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t){r.forEach(e,function(n,r){r!==t&&r.toUpperCase()===t.toUpperCase()&&(e[t]=n,delete e[r])})}},function(e,t,n){"use strict";var r=n(2),o=n(13),s=n(16),i=n(5),a=n(17),u=n(20),c=n(21),f=n(14);e.exports=function(e){return new Promise(function(t,n){var p=e.data,d=e.headers;r.isFormData(p)&&delete d["Content-Type"];var l=new XMLHttpRequest;if(e.auth){var h=e.auth.username||"",m=e.auth.password?unescape(encodeURIComponent(e.auth.password)):"";d.Authorization="Basic "+btoa(h+":"+m)}var y=a(e.baseURL,e.url);if(l.open(e.method.toUpperCase(),i(y,e.params,e.paramsSerializer),!0),l.timeout=e.timeout,l.onreadystatechange=function(){if(l&&4===l.readyState&&(0!==l.status||l.responseURL&&0===l.responseURL.indexOf("file:"))){var r="getAllResponseHeaders"in l?u(l.getAllResponseHeaders()):null,s=e.responseType&&"text"!==e.responseType?l.response:l.responseText,i={data:s,status:l.status,statusText:l.statusText,headers:r,config:e,request:l};o(t,n,i),l=null}},l.onabort=function(){l&&(n(f("Request aborted",e,"ECONNABORTED",l)),l=null)},l.onerror=function(){n(f("Network Error",e,null,l)),l=null},l.ontimeout=function(){var t="timeout of "+e.timeout+"ms exceeded";e.timeoutErrorMessage&&(t=e.timeoutErrorMessage),n(f(t,e,"ECONNABORTED",l)),l=null},r.isStandardBrowserEnv()){var g=(e.withCredentials||c(y))&&e.xsrfCookieName?s.read(e.xsrfCookieName):void 0;g&&(d[e.xsrfHeaderName]=g)}if("setRequestHeader"in l&&r.forEach(d,function(e,t){"undefined"==typeof p&&"content-type"===t.toLowerCase()?delete d[t]:l.setRequestHeader(t,e)}),r.isUndefined(e.withCredentials)||(l.withCredentials=!!e.withCredentials),e.responseType)try{l.responseType=e.responseType}catch(t){if("json"!==e.responseType)throw t}"function"==typeof e.onDownloadProgress&&l.addEventListener("progress",e.onDownloadProgress),"function"==typeof e.onUploadProgress&&l.upload&&l.upload.addEventListener("progress",e.onUploadProgress),e.cancelToken&&e.cancelToken.promise.then(function(e){l&&(l.abort(),n(e),l=null)}),p||(p=null),l.send(p)})}},function(e,t,n){"use strict";var r=n(14);e.exports=function(e,t,n){var o=n.config.validateStatus;n.status&&o&&!o(n.status)?t(r("Request failed with status code "+n.status,n.config,null,n.request,n)):e(n)}},function(e,t,n){"use strict";var r=n(15);e.exports=function(e,t,n,o,s){var i=new Error(e);return r(i,t,n,o,s)}},function(e,t){"use strict";e.exports=function(e,t,n,r,o){return e.config=t,n&&(e.code=n),e.request=r,e.response=o,e.isAxiosError=!0,e.toJSON=function(){return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:this.config,code:this.code}},e}},function(e,t,n){"use strict";var r=n(2);e.exports=r.isStandardBrowserEnv()?function(){return{write:function(e,t,n,o,s,i){var a=[];a.push(e+"="+encodeURIComponent(t)),r.isNumber(n)&&a.push("expires="+new Date(n).toGMTString()),r.isString(o)&&a.push("path="+o),r.isString(s)&&a.push("domain="+s),i===!0&&a.push("secure"),document.cookie=a.join("; ")},read:function(e){var t=document.cookie.match(new RegExp("(^|;\\s*)("+e+")=([^;]*)"));return t?decodeURIComponent(t[3]):null},remove:function(e){this.write(e,"",Date.now()-864e5)}}}():function(){return{write:function(){},read:function(){return null},remove:function(){}}}()},function(e,t,n){"use strict";var r=n(18),o=n(19);e.exports=function(e,t){return e&&!r(t)?o(e,t):t}},function(e,t){"use strict";e.exports=function(e){return/^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(e)}},function(e,t){"use strict";e.exports=function(e,t){return t?e.replace(/\/+$/,"")+"/"+t.replace(/^\/+/,""):e}},function(e,t,n){"use strict";var r=n(2),o=["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"];e.exports=function(e){var t,n,s,i={};return e?(r.forEach(e.split("\n"),function(e){if(s=e.indexOf(":"),t=r.trim(e.substr(0,s)).toLowerCase(),n=r.trim(e.substr(s+1)),t){if(i[t]&&o.indexOf(t)>=0)return;"set-cookie"===t?i[t]=(i[t]?i[t]:[]).concat([n]):i[t]=i[t]?i[t]+", "+n:n}}),i):i}},function(e,t,n){"use strict";var r=n(2);e.exports=r.isStandardBrowserEnv()?function(){function e(e){var t=e;return n&&(o.setAttribute("href",t),t=o.href),o.setAttribute("href",t),{href:o.href,protocol:o.protocol?o.protocol.replace(/:$/,""):"",host:o.host,search:o.search?o.search.replace(/^\?/,""):"",hash:o.hash?o.hash.replace(/^#/,""):"",hostname:o.hostname,port:o.port,pathname:"/"===o.pathname.charAt(0)?o.pathname:"/"+o.pathname}}var t,n=/(msie|trident)/i.test(navigator.userAgent),o=document.createElement("a");return t=e(window.location.href),function(n){var o=r.isString(n)?e(n):n;return o.protocol===t.protocol&&o.host===t.host}}():function(){return function(){return!0}}()},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t){function n(e,t){return r.isPlainObject(e)&&r.isPlainObject(t)?r.merge(e,t):r.isPlainObject(t)?r.merge({},t):r.isArray(t)?t.slice():t}function o(o){r.isUndefined(t[o])?r.isUndefined(e[o])||(s[o]=n(void 0,e[o])):s[o]=n(e[o],t[o])}t=t||{};var s={},i=["url","method","data"],a=["headers","auth","proxy","params"],u=["baseURL","transformRequest","transformResponse","paramsSerializer","timeout","timeoutMessage","withCredentials","adapter","responseType","xsrfCookieName","xsrfHeaderName","onUploadProgress","onDownloadProgress","decompress","maxContentLength","maxBodyLength","maxRedirects","transport","httpAgent","httpsAgent","cancelToken","socketPath","responseEncoding"],c=["validateStatus"];r.forEach(i,function(e){r.isUndefined(t[e])||(s[e]=n(void 0,t[e]))}),r.forEach(a,o),r.forEach(u,function(o){r.isUndefined(t[o])?r.isUndefined(e[o])||(s[o]=n(void 0,e[o])):s[o]=n(void 0,t[o])}),r.forEach(c,function(r){r in t?s[r]=n(e[r],t[r]):r in e&&(s[r]=n(void 0,e[r]))});var f=i.concat(a).concat(u).concat(c),p=Object.keys(e).concat(Object.keys(t)).filter(function(e){return f.indexOf(e)===-1});return r.forEach(p,o),s}},function(e,t){"use strict";function n(e){this.message=e}n.prototype.toString=function(){return"Cancel"+(this.message?": "+this.message:"")},n.prototype.__CANCEL__=!0,e.exports=n},function(e,t,n){"use strict";function r(e){if("function"!=typeof e)throw new TypeError("executor must be a function.");var t;this.promise=new Promise(function(e){t=e});var n=this;e(function(e){n.reason||(n.reason=new o(e),t(n.reason))})}var o=n(23);r.prototype.throwIfRequested=function(){if(this.reason)throw this.reason},r.source=function(){var e,t=new r(function(t){e=t});return{token:t,cancel:e}},e.exports=r},function(e,t){"use strict";e.exports=function(e){return function(t){return e.apply(null,t)}}}])});
//# sourceMappingURL=axios.min.map
我们以后会经常使用vue上的axios
来向后端发送ajax请求,
Axios 是一个基于promise 的HTTP库,还是基于XMLHttpRequest封装的

我们提交请求后得到该数据:注意这个数据本身就是data,我们自己的数据也叫做data,
相当于对象里面又套了对象,我们通过句点符的形式取出我们所需要的数据

<!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:8000/collection/').then(res => {
                    // res是对象,有点特殊,真正的数据(想要body体内容),在res.data中
                    console.log(res)
                    this.name = res.data.name
                    this.age = res.data.age
                    this.gender = res.data.gender
                })

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

image-20230216224802071

3.4 小电影案例

网址:https://m.maizuo.com/v5/?co=mzmovie#/films/nowPlaying

抓数据

image-20230216225242315

image-20230216231822953

右键复制obj到JSON在线解析及格式化验证 - JSON.cn

image-20230216231801016

创建文件.json格式将内容复制到文件中

image-20230216234251160

视图层

from django.shortcuts import render
from django.http import JsonResponse
from rest_framework.response import Response
from rest_framework.views import APIView
import json


class CollectionView(APIView):
    def get(self, request):
        with open(r'E:\Djangoproject\vue_ajax\film.json', 'r', encoding='utf-8')as f:
            back_dict = json.load(f)
        obj = JsonResponse(back_dict)             # 原生响应
        obj['Access-Control-Allow-Origin'] = '*'  # 针对简单请求
        return obj
        # return Response(back_dict, headers={'Access-Control-Allow-Origin': '*'})  # 用rest_framework的reponse

前端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script>
     <script src="./js/vue.js"></script>
    <script src="./js/axios.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">点我</button>
        <ul>
            <li v-for="item in dataList">
                <h2>名字:{{ item.name }}</h2>
                <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:{
            handleClick(){
                axios.get('http://127.0.0.1:8000/collection/').then(res=>{
                    console.log(res)
                    this.dataList=res.data.data.films
                })
            }
        }
    })
</script>
</html>

路由

from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('collection/', views.CollectionView.as_view()),
]

image-20230216235642635

4 vue生命周期

# 从vue实例创建开始,到实例被销毁,总共经历了8个生命周期钩子[只要写了就会执行]函数
	-钩子:反序列化验证---》钩子函数
    -学名[专门名字]---》面向切面编程(AOP)
    -OOP:面向对象编程
        
        
# 8个生命周期钩子函数
    beforeCreate	  创建Vue实例之前调用
    created	          创建Vue实例成功后调用(可以在此处发送异步请求后端数据)
    beforeMount	      渲染DOM之前调用
    mounted	          渲染DOM之后调用
    beforeUpdate	  重新渲染之前调用(数据更新等操作时,控制DOM重新渲染)
    updated	          重新渲染完成之后调用
    beforeDestroy	  销毁之前调用
    destroyed	      销毁之后调用



# 重点:
	-1 用的最多的,created  发送ajax请求----》有的人放在mounted中加载
	-2 beforeDestroy
    	-组件一创建,created中启动一个定时器
        -组件被销毁,beforeDestroy销毁定时器
	


http协议是只能通过请求发送,得到响应,
这也就意味着服务端并不能主动的推送数据给客户端,
我们获取数据就是基于请求而已

如果我们想要实现实时聊天的效果(在线聊天室)
	轮询: 定时器+ajax ---知识点 http---版本区别
	长轮询: 定时器+ ajax
	websocket协议:服务端主动推送消息

2987368-20230216234353148-931405378

理解图

2987368-20230216234353311-1329019777

重点

用的最多的,created发送ajax请求,–》有的人放在mounted中加载

beforeDestroy

组件一创建,created中启动一个定时器

组件被销毁,beforeDestroy销毁定时器

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script>
    <script src="./js/vue.js"></script>
</head>
<body>
<div class="app">
    <div class="app">
        <button @click="handlerClick">点我显示或关闭</button>
        <childs v-if="show"></childs>
    </div>
</div>
</body>
<script>
 
    Vue.component('childs', {
        template: `
          <div>{{name}}
          <p @click="handler">点我改变name</p>
          </div>
        `,
        data() {
            return {name: '123'}
        },
        methods: {
            handler() {
                this.name = 111
            }
        },
        //创建Vue对象之前执行的
        //实例化Vue对象的首先执行的相当于申请了一块内存地址
        beforeCreate() {
            console.group('准备创建实例了')
            console.log(this.$el, this.$data, this.name)
        },
        //创建Vue对象完毕执行的
        //这个相当于把要托管的标签名与内部的一些数据进行绑定
        created() {
            console.group('实例创建过了')
            console.log(this.$el, this.$data, this.name)
        },
        //这个是相当于进行页面渲染之前执行
        beforeMount() {
            console.group('准备渲染页面了')
            console.log(this.$el, this.$data, this.name)
        },
        //这个是页面渲染完毕后执行,这个el就托管了模板字符串的标签了
        mounted() {
            console.group('页面渲染过了')
            console.log(this.$el, this.$data, this.name)
        },
        //这个是在检测的数据变化要进行数据更新之前要做的操作
        beforeUpdate() {
            console.group('准备更新数据了')
            console.log(this.$el, this.$data, this.name)
        },
        //这个是数据变化之后的要做的
        updated() {
            console.group('数据更新过了')
            console.log(this.$el, this.$data, this.name)
        },
        //这个是这个Vue对象要被销毁之前做操作
        beforeDestroy() {
            console.group('准备删除实例了')
            console.log(this.$el, this.$data, this.name)
        },
        //这个是Vue对象被销毁之后做的操作
        destroyed() {
            console.group('实例删除过了')
            console.log(this.$el, this.$data, this.name)
        },
    })
 
 
    var vm = new Vue({
        el: '.app',
        data: {
            show: true
        },
        methods: {
            handlerClick() {
                this.show = !this.show
            },
        },
 
 
    })
</script>
</html>

image-20230216234209853

image-20230216234220921

image-20230216234242968

参考博客: https://zhuanlan.zhihu.com/p/371500343

# 1 轮询:
客户端向服务端无限循环发送http请求,一旦服务端有最新消息,从当次http响应中带回,客户端就能收到变化
# 2 长轮回(web版微信采用此方式)
客户端和服务端保持一个长连接(http),等服务端有消息返回就断开,
如果没有消息,就会hold住,等待一定时间,然后再重新连接,也是个循环的过程
# 3 websocket协议
客户端发起HTTP握手,告诉服务端进行WebSocket协议通讯,并告知WebSocket协议版本。
服务端确认协议版本,升级为WebSocket协议。之后如果有数据需要推送,会主动推送给客户端

5 vue组件

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

定义全局组件

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

    <h1>组件</h1>
    <child></child>
</div>
</body>
<script>
    Vue.component('child', {
        template: `
          <div>
          <button>后退</button>
          <span style="font-size: 30px">首页{{name}}</span>
          <button @click="handleFor">前进</button>
          </div>`, // 里面写html内容,必须包在一个标签中
        data() {   // data必须是方法,返回对象
            return {
                name:'ikun',
                t:null
            }
        },
        methods:{
            handleFor(){
                this.name = 'ckx'
            }
        }
    })
    var vm = new Vue({
        el: '.app',
    })

</script>
</html>

image-20230217194311178

image-20230217194323757

定义局部组件

局部定义的变量只能在模板字符串内使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script>
    <script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
    <child></child>
</div>
 
</body>
<script>
    Vue.component('child', {
        template: `
          <div>
          {{ name }}
          <br>
          <child1>
          </child1>
          {{name}}
          </div>
        `,
        data() {
            return {
                name: '张三',
            }
        },
        components: {
            child1: {
                template: `
                  <div>
                  {{ age }}
                  </div>
                `,
                data() {
                    return {
                        age: 13
                    }
                },
            }
        }
    })
 
 
    var vm = new Vue({
        el: '#app',
        data: {},
        methods: {}
    })
 
 
</script>
</html>

image-20230216224820398

image-20230216225134637

posted @ 2023-02-17 19:46  Super小赵  阅读(40)  评论(0编辑  收藏  举报
****************************************** 页脚Html代码 ******************************************