vue之vue生命周期和ajax请求
一、表单控制
# 我们之前所学的input标签中有很多类型 checkbox和radio 这些都是单选或则多选的那么绑定的变量 该是什么类型为好呢? # input:checkbox(单选,多选),radio(单选)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="./js/vue.js"></script> </head> <body> <div id="app"> <h1>表单控制</h1> <p>用户名:<input type="text" v-model="name"></p> <p>密码:<input type="text" v-model="password"></p> <p><input type="checkbox" v-model="isRemember"> 记住密码</p> <!--因为记住密码只有两种状态 所以可以是布尔值 checkbox可以单选--> <p> <input type="radio" v-model="gender" value="1"> 男 <input type="radio" v-model="gender" value="2"> 女 <input type="radio" v-model="gender" value="0"> 未知 <!--因为radio是单选 所以可以是字符串来判断 选择了什么 传递给后端的值 是value的值--> </p> <p> 爱好: <input type="checkbox" value="篮球" v-model="hobby"> 篮球 <input type="checkbox" value="足球" v-model="hobby"> 足球 <input type="checkbox" value="乒乓球" v-model="hobby"> 乒乓球 <input type="checkbox" value="橄榄球" v-model="hobby"> 橄榄球 <!--checkbox如果是多选的话 可以使用数组 传递给后端的值 是value的值 其实也可以用数字--> </p> </div> </body> <script> new Vue({ el: '#app', data: { name: '', password: '', isRemember: false, // checkbox单选,使用布尔类型 gender: '', // radio单选,使用字符串 hobby: [], // checkbox 多选使用数组 }, }) </script> </html>
二、购物车案例
1 补充
python中只有基于迭代的循环,没有基于索引的循环
java,go,js中是既有基于迭代的循环,也有基于索引的循环
js中的for循环
1 for(i=0;i<checkGroup.length;i++) # 基于索引的循环 2 for (i in checkGroup) # 基于迭代的循环 3 for (i of checkGroup) # es6中 循环 4 数组内置方法.forEach() 5 jquery $.each 循环 # 代码演示 # 定义一个数组 var goodList = [ {name: '今瓶没', price: 99, number: 2}, {name: '西柚记', price: 59, number: 1}, {name: '水壶转', price: 89, number: 5}, {name: '特斯拉', price: 230000, number: 5},] 1 方式一:js的基于索引的循环 # 原生js基于索引的循环 for (var i = 0; i< goodList.length; i++) { console.log(goodList[i]) # i就是索引,不能拿到数组中的值 } 2 方式二:基于迭代的循环 # 原生js基于迭代的循环 for (i in goodList){ console.log(goodList[i]) } # i 也是索引,不能拿到数组中的值 3 方式三:of 循环,基于迭代的 # 原生of循环 for (i of goodList){ console.log(i) } # i就是数组中一个一个的值 4 方式四:数组的循环方法 # 数组的内置方法 goodList.forEach(item => { console.log('---', item) }) # item就是数组中一个一个的值 5 jquery:引入 # jquery方法 $.each(goodList, (i, v) => { console.log(v) # 可以有两个值 i是所以,v是数组中一个一个的值 })
2 购物车代码
<div id="app"> <div class="container-fluid"> <h2 class="text-center">购物车案例</h2> <div class="col-md-6 col-md-offset-3"> <table class="table-hover table table-striped"> <thead> <tr> <th>商品名称</th> <th>商品单价</th> <th>商品数量</th> <th><input type="checkbox" v-model="checkAll" @change="handleChange">全选/取消</th> </tr> </thead> <tbody> <tr v-for="item in goodList"> <td>{{item.name}}</td> <td>{{item.price}}</td> <td><span class="btn link btn-sm" @click="handleClick(item)">-</span>{{item.number}}<span class="btn link btn-sm" @click="item.number++">+</span></td> <!--这里++应该要传到后端判断有没有库存的 这里没有判断直接加了--> <td><input type="checkbox" v-model="checkGroup" :value="item" @change="handleOne"></td> </tr> </tbody> </table> <br> <span>选中的商品:{{checkGroup}}</span> <br> <span>总价格:{{getPrice()}}</span> </div> </div> </div> <!--vm实例--> <script> var vm = new Vue({ el: '#app', data: { goodList: [ {name: '今瓶没', price: 99, number: 2}, {name: '西柚记', price: 59, number: 1}, {name: '水壶转', price: 89, number: 5}, {name: '特斯拉', price: 230000, number: 5},], checkGroup: [], checkAll: false, }, methods: { handleChange() { if (this.checkAll) { // 如果全选 直接让选择的数组等于循环的数组 this.checkGroup = this.goodList } else { this.checkGroup = [] // 取消就直接为空即可 } }, handleOne() { // if (this.checkGroup.length === this.goodList.length) { // 就是判断两个数组是否相等 // this.checkAll = true // 相等就是全选 // } else { // this.checkAll = false // 没有就是没有全选 用户只选择了几个商品 // } // 可以简写成这样 this.checkAll = this.checkGroup.length === this.goodList.length }, getPrice() { var total = 0 for (item of this.checkGroup) { total += item.price * item.number // 计算总价格 } return total }, handleClick(item) { if (item.number > 1) { // 不能让数量为小于0 item.number-- } else { alert('太少了,受不了了') } } }, }) </script>
三、v-model进阶
lazy:等待input框的数据绑定时区焦点之后再变化
number:数字开头,只保留数字,后面的字母不保留;字母开头,都保留
trim:去除首尾的空格
<div id="app"> <h1>v-model进阶</h1> <input type="text" v-model.lazy="name1"> ---->{{name1}} <!--就是输入框失去焦点的时候 数据绑定才会把用户输入的值绑定 --> <br> <input type="text" v-model.number="name2"> ---->{{name2}} <!--就是如果开头是数字 那么不管后面写什么字符 只会保留数字 但是开头是字母的话 就会都保留--> <br> <input type="text" v-model.trim="name3"> ---->{{name3}} <!--这个就是取出首尾的空格--> </div> <script> new Vue({ el: '#app', data: { name1: '', name2: '', name3: '', }, }) </script>
四、vue的生命周期
# var vm = new Vue() -1 实例创建,数据放到实例中 -2 挂在模板:el---》div -3 改页面,改变量,都会相互影响 update -4 销毁实例 # 这四个过程,对应八个函数,依次执行(到某个过程就会执行某个函数) beforeCreate 创建Vue实例之前调用,data,el都没有 created 创建Vue实例成功后调用(可以在此处发送异步请求后端数据),data有了,el没有的 beforeMount 渲染DOM之前调用 ,data有了,el没有 mounted 渲染DOM之后调用 beforeUpdate 重新渲染之前调用(数据更新等操作时,控制DOM重新渲染) updated 重新渲染完成之后调用 beforeDestroy 销毁之前调用 destroyed 销毁之后调用 # 如果写了这些钩子函数 那么一个组件的创建到销毁的过程中 到那个时间点就会触发对应的钩子函数
一个实例只能看到前面六个钩子函数,销毁是看不到的 所以需要组件
一个组件的创建到销毁是能看到八个钩子函数的 只要写了的话
1. 代码实现
<div id="app"> <span>{{name}}</span> </div> <script> var vm = new Vue({ el:'#app', data:{ name:'jason' }, beforeCreate() { console.log('beforeCreate') // 实例前触发该钩子函数 }, created() { console.log('created') // 实例创建后触发该钩子函数 }, beforeMount() { console.log('beforeMount') // 渲染DOM之前, 渲染页面之前触发该钩子函数 }, mounted() { console.log('mounted') }, // 渲染DOM之后, 渲染页面之后触发 该钩子函数 beforeUpdate() { console.log('beforeUpdate') }, // 重新渲染之前触发 就是修改了组件的内的东西之前 就会触发 updated() { console.log('updated') }, // 重新渲染之后触发 就是修改之后 beforeDestroy() { console.log('beforeDestroy') // 销毁实例之前触发 }, destroyed() { console.log('destroyed') // 销毁实例之后触发 }, }) </script>
2.创建组件
<div id="app"> <button @click="handleClick">点击显示或取消组件</button> <!--通过点击按钮模拟创建和销毁组件--> <div v-if="res"> <!--上面的点击事件和该变量都是 实例中的事件和变量 不是组件的--> <hr> <child></child> <!--在实例中创建组件--> <hr> </div> </div> <script> Vue.component('child', { // 创建组件 组件名为 child template: ` <div> <h1>{{ name }}</h1> <button @click="handleClick">点我</button> <!--该点击事件和变量 是组件中的 不是实例的--> </div> `, // 组件的内容 data() { return { // 组件的变量需要返回才行 name:'lqz' } }, methods: { handleClick(){ this.name='tony' // 点击事件 让name变成tony } }, // 也可以写methods // 也可以写钩子函数 beforeCreate() { console.log('beforeCreate') // 组件创建前触发该钩子函数 }, created() { console.log('created') // 组件创建后触发该钩子函数 }, beforeMount() { console.log('beforeMount') // 渲染DOM之前, 渲染页面之前触发该钩子函数 }, mounted() { console.log('mounted') }, // 渲染DOM之后, 渲染页面之后触发 该钩子函数 beforeUpdate() { console.log('beforeUpdate') }, // 重新渲染之前触发 就是修改了组件的内的东西之前 就会触发 updated() { console.log('updated') }, // 重新渲染之后触发 就是修改之后 beforeDestroy() { console.log('beforeDestroy') // 销毁组件之前触发 }, destroyed() { console.log('destroyed') // 销毁组件之后触发 }, })
var vm = new Vue({ el: '#app', data: { res: true, }, methods: { handleClick() { this.res = !this.res } }, }) </script>
3 小案例
组件创建,开启定时器,不停的打印hello,在destroyed中对定时器进行销毁 -补充:js 定时任务和延时任务 # 延时任务 setTimeout(()=>{ console.log('3s后执行我') # 这个就三秒之后执行一次 },3000) #定时任务 setInterval(()=>{ console.log('hello') # 这个是每三秒执行一次 },3000)
代码演示
<div id="app"> <button @click="handleClick">点击显示或取消组件</button> <!--通过点击按钮模拟创建和销毁组件--> <div v-if="res"> <!--上面的点击事件和该变量都是 实例中的事件和变量 不是组件的--> <hr> <child></child> <!--在实例中创建组件--> <hr> </div> </div> <script> Vue.component('child', { // 创建组件 组件名为 child template: ` <div> <h1>name:{{ name }}</h1> <button @click="handleClick"> </div> `, // 组件的内容 data() { return { // 组件的变量需要返回才行 name: 'lqz', t:'' } }, methods: { handleClick() { this.name = 'tony' // 点击事件 让name变成tony } }, // 也可以写methods // 也可以写钩子函数 beforeCreate() { console.log('beforeCreate') // 组件创建前触发该钩子函数 }, created() { console.log('created') // 组件创建后触发该钩子函数 this.t = setInterval(() => { console.log('hello') }, 3000) }, beforeDestroy() { console.log('beforeDestroy') // 销毁组件之前触发 clearTimeout(this.t) // 定时任务开启之后 就算销毁组件 还是会继续执行 这是不合理的 所以我们需要在组件销毁之后把 定时任务给取消了 this.t = '' }, destroyed() { console.log('destroyed') // 销毁组件之后触发 }, }) var vm = new Vue({ el: '#app', data: { res: true, }, methods: { handleClick() { this.res = !this.res } }, }) </script>
五、ajax请求
# 向后端发送ajax请求---》jq的ajax方法 我们之前学的ajax其实是jquery的方法 只是该方法名字叫做ajax -方案一: jq的ajax---》在vue中不推荐 jquery与vue是一个东西 两个的操作有点相违背 jquery是为了方便我们去DOM vue是不用我们自己去操作DOM # 所以不推荐 -方案二:js原生官方提供了一个 fetch方法 -方案三:axios第三方 专门发送ajax请求第三方模块
后端
# 路由匹配 from django.urls import path from app01 import views urlpatterns = [ path('index/', views.index) ] # 试图函数 from django.http import JsonResponse def index(request): response = JsonResponse({'name': 'lqz', 'age': 18}) response['Access-Control-Allow-Origin'] = '*' # 因为跨域问题 所以响应头需要加上这个东西 return response
1 jquery发送ajax
<div id="app"> <p><span>name:{{name}}</span></p> <p><span>age:{{age}}</span></p> <p> <button @click="handleClick">点击向后端发送ajax请求</button> </p> </div> <script> var vm = new Vue({ el: '#app', data: { name: '', age: 0 }, methods: { handleClick() { // 第一种使用jquery发送ajax $.ajax({ url: 'http://127.0.0.1:8000/index/', type: 'get', success: data => { this.name = data.name // 从后端获取name和age this.age = data.age } }) } }, }) </script>
2.原生fetch发送ajax
<script> var vm = new Vue({ el: '#app', data: { name: '', age: 0 }, methods: { handleClick() { // fetch('http://127.0.0.1:5000/index').then(function (res) {return res.json}) // fetch('http://127.0.0.1:5000/index').then(res => res.json()) //还可以这样写 fetch('http://127.0.0.1:8000/index/').then(res => res.json()).then(res => { console.log(res) this.name = res.name this.age = res.age }) } }, }) </script>
3.使用axios发送ajax请求
<script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script> var vm = new Vue({ el: '#app', data: { name: '', age: 0 }, methods: { handleClick() { // 方式3:使用axios发送ajax请求 使用axios需要先导入链接 axios.get('http://127.0.0.1:8000/index/').then(res => { console.log(res) this.name = res.data.name this.age = res.data.age }) } }, }) </script>
4 使用axios下载电影案例
4.1 后端
from django.http import JsonResponse import json def index(request): with open(r'./data.json', 'r', encoding='utf8') as f: # 这个文件是提前爬出来的一些电影数据 data = json.load(f) response = JsonResponse(data) response['Access-Control-Allow-Origin'] = '*' # 因为跨域问题 所以响应头需要加上这个东西 return response
5.2 前端
<div id="app"> <ul> <li v-for="item in file_data"> <h2>电影名字:{{item.name}}</h2> <p>电影简介:{{item.synopsis}}</p> <img :src="item.poster" alt="" height="200px" width="100px"> </li> </ul> </div> <script> var vm = new Vue({ el: '#app', data: { file_data: '' }, created() { axios.get('http://127.0.0.1:8000/index/').then(res => { this.file_data = res.data.data.films }) } }) </script>