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()

            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)

<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)

<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}})

// 引入 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

# 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:

<!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 后端:

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:

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

JSON在线解析及格式化验证 - JSON.cn

效果:

二、计算属性

计算属性是基于它们的依赖变量进行缓存的
计算属性只有在它的相关依赖变量发生改变时才会重新求值,否则不会变(函数只要页面变化,就会重新运算)
计算属性就像Python中的property,可以把方法/函数伪装成属性
计算属性,必须有返回值

1、基本使用

<!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) :从第二个字母截取到尾部

  computed: {
            getName() {
                console.log('计算属性执行了')
                return this.username1.substring(0, 1).toUpperCase() + this.username1.substring(1)
            }
        }

2、重写过滤案例

<!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

属性如果发生变化,就会执行某个函数

<!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 元素或组件实例的引用,从而方便地访问和操作它们。

<!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个生命周期。

# 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、组件也有生命周期

<!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 元素,封装可重用的代码,目的是复用

例如:有一个轮播图,可以在很多页面中使用,一个轮播有js,css,html
组件把js,css,html放到一起,有逻辑,有样式,有html

#组件的分类:
    全局组件:可以放在根中,可以在所有组件中使用
    局部组件:只能在当前组件中使用

2、定义全局组件

Vue.component('child', template: ``), 中child是自定义的组件名字,<child></child> 表示使用child组件,template模版中存放html页面

<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>是应用局部组件

<!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 全局组件是使用Vue.component定义的,可以在全局任意组件中使用
# 2 局部组件是定义在某个组件内的:components,只能用在当前组件中
# 3 组件可以嵌套定义和使用

# 扩展:elementui,提供给咱们很多全局组件

七、组件间通信

1、父传子: 自定义属性

<!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的作用:

  1. 数据传递: props 允许父组件将数据传递给子组件。父组件可以通过绑定属性的方式将数据传递给子组件。

  2. 参数配置: 除了数据,props 也可以用于配置子组件的行为。父组件可以通过 props 向子组件传递配置参数,以影响子组件的行为。

  3. 动态数据: props 可以接收动态数据,这意味着父组件可以根据需要动态地更新传递给子组件的数据。

  4. 数据验证: Vue.js 允许你在子组件中对 props 进行验证,以确保传递的数据满足特定的要求。这有助于提高应用程序的可靠性。

2、子传父: 自定义事件

<!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 的基本用法和作用:

  1. 触发自定义事件: 使用 $emit 方法,你可以在 Vue 组件内部触发自定义事件,这个事件可以有任何自定义名称,通常用驼峰命名规则。

  2. 传递数据: 除了触发事件,你还可以通过 $emit 向事件的监听器传递数据,这些数据可以是任何 JavaScript 数据类型。

  3. 监听事件: 父组件或其他组件可以使用 v-on 指令(或简写为 @)来监听并响应子组件触发的自定义事件。

 这里属于出发自定义的事件,触发事件的同时把username传进去

八、作业记录

1、写一个books接口,带按价格排序,前端页面创建完成,向后端发送请求,获取图书属性,表格显示在前端

前端使用监听属性实现点击价格正序和倒序排列 

后端代码:

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__"

前端:

<!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 media下的图片 

后端:

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': '*'})

路由:

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 配置中更灵活地捕获不同类型的数据,并将它们传递给视图函数以进行处理。你可以根据你的项目需求选择适当的转换器。

前端:

<!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>

效果:

 

 
 
 
posted @ 2023-09-19 15:50  凡人半睁眼  阅读(8)  评论(0编辑  收藏  举报