Vue之后端交互、计算、监听、组件间通信
一、与后端交互的多种方式
前后端要打通----> 从前端发送ajax---> 核心:使用js发送http请求,接收返回
- 原生js,可以开启ajax,但是原生js开启,比较麻烦,需要做浏览器兼容,有坑(基本不写)
-jquery,写了个兼容所有浏览器的 $.ajax(),不仅仅有ajax,还封装了很多dom操作。vue中使用它,不合适
-const xhr = new XMLHttpRequest()
Fetch和XMLHttpRequest (XHR) 都是用于在浏览器中进行网络请求的技术,它们的作用是从服务器获取数据或将数据发送到服务器
-axios:第三方的 ajax包(常用)
-fetch: 原生js发送ajax请求,有的浏览器也不兼容
1、js版本的 $.ajax()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | handleLoad() { // 请求发送成功,后端执行了,但是被浏览器拦截了,因为有跨域问题 // 当前地址,如果向非浏览器地址栏中得地址发送请求,就会出现跨域 // 1 ajax请求方式 1 jquery的ajax var _this = this $.ajax({ url: 'http://127.0.0.1:5000', type: 'get', success: function (data) { console.log(typeof data) var res = JSON.parse(data) _this.name = res.name _this.age = res.age } }) } |
补充: 使用箭头函数(箭头函数没有自己的this,不需要定义_this)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | < script > let vm = new Vue({ el: '#box', data: { name: '', age: 0 }, methods: { handleClick() { $.ajax({ url: 'http://127.0.0.1:5000/', // 发送请求的url,本地的5000端口,是flask的默认端口 method: 'get', success: (data)=> { if (data.code == 100) { this.name=data.name this.age=data.age } // console.log(data) } }) } } }) </ script > |
2、axios(第三方的 ajax包)
起步 | Axios 中文文档 | Axios 中文网 (axios-http.cn)
1 2 3 4 5 6 7 8 9 10 11 12 | < head > < script src="https://unpkg.com/axios/dist/axios.min.js"></ script > </ head > handleLoad() { var _this = this axios.get('http://127.0.0.1:5000').then(function (res) { console.log(res.data) _this.name = res.data.name _this.age = res.data.age }) } |
补充:axios携带参数
axios.get(地址,{})
axios.post(地址,{},{headers:{token:asdasdf}})
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | // 引入 Axios 库 import axios from "axios"; // 定义 API 地址 const apiUrl = "https://api.example.com/endpoint"; // 替换为实际的 API 地址 // 准备要发送的数据 const requestData = { key1: "value1", // 请求体中的参数1 key2: "value2", // 请求体中的参数2 }; // 准备要添加的自定义头部 const customHeaders = { token: "asdasdf", // 替换为实际的 token 值 }; // 使用 Axios 发送 POST 请求 axios.post(apiUrl, requestData, { headers: customHeaders, // 添加自定义头部 }) .then(response => { // 请求成功时的处理 console.log("响应数据:", response.data); }) .catch(error => { // 请求失败时的处理 console.error("请求失败:", error); }); |
3、fetch
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | # fetch固定格式 fetch('http://example.com/movies.json') .then(function(response) { return response.json(); }) .then(function(myJson) { console.log(myJson); }); < script > let vm = new Vue({ el: '#box', data: { name:'', age: '', }, methods: { handleClick() { fetch('http://127.0.0.1:5000/').then(response => { return response.json() }).then(json => { console.log('从后端获取的json数据', json) // success 获取的数据 this.name = json.name this.age = json.age }).catch(ex => { console.log('出现了异常', ex) // 抛出异常 }) } } }) </ script > |
4、小电影案例
html:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | <! DOCTYPE html> < html lang="en"> < head > < meta charset="UTF-8"> < title >Title</ title > < script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></ script > < script src="https://unpkg.com/axios/dist/axios.min.js"></ script > </ head > < body > < div id="app"> < button @click="handleLoad">点我,加载小电影</ button > < hr > < ul > < li v-for="item in dataList"> < h3 >电影名字:{{item.name}}</ h3 > < h3 >导演:{{item.director}}</ h3 > < p >电影介绍:{{item.synopsis}}</ p > < p >< img :src="item.poster" alt="" height="300px"></ p > </ li > </ ul > </ div > </ body > < script > var vm = new Vue({ el: '#app', data: { dataList: [] }, methods: { handleLoad() { axios.get('http://127.0.0.1:5000/films').then(res => { console.log(res.data) this.dataList = res.data.data.films }) } } }) </ script > </ html > |
flask 后端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import json from flask import Flask, jsonify app = Flask(__name__) @app.route('/films') def films(): with open('./filme.json', 'rt', encoding='utf-8') as f: res = json.load(f) res = jsonify(res) res.headers = {'Access-Control-Allow-Origin': '*'} return res if __name__ == '__main__': app.run() |
原生django:
1 2 3 4 5 6 7 8 9 10 | import json from django.http import HttpResponse, JsonResponse def films(request, *args, **kwargs): with open('filme.json', 'rt', encoding='utf-8') as f: result = json.load(f) res = {'code': 100, 'msg': '查询成功', 'result': result} aa = JsonResponse(res) aa['Access-Control-Allow-Origin'] = '*' return aa |
电影json地址:
https://m.maizuo.com/v5/#/films/nowPlaying
效果:
二、计算属性
计算属性是基于它们的依赖变量进行缓存的
计算属性只有在它的相关依赖变量发生改变时才会重新求值,否则不会变(函数只要页面变化,就会重新运算)
计算属性就像Python中的property,可以把方法/函数伪装成属性
计算属性,必须有返回值
1、基本使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | <! DOCTYPE html> < html lang="en"> < head > < meta charset="UTF-8"> < title >Title</ title > < script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></ script > < script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></ script > </ head > < body > < div id="app"> < h1 >实现输入input中后名字首字母大写</ h1 > < input type="text" v-model="username"> ---> {{ getUpperCase()}} < br > < input type="text" v-model="age">---->{{ age }} < h2 >通过计算属性实现--->当属性用</ h2 > < input type="text" v-model="username1">--->{{ getName }} </ div > </ body > < script > var vm = new Vue({ el: '#app', data: { username: '', age: '', username1: '' }, methods: { getUpperCase() { console.log('函数执行我执行了') return this.username.substring(0, 1).toUpperCase() + this.username.substring(1) } }, computed: { getName() { console.log('计算属性执行了') return this.username1.substring(0, 1).toUpperCase() + this.username1.substring(1) } } }) </ script > </ html > |
补充:计算属性的关键字
在methods中写 computed,下的方法包装成属性。
return this.username1.substring(0, 1).toUpperCase() + this.username1.substring(1) ### username1.substring(0,1)截取第一个字母,.username1.substring(1) :从第二个字母截取到尾部
1 2 3 4 5 6 | computed: { getName() { console.log('计算属性执行了') return this.username1.substring(0, 1).toUpperCase() + this.username1.substring(1) } } |
2、
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <! DOCTYPE html> < html lang="en"> < head > < meta charset="UTF-8"> < title >Title</ title > < script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></ script > </ head > < body > < div id="app"> < input type="text" v-model="search"> < hr > < ul > < li v-for="item in newdataList">{{ item }}</ li > </ ul > </ div > </ body > < script > let vm = new Vue({ el: '#app', data: { search: '', dataList: ['a', 'at', 'atom', 'attoo', 'be', 'beyond', 'cs', 'csrf'], }, computed: { newdataList() { return this.dataList.filter(item => item.indexOf(this.search) >= 0) } } }) </ script > </ html > |
三、监听(侦听)属性
1、关键字 watch
属性如果发生变化,就会执行某个函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | <! DOCTYPE html> < html lang="en"> < head > < meta charset="UTF-8"> < title >Title</ title > < link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"> < script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></ script > < script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.min.js"></ script > < script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></ script > </ head > < body > < div id="app"> < div class="container-fluid"> < div class="row"> < div class="col-md-6 col-md-offset-3"> < div class="text-center"> < span class="btn btn-danger" @click="course_type='0'"> Python课程</ span > < span class="btn btn-danger" @click="course_type='1'"> Go课程</ span > < span class="btn btn-danger" @click="course_type='2'"> Linux课程</ span > </ div > < div > 点击了 {{course_type}} 课程类型 < br > {{course}} 课程 </ div > </ div > </ div > </ div > </ div > </ body > < script > var vm = new Vue({ el: '#app', data: { course: 'python', course_type: '', }, watch: { course_type() { console.log('我变了', this.course_type) if (this.course_type == 0) { this.course = 'python' } else if (this.course_type == 1) { this.course = 'Go' } else { this.course = 'Linux' } } } }) </ script > </ html > |
四、ref属性
ref
属性允许你在 Vue 组件中获取对 DOM 元素或组件实例的引用,从而方便地访问和操作它们。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | <! DOCTYPE html> < html lang="en"> < head > < meta charset="UTF-8"> < title >Title</ title > < script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></ script > </ head > < body > < div id="app"> < h1 >ref属性放在普通标签上</ h1 > < input type="text" v-model="username" ref="myinput"> < br > < img src="http://pic.imeitou.com/uploads/allimg/230331/7-230331110I0.jpg" alt="" height="300px" ref="myimg"> < h1 >ref放在组件上</ h1 > < hr > < lqz ref="mylqz"></ lqz > < hr > < button @click="handleClick">点我执行函数</ button > < br > {{username}} </ div > </ body > < script > var vm = new Vue({ el: '#app', data: { username: '' }, methods: { handleClick() { console.log(this.$refs) // 通过key,取到标签,拿到原生dom,通过dom操作,控制标签 this.$refs.myinput.value = 'lqz' this.$refs.myimg.src='10026.jpg' // 放在组件上---》现在在父组件中,能拿到子组件对象,对象中的属性和方法直接用即可 console.log(this.$refs.mylqz) // this.$refs.mylqz.title = 'sb' // this.username=this.$refs.mylqz.title //this.$refs.mylqz.handleBack() } }, components: { lqz: { template: ` < div > < button @click="handleBack">后退</ button > {{ title }} < button >前进</ button > </ div >`, data() { return { title: "首页" } }, methods: { handleBack() { alert('后退了') } } } } }) </ script > </ html > |
五、Vue生命周期
1、 vue实例有生命周期,每个组件也有这8个生命周期。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # new Vue()---->创建出来---》页面关闭---》被销毁掉----》整个整个过程经历了一个周期----》vue帮咱们提供了一些钩子函数[写了就会执行,不写就不执行],到某个阶段,就会触发某个函数的执行 # 8 个生命周期钩子函数 beforeCreate 创建Vue实例之前调用 created 创建Vue实例成功后调用 beforeMount 渲染DOM之前调用 mounted 渲染DOM之后调用 beforeUpdate 重新渲染之前调用(数据更新等操作时,控制DOM重新渲染) updated 重新渲染完成之后调用 beforeDestroy 销毁之前调用 destroyed 销毁之后调用 # 8个声明周期钩子,什么情况会用到 -created:用的最多,变量初始化完成了(data中得数据),在这里,我们发送ajax请求 -beforeDestroy:组件销毁之前会执行 -组件创建,就执行一个定时任务[每隔1s,打印一个helloworld] -组件销毁,定时任务要销毁,如果定时任务不销毁,会一直执行 |
2、组件也有生命周期
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | <! DOCTYPE html> < html lang="en"> < head > < meta charset="UTF-8"> < title >生命周期</ title > < script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></ script > </ head > < body > < div id="box"> < child v-if="isShow"></ child > < br > < button @click="terminate">删除显示子组件</ button > </ div > </ body > < script > Vue.component('child', { template: ` < div > {{ name }} < button @click="name='lqs'">更新数据1</ button > < button @click="name='asdf'">更新数据2</ button > </ div >`, data() { return { name: 'Darker1', t: null } }, 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) // 启动一个定时器 this.t = setInterval(() => { console.log('asdfasdfasdf') }, 3000) }, 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) }, beforeDestroy() { console.group('当前状态:beforeDestroy') console.log('当前el状态:', this.$el) console.log('当前data状态:', this.$data) console.log('当前name状态:', this.name) clearInterval(this.t) this.t = null }, destroyed() { console.group('当前状态:destroyed') console.log('当前el状态:', this.$el) console.log('当前data状态:', this.$data) console.log('当前name状态:', this.name) }, }) let vm = new Vue({ el: '#box', data: { isShow: true }, methods: { terminate() { this.isShow = !this.isShow }, }, // beforeCreate() { // console.log("vue实例,开始创建了") // console.log(this.isShow) // }, // created() { // console.log("vue实例,创建成功了") // console.log(this.$data) // 数据有了 // console.log(this.$el) // 没有 模板 // }, // beforeMount() { // console.log("vue实例,准备挂载el") // console.log(this.$data) // 数据有了 // console.log(this.$el) //模板有了,但是 插值都没渲染上 // }, // mounted() { // console.log("vue实例,挂载el了") // console.log(this.$data) // 数据有了 // console.log(this.$el) //模板有了,但是 插值都没渲染上 // }, }) // setTimeout(() => { // alert('lqz is handsome') // }, 3000) // // setInterval(()=>{ // console.log('lqz is handsome') // },5000) </ script > </ html > |
六、组件介绍和使用
1、组件就是:扩展 HTML 元素,封装可重用的代码,目的是复用
1 2 3 4 5 6 | 例如:有一个轮播图,可以在很多页面中使用,一个轮播有js,css,html 组件把js,css,html放到一起,有逻辑,有样式,有html #组件的分类: 全局组件:可以放在根中,可以在所有组件中使用 局部组件:只能在当前组件中使用 |
2、定义全局组件
Vue.component('child', template: ``), 中child是自定义的组件名字,<child></child> 表示使用child组件,template模版中存放html页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | < script > //1 定义一个全局组件,vue2中,组件必须在一个标签中 Vue.component('child', { template: ` < div > < button @click="back">后退</ button > {{ title }} < button >前进</ button > </ div > `, data() { return { title: '我是首页' } }, methods: { back() { console.log('退了') } } }) var vm = new Vue({ el: '#app', }) </ script > |
3、定义局部组件
这里lqz是一个自定义的局部组件的名字,<lqz></lqz>是应用局部组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | <! DOCTYPE html> < html lang="en"> < head > < meta charset="UTF-8"> < title >Title</ title > < script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></ script > </ head > < body > < div id="app"> < h1 >组件的使用</ h1 > < lqz ></ lqz > </ div > </ body > < script > var lqz={ template: ` < div > < h1 >我是局部组件</ h1 > < img :src="url" alt="" height="400px"> </ div >`, data() { return { url: 'http://www.qingjv.com/static/upload/image/20221021/1666333229189563.jpg' } }, methods: {} } // 根组件 var vm = new Vue({ el: '#app', data: {}, // 局部组件是定义在某个组件内,可以定义多个,只能在它父组件中使用,不能到别的地方使用 components: { lqz, } }) </ script > </ html > |
小结:
1 2 3 4 5 | # 1 全局组件是使用Vue.component定义的,可以在全局任意组件中使用 # 2 局部组件是定义在某个组件内的:components,只能用在当前组件中 # 3 组件可以嵌套定义和使用 # 扩展:elementui,提供给咱们很多全局组件 |
七、组件间通信
1、父传子: 自定义属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | <! DOCTYPE html> < html lang="en"> < head > < meta charset="UTF-8"> < title >Title</ title > < script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></ script > </ head > < body > < div id="app"> < h1 >组件的使用</ h1 > < hr > < lqz :url="url" :myshow="true"></ lqz > < hr > </ div > </ body > < script > // 2 var lqz = { template: ` < div > < h1 >我是局部组件</ h1 > < img :src="url" alt="" height="400px"> < button @click="handleCheck">点我看myshow类型</ button > </ div >`, data() { return {} }, methods: { handleCheck() { console.log(this.myshow) console.log(typeof this.myshow) } }, props: ['url', 'myshow'] } // 根组件 var vm = new Vue({ el: '#app', data: { url: 'http://pic.imeitou.com/uploads/allimg/230331/7-230331110I0.jpg', }, // 局部组件是定义在某个组件内,可以定义多个,只能在它父组件中使用,不能到别的地方使用 components: { lqz, } }) </ script > </ html > |
props的作用:
-
数据传递:
props
允许父组件将数据传递给子组件。父组件可以通过绑定属性的方式将数据传递给子组件。 -
参数配置: 除了数据,
props
也可以用于配置子组件的行为。父组件可以通过props
向子组件传递配置参数,以影响子组件的行为。 -
动态数据:
props
可以接收动态数据,这意味着父组件可以根据需要动态地更新传递给子组件的数据。 -
数据验证: Vue.js 允许你在子组件中对
props
进行验证,以确保传递的数据满足特定的要求。这有助于提高应用程序的可靠性。
2、子传父: 自定义事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | <! DOCTYPE html> < html lang="en"> < head > < meta charset="UTF-8"> < title >Title</ title > < script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></ script > </ head > < body > < div id="app"> < h1 >组件的使用</ h1 > 接受到的子组件输入的内容是:{{username}} < hr > < lqz @myevent="handelEvent"></ lqz > < hr > </ div > </ body > < script > // 2 var lqz = { template: ` < div > < h1 >我是局部组件</ h1 > < img :src="url" alt="" height="400px"> < br > < input type="text" v-model="username"> < button @click="handleSend">传递到父组件</ button > </ div >`, data() { return { url: 'https://pic2.zhimg.com/v2-ab3bd9cb8ba184b2f12bbfe969036955_r.jpg', username: '' } }, methods: { handleSend() { // 传递给父组件 this.$emit('myevent', this.username) } } } // 根组件 var vm = new Vue({ el: '#app', data: { username: '' }, methods: { handelEvent(username) { console.log('父组件自定义事件的event执行了') console.log(username) this.username = username } }, // 局部组件是定义在某个组件内,可以定义多个,只能在它父组件中使用,不能到别的地方使用 components: { lqz, } }) </ script > </ html > |
补充:
1 子传父的流程
2 $emit
的基本用法和作用:
-
触发自定义事件: 使用
$emit
方法,你可以在 Vue 组件内部触发自定义事件,这个事件可以有任何自定义名称,通常用驼峰命名规则。 -
传递数据: 除了触发事件,你还可以通过
$emit
向事件的监听器传递数据,这些数据可以是任何 JavaScript 数据类型。 -
监听事件: 父组件或其他组件可以使用
v-on
指令(或简写为@
)来监听并响应子组件触发的自定义事件。
这里属于出发自定义的事件,触发事件的同时把username传进去
八、作业记录
1、写一个books接口,带按价格排序,前端页面创建完成,向后端发送请求,获取图书属性,表格显示在前端
后端代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | from .models import Book from rest_framework.viewsets import ModelViewSet from .serializer import BookSerializer from rest_framework.filters import OrderingFilter class BookView(ModelViewSet): queryset = Book.objects.all() serializer_class = BookSerializer filter_backends = [OrderingFilter] ordering_fields = ['id', 'price'] def list(self, request, *args, **kwargs): res = super().list(request, *args, **kwargs) res.headers['Access-Control-Allow-Origin'] = '*' return res ### super().list 中有 return Response(serializer.data) ### 序列化文件 from rest_framework.serializers import ModelSerializer from .models import Book class BookSerializer(ModelSerializer): class Meta: model = Book fields = "__all__" |
前端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | <! DOCTYPE html> < html lang="en"> < head > < meta charset="UTF-8"> < title >Title</ title > < link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"> < script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></ script > < script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.min.js"></ script > < script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></ script > < script src="https://unpkg.com/axios/dist/axios.min.js"></ script > < style > .text-center { text-align: center; } </ style > </ head > < body > < div id="app"> < div class="container-fluid"> < div class="row"> < div class="col-md-6 col-md-offset-3"> < div class="text-center"> < button class="btn btn-primary" @click="handleClick">点我按照价格排序</ button > </ div > < table class="table table-bordered"> < thead > < tr > < th class="text-center">id号</ th > < th class="text-center">图书名字</ th > < th class="text-center">图书价格</ th > </ tr > </ thead > < tbody > < tr v-for="item in books_list"> < th scope="row" class="text-center">{{ item.id }}</ th > < td class="text-center">{{ item.title }}</ td > < td class="text-center">{{ item.price }}</ td > </ tr > </ tbody > </ table > </ div > </ div > </ div > </ div > </ body > < script > let vm = new Vue({ el: '#app', data: { books_list: [], ordering: 'price', url: 'http://127.0.0.1:8000/books/' }, created() { axios.get(this.url).then(res => { console.log(res.data) this.books_list = res.data }) }, methods: { handleClick() { if (this.ordering.indexOf('-') >= 0) { this.ordering = 'price' } else { this.ordering = '-price' } } }, watch: { ordering() { axios.get(this.url+'?ordering='+this.ordering).then( res => { this.books_list = res.data }) } } }) </ script > </ html > |
备注:
1 created()生命周期:创建Vue实例成功后调用。这里vue实例创建后把后端返回的数据赋值给 books_list 列表
2 handleClick 点击事件用来动态给ordering属性赋值
3 watch 监听函数监听ordering的变化,从而修改请求地址的表达
2、定义组件,组件创建成功,向后端发送请求,后端返回一张图片地址,显示在组件上
后端:
1 2 3 4 5 6 7 8 9 | from rest_framework.views import APIView from rest_framework.response import Response class ImageView(APIView): def get(self, request, *args, **kwargs): return Response({'code': 100, 'msg': '成功', 'url': 'http://127.0.0.1:8000/media/11.jpg/'}, headers={'Access-Control-Allow-Origin': '*'}) |
路由:
1 2 3 4 5 6 7 8 9 10 11 12 13 | from django.urls import path from app01.views import ImageView from django.views.static import serve from django.conf import settings urlpatterns = [ path('admin/', admin.site.urls), path('img/', ImageView.as_view()), path('media/< path:path >', serve,{'document_root': settings.MEDIA_ROOT}), ] ## setting中配置 MEDIA_ROOT = os.path.join(BASE_DIR, 'media') |
补充:
1 serve 视图函数用于定位和提供媒体文件的地方。
2 media/<path:path> 这是django3中的5中转换器之一path,转换器允许你在 Django URL 配置中更灵活地捕获不同类型的数据,并将它们传递给视图函数以进行处理。你可以根据你的项目需求选择适当的转换器。
前端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | <! DOCTYPE html> < html lang="en"> < head > < meta charset="UTF-8"> < title >Title</ title > < link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"> < script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></ script > < script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.min.js"></ script > < script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></ script > < script src="https://unpkg.com/axios/dist/axios.min.js"></ script > </ head > < body > < div id="app"> < h1 >组件</ h1 > 路径:{{a}} < hr > < lqz @myevent="handelEvent"> </ lqz > < hr > </ div > </ body > < script > var vm = new Vue({ el: '#app', data: { a: '' }, components: { lqz: { template: ` < div > < h1 >这是请求的一张图片</ h1 > < img :src="url" alt="" height="300px"> < br > < button @click="handleSend">传递到父组件</ button > </ div > `, data() { return { url: '' } }, created() { axios.get('http://127.0.0.1:8000/img/').then(res => { console.log(res) this.url = res.data.url }) }, methods: { handleSend() { this.$emit('myevent', this.url) } } } }, methods: { handelEvent(url) { this.a = url } } }) </ script > </ html > |
效果: