74、计算属性、监听(侦听)属性、Vue生命周期、组件介绍和使用、组件间通信、ref属性

115 阅读6分钟

计算属性

1.计算属性是基于它们的依赖变量进行缓存的
2.计算属性只有在它的相关依赖变量发生改变时才会重新求值,否则不会变(函数只要页面变化,就会重新运算)
3.计算属性就像Python中的property,可以把方法/函数伪装成属性
4.计算属性函数,必须有返回值
	作用:延缓计算:跟它相关联的变量发生变化,它才会重新运算
  方法烦属性用,可以被for循环,if判断

基本使用

效果:实现输入input中后名字首字母大写

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src='./js/vue.js'></script>
</head>
<body>
<div id='app'>
    <p> 用户名:<input type="text"  v-model="username">---->{{ username.substring(0, 1).toUpperCase() + username.substring(1) }}</p>

    <p>用户名1:<input type="text" v-model="username1">---->{{ First_Upper() }}</p>
    <p>通过计算属性实现--->当属性用</p>
    <p>用户名2:<input type="text" v-model="username2">---->{{ getName}}</p>

</div>

</body>
<script>
    var vue = new Vue({
        el: '#app',
        data: {
            username: '',
            username1: '',
            username2: '',
        },
        methods: {
            First_Upper() {
                console.log('函数执行了')
                return this.username1.substring(0, 1).toUpperCase() + this.username1.substring(1)
            }
        },
        computed:{
            getName(){
                console.log('计算属性执行了')
                return this.username2.substring(0, 1).toUpperCase() + this.username2.substring(1)
            }

        }
    })
</script>
</html>

重写过滤案列

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
    <input type="text" v-model="search" @input="handleInput">
    <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'],
            newdataList: ['a', 'at', 'atom', 'attoo', 'be', 'beyond', 'cs', 'csrf'],
        },
        methods: {

            handleInput() {
                this.newdataList = this.dataList.filter(item => item.indexOf(this.search) >= 0)
            }
        }

    })
</script>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/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>

监听(侦听)属性

属性如果发生变化,就会执行某个函数(当watch的变亮发生变化,就会触发函数的执行)

<!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>
    <input type="text" v-model="username"> -->{{username}}
    
</div>

</body>
<script>
    var vm = new Vue({
        el:'#app',
        data:{
            username:''
        },
        watch:{
            username(newValue,oldValue){
                console.log('新值',newValue)
                console.log('旧值',oldValue)
                console.log('我发生了变化')
            }
    }
    })
</script>
</html>

监听事件.png

Vue生命周期

1.new Vue()---->创建出来--->页面关闭--->被销毁掉---->整个整个过程经历了一个周期---->vue帮咱们提供了一些钩子函数[写了就会执行,不写就不执行],到某个阶段,就会触发某个函数的执行

官网图片+理解

vue生命周期.jpeg

Vue生命周期

钩子函数描述
beforeCreate创建Vue实例之前调用
created创建Vue实例成功后调用(可以在此处发送异步请求后端数据)
beforeMount渲染DOM之前调用
mounted渲染DOM之后调用
beforeUpdate重新渲染之前调用(数据更新等操作时,控制DOM重新渲染)
updated重新渲染完成之后调用
beforeDestroy销毁之前调用
destroyed销毁之后调用
<!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>
    <input type="text" v-model="username">-->{{username}}

</div>
</body>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            username: ''
        },
        beforeCreate() {
            console.log('beforeCreate执行了')
        },
        created() {
            console.log('created执行了')
        },
        beforeMount() {
            console.log('beforeMount执行了')
        },
        mounted() {
            console.log('mounted执行了')
        },
        beforeUpdate() {
            console.log('beforeUpdate执行了')
        },
        updated() {
            console.log('updated执行了')
        },
        beforeDestroy() {
            console.log('beforeDestroy执行了')
        },
        destroyed() {
            console.log('destroyed执行了')
        },
    })

</script>
</html>

案例 生命周期.png

为了演示beforeDestroy,destroyed的执行借助组件

补充:组件

vue实例有生命周期,每个组件也有这8个生命周期

<script>
    //组件有自己的html,cxx,js,事件等等
    //``模版字符串,是es6的语法
    //在组件中,data必须是一个函数,返回对象
    //1.定义一个全局组件
    Vue.component('child',{
        template:``,
        data(){ 
            return {}
        },
        methods:{
        },
    })
</script>

效果:点击按钮,就显示组件

<!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>
    <button @click="handleShow" >显示组件,隐藏组件</button>
    <hr>
    <child v-if="show"></child>
    <hr>
</div>

</body>
<script>
    Vue.component('child',{
        template:`    <div>
        <button @click="back">后退</button>
        {{name}}
        <button @click="forword">前进</button>
    </div>`,
        data(){
            return {
                name:'首页'
            }
        },
        methods:{
           back(){
               alert('后退了')
           } ,
            forword(){
               alert('前进了')
            }
        },
    })
    var vm = new Vue({
        el: '#app',
        data: {
            username: '',
            show:false
        },
        methods: {
           handleShow(){
               this.show = !this.show
           }
        },
    })
</script>
</html>

利用组件演示Vue生命周期

1.created:用的最多,变量初始化完成了(data中得数据),在这里,我们发送ajax请求
2.beforeDestroy:组件销毁之前会执行,主要做资源清理工作
	组件创建,就执行一个定时任务[每隔1s,打印一个helloworld]
	组件销毁,定时任务要销毁,如果定时任务不销毁,会一直执行
<!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>
    <input type="text" v-model="username">-->{{username}}

    <h1>使用组件</h1>
    <button @click="handleShow">显示组件,隐藏组件</button>
    <hr>
    <child v-if="show"></child>
    <hr>
</div>

</body>
<script>
    //组件有自己的html,cxx,js,事件等等
    //``模版字符串,是es6的语法
    //在组件中,data必须是一个函数,返回对象
    //1.定义一个全局组件
    Vue.component('child', {
        template: `
          <div>
          <button @click="back">后退</button>
          {{ name }}
          <button @click="forword">前进</button>
          </div>`,
        data() {
            return {
                name: '首页',
                t :null,
            }
        },
        methods: {
            back() {
                alert('后退了')
            },
            forword() {
                alert('前进了')
            }
        },
        beforeCreate() {
            console.log('beforeCreate执行了')
            console.log(this) //VueComponent
            console.log('当前el状态:', this.$el)
            console.log('当前data状态:', this.$data)
            console.log('当前name状态:', this.name)
        },
        created() {
            console.log('created执行了')
            console.log(this)
            console.log('当前el状态:', this.$el)
            console.log('当前data状态:', this.$data)
            console.log('当前name状态:', this.name)

            //启动一个定时器
            this.t = setInterval(() =>{
                console.log('helloword')
            },1000)
        },
        beforeMount() {
            console.log('beforeMount执行了')
            console.log(this)
            console.log('当前el状态:', this.$el)
            console.log('当前data状态:', this.$data)
            console.log('当前name状态:', this.name)

        },
        mounted() {
            console.log('mounted执行了')
            console.log('当前el状态:', this.$el)
            console.log('当前data状态:', this.$data)
            console.log('当前name状态:', this.name)

        },
        beforeUpdate() {
            console.log('beforeUpdate执行了')
            console.log('当前el状态:', this.$el)
            console.log('当前data状态:', this.$data)
            console.log('当前name状态:', this.name)
        },
        updated() {
            console.log('updated执行了')
            console.log('当前el状态:', this.$el)
            console.log('当前data状态:', this.$data)
            console.log('当前name状态:', this.name)
        },
        beforeDestroy() {
            console.log('beforeDestroy执行了')
            console.log('当前el状态:', this.$el)
            console.log('当前data状态:', this.$data)
            console.log('当前name状态:', this.name)

            //销毁定时器
            clearInterval(this.t)
            this.t = null
        },
        destroyed() {
            console.log('destroyed执行了')
            console.log('当前el状态:', this.$el)
            console.log('当前data状态:', this.$data)
            console.log('当前name状态:', this.name)
        },
    })

    var vm = new Vue({
        el: '#app',
        data: {
            username: '',
            show: false
        },
        methods: {
            handleShow() {
                this.show = !this.show

            }
        },
    })

</script>
</html>

组件介绍和使用

1.组件:就是扩展 HTML 元素,封装可重用的代码,目的是复用
	例如:有一个轮播图,可以在很多页面中使用,一个轮播有js,css,html
		组件把js,css,html放到一起,有逻辑,有样式,有html
    
2.组件的分类:
    全局组件:可以放在根中,可以在所有组件中使用
    局部组件:只能在当前组件中使用

定义全局组件

1.定义一个全局组件:Vue.component(类似于自定义的标签名,{}),在{}里面写template、data、methods等
2.在全局任意位置使用
<!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>
    <hr>
    <child></child>
    <hr>

    <h1>第二次出现</h1>
    <child></child>
</div>

</body>

<script>
    //1  定义一个全局组件,vue2中,组件必须在一个标签中
    Vue.component('child',{
        template:`
            <div>
        <button @click="back">后退</button>
        {{name}}
        <button @click="forword">前进</button>
    </div>
        `,
        data(){
            return {
                name:'首页',
            }
        },
        methods:{
            back(){
                alert('后退了')
            },
            forword(){
                alert('前进了')
            }
        },

    })
  
    var vm = new Vue({
        el:'#app',
    })
</script>
</html>

定义局部组件

1.局部组件是定义在某个组件内,可以定义多个,只能在它父组件中使用,不能在别的地方使用
2.components写在父组件内,里面写template、data、methods等
<!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>
    <child></child>
</div>

</body>
<script>
    var child = {
        template:`    <div>
        <h2>我是局部组件</h2>
        <img :src="url" alt="" height="300px">
    </div>`,
        data(){
            return {
                url:'./img/3.jpg'
            }
        },
        methods:{},
    }
    //根组件
    var vm = new Vue({
        el:'#app',
        data:{},
        //局部组件是定义在某个组件内,可以定义多个,只能在它父组件中使用,不能在别的地方使用
        components:{
            child,
        }
    })

</script>

</html>

全局组件和局部组件

<!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>
    <hr>
    <child></child>
    <hr>
    <hr>
    <part_components></part_components>
    <hr>
</div>
</body>
<script>
    //全局组件
    Vue.component('child', {
        template: `
          <div>
          <h1>全局组件</h1>
          <button @click="back">后退</button>
          {{ name }}
          <button @click="forword">前进</button>
          </div>`,
        data() {
            return {
                name: '首页'
            }
        },
        methods: {
            back() {
                alert('后退了')
            },
            forword() {
                alert('前进了')
            }
        },
    })
    //局部组件
    var part_components = {
        template: `    <div>
        <h1>局部组件</h1>
        <img :src="img" alt="" height="400px">
    </div>`,
        data() {
            return {
                img:'./img/4.jpg'
            }
        },
        methods: {}
    }

    var vue = new Vue({
        el: '#app',
        data: {},
        methods: {},
        //局部组件
        components: {part_components,},
    })
</script>
</html>

总结

1.全局组件是使用Vue.component定义的,可以在全局任意组件中使用
2.局部组件是定义在某个组件内的:components,只能用在当前组件中
3.组件可以嵌套定义和使用
4.扩展:elementui,提供给咱们很多全局组件

组件间通信

1.父组件把数据传递给子组件
    1.需要自定义属性
      1.在子组件中自定义属性,使用属性指令绑定父组件的变量
    	<part_components :myshow="true" :url="url"></part_components>
    	父组件里的data:url:'./img/5.jpg'
      2.在子组件中,使用props接受 ['属性名','属性名2']
      	"""
      	限制属性类型:props: {myshow: Boolean, url: String}
      	"""
      3.在子组件中,使用属性名即可
2.子组件把数据传递给父组件
    1.需要自定义事件
			1.父组件中自定义事件
    		<part_components @myevent="handelEvent"></part_components>
			2.子组件中只要执行 this.$emit('myevent'),就会触发自定义事件对应的函数
      	父组件methods:
                methods:{
            handelEvent(username){
                console.log('父组件自定义事件的event执行了')
                console.log(username)
                this.username = username
            }

组件间通信之父传子

<!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>
    <part_components :myshow="true" :url="url"></part_components>
</div>


</body>
<script>

    var part_components={
        template: `
          <div>
          <h1>局部组件</h1>
          <img :src="url" alt="" width="300px">
          <button @click="handleCheck" >点我看myshow类型</button>
          </div>`,
        data(){
            return {
            }

        },
        methods: {
            handleCheck(){
                console.log(this.myshow)
                console.log(typeof this.myshow)  //boolean
            }
        },
        props:['url','myshow']

    }
    var vue = new Vue({
        el:'#app',
        data:{
            url:'./img/5.jpg'
        },
        methods:{},
        components:{
            part_components,
        }
    })
</script>
</html>

父传子.png

组件间通信之子传父

<!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>
    接收到的子组件输入的内容是:{{username}}
    <hr>
    <part_components @myevent="handelEvent"></part_components>
    <hr>
</div>
</body>
<script>

    var part_components={
        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:'./img/6.jpeg',
                username:''
            }

        },
        methods: {
            handleSend(){
                //传递给父组件
                console.log(this)
                this.$emit('myevent',this.username)
            }
            }
        }

    var vue = new Vue({
        el:'#app',
        data:{
            username:'',

        },
        methods:{
            handelEvent(username){
                console.log('父组件自定义事件的event执行了')
                console.log(username)
                this.username = username
            }
        },
        components:{
            part_components,
        }
    })
</script>
</html>

补充

1.以后前后端分离
	1.前端是前端(小程序);后端是后端,完全没联系
	2.后端只写接口,没有template和static
	3.media 要有

ref属性

1.ref属性,vue提供的,写在标签上
	1.可以写在普通标签:在vue中使用 this.$refs.名字:拿到dom对象,可以原生操作
  	eg:
      this.$refs.myinput.value = 'nana'
      this.$refs.myimg.src='./img/1.jpg'
  2.可以写在组件上:在vue中使用 this.$refs.名字:拿到[组件]对象,组件属性,方法直接使用即可

写在普通标签上

<!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>ref属性放在普通标签上</h1>
    <input type="text" v-model="username" ref = 'myinput'>--->{{username}}
    <br>
    <img src="./img/3.jpg" alt="" ref="myimg" height="300px">
    <button @click="handleClick">点我执行函数</button>
</div>
 </body>
<script>
    var vm = new Vue({
        el:'#app',
        data:{
            username:'',
        },
        methods:{
            handleClick(){
                console.log(this) //Vue
                console.log(this.$refs) //{myinput: input, myimg: img}
                //通过key,取到标签,拿到原生dom,通过dom操作,控制标签
                this.$refs.myinput.value = 'nana'
                this.$refs.myimg.src='./img/1.jpg'
            }
        },

    })
</script>
</html>

写在组件上

<!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>ref属性放在组件上</h1>
    <hr>
    <part_components ref="myref"></part_components>
    <hr>
    <button @click="handleClick">点我执行函数</button>
    {{username}}
</div>
</body>
<script>
    var part_components={
        template:`                  <div>
                  <button @click="handleBack">后退</button>
                  {{ title }}
                  <button>前进</button>
                  </div>`,
        data(){
            return {title:'首页'}
        },
        methods: {
            handleBack(){
                alert('后退了')
            }
        },

    }
    var vm = new Vue({
        el:'#app',
        data:{
            username:'',
        },
        methods:{
            handleClick(){
                console.log(this) //Vue
                console.log(this.$refs) //{myref: VueComponent}
                //放在组件上:在父组件中,能拿到子组件的兑现个,对象中的属性和方法直接用即可
                console.log(this.$refs.title)
                this.$refs.myref.title = 'nana'
                this.username = this.$refs.myref.title
                this.$refs.myref.handleBack()

            }
        },
        components:{
            part_components,
        }

    })
</script>
</html>

作业

1.购物车使用计算属性,过滤案例使用计算属性
2.写一个books接口,带按价格排序,前端页面创建完成,向后端发送请求,获取图书属性,表格显示在前端
	前端使用监听属性实现点击价格正序和倒序排列
3.定义组件,组件创建成功,向后端发送请求,后端返回一张图片地址,显示在组件上
	1 网络图片
  2 media下的图片

4 在上面的子组件就中写一个按钮,点击按钮,把子组件的图片地址,传递到父组件中打印出来(alert)

购物车使用计算属性

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src='https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js'></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"
            integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd"
            crossorigin="anonymous"></script>
    <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css"
          integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
    <script src='./js/vue.js'></script>
</head>
<body>
<div id='app'>
    <div class='container-fluid'>
        <div class='row'>
            <div class='col-md-6 col-md-offset-3'>
                <h1 class='text-center'> 购物车表格</h1>
                <div class="bs-example" data-example-id="hoverable-table">
                    <table class="table table-hover">
                        <thead>
                        <tr>
                            <th>商品id</th>
                            <th>商品名称</th>
                            <th>商品价格</th>
                            <th>商品数量</th>
                            <th>全选/不全选
                                <input type="checkbox" v-model="check_all" @change="handelcheckall"></th>
                            <th>操作</th>
                        </tr>
                        </thead>
                        <tbody>
                        <tr v-for="goods in good_list">
                            <th scope="row">{{goods.id}}</th>
                            <td>{{goods.name}}</td>
                            <td>{{goods.price}}</td>
                            <td>
                                <button class='btn' @click="handeljian(goods)">-</button>
                                {{goods.number}}
                                <button class='btn' @click="goods.number++">+</button>
                            </td>
                            <td>
                                <input type="checkbox" v-model="checkGroup" :value="goods" @change="handelcheckone">

                            </td>
                            <td>
                                <input type="button" class='btn btn-danger' value='删除' @click="del_goods(goods)">
                            </td>

                        </tr>
                        </tbody>
                    </table>
                    <h3>
                        合计:{{get_price}}
                    </h3>
                    <hr>
                    选中物品:{{checkGroup}}-->全选:{{check_all}}

                </div>
            </div>
        </div>
    </div>

</div>

</body>
<script>
    var vue = new Vue({
        el: '#app',
        data: {
            good_list: [
                {id: 1, name: '钢笔', price: 12, number: 2},
                {id: 2, name: '脸盆', price: 20, number: 20},
                {id: 3, name: '毛笔', price: 6, number: 9},
                {id: 4, name: '圆珠笔', price: 8, number: 5},
                {id: 5, name: '铅笔', price: 1, number: 3},],
            checkGroup: [],
            check_all: false
        },
        methods: {

            handelcheckall() {
                // 全选中:对钩都打上,js中得含义是:checkGroup变量满值
                if (this.check_all) {
                    this.checkGroup = this.good_list
                } else {
                    this.checkGroup = []
                }
            },
            handelcheckone() {
                // 判断 checkGroup的长度,是否等于good_list长度
                if (this.checkGroup.length != this.good_list.length) {
                    this.check_all = false
                } else {
                    this.check_all = true
                }
            },
            handeljian(goods){
                if (goods.number >1){
                    goods.number -=1
                }else {
                    alert('不能在减了')
                }
            },
            del_goods(goods){
                this.good_list.pop((goods.id)-1)
            }
        },
        computed:{
            //总价格  -->循环列表-->价格*数量
            get_price(){
                sum = 0
                for (goods of this.checkGroup) {
                    sum += goods.price * goods.number

                }
                return sum
            }
        }
    })
</script>
</html>

写一个books接口

需求:带按价格排序,前端页面创建完成,向后端发送请求,获取图书属性,表格显示在前端,前端使用监听属性:实现点击价格正序和倒序排列

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src='https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js'></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"
            integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd"
            crossorigin="anonymous"></script>
    <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css"
          integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
    <script src='./js/vue.js'></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id='app'>
    <div class="container-fluid">
        <div class="row">
            <div class='col-md-6 col-md-offset-3'>
                <h1 class='text-center'>图示展示</h1>
                <button class="btn btn-success" @click="showBook">展示书籍</button>
                <button class="btn btn-success" @click = 'changClick'>{{zheng ? '倒叙' : '正序'}}</button>


                <table class="table table-hover table-striped" v-show="is_show">

                    <thead>
                    <tr>
                        <th>id</th>
                        <th>图书名字</th>
                        <th>图书价格</th>

                    </tr>
                    </thead>
                    <tbody>
                    <tr v-for="book in book_list">
                        <th scope="row">{{book.id}}</th>
                        <td>{{book.name}}</td>
                        <td>{{book.price}}</td>

                    </tr>

                    </tbody>
                </table>
            </div>
        </div>
    </div>
</div>
</body>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            is_show: false,
            book_list: [],
            zheng: true,
        },
        methods: {
            showBook() {
                this.is_show = true
                axios.get('http://127.0.0.1:8000/books/').then(res => {
                    console.log(res.data)
                    this.book_list = res.data
                })

            },
            changClick(){
                this.zheng =!this.zheng
            }
        },
        watch: {
            zheng:function() {
                if (this.zheng) {
                    //倒叙
                    axios.get('http://127.0.0.1:8000/books/?ordering=-price').then(res => {
                        console.log(res.data)
                        this.book_list = res.data
                    })

                } else {
                    //正序
                    axios.get('http://127.0.0.1:8000/books/?ordering=price').then(res => {
                        console.log(res.data)
                        this.book_list = res.data
                    })
                }
            }
        }
    })
</script>
</html>
from django.shortcuts import render

# Create your views here.
from .models import Book
from .serializer import BookSerializer

from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin
from rest_framework.response import Response
from rest_framework.filters import OrderingFilter
class BookView(GenericViewSet,ListModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    filter_backends=[OrderingFilter]
    ordering_fields = ['price']

    def get(self,request):
        obj = self.list(request)

        return Response(obj.data,headers={'Access-Control-Allow-Origin':'*'})

定义组件,组件创建成功,向后端发送请求,后端返回一张图片地址,显示在组件上(网络图片;media下的图片)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src='./js/vue.js'></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id='app'>
    <h1>父组件</h1>
    <button @click="get_img">父组件接收图片:</button>
    <img :src="img" alt="" height="300px">

    <hr>
    <child :my_img="img" ></child>
</div>
</body>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            img: '',
            is_show:true
        },
        methods: {
            get_img() {
                axios.get('http://127.0.0.1:8000/get_img/').then(res => {
                    console.log(res.data, typeof res.data)
                    this.img = res.data.url

                })
                

            },
        },
        components: {child:{
            template: `
              <div>
              <h1>组件</h1>
              <img :src="my_img" alt="" height="300px">
              </div>`,
            props: ["my_img"],

        }}
    })
</script>
</html>
from django.http import JsonResponse
def get_img(request):
    url='https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F5da5a7c4-e8ef-4975-8581-81e42fdba317%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1688648650&t=cfe8b5c2fa170e2a7d4815454cd7956a'
    obj = JsonResponse({'url':url})
    obj.headers['Access-Control-Allow-Origin'] ='*'
    return obj

media

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src='./js/vue.js'></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id='app'>
    <h1>父组件</h1>
    <button @click="get_img">父组件接收图片:</button>
    <img :src="img" alt="" height="300px">

    <hr>
    <child :my_img="img" ></child>


</div>

</body>

<script>
    
    var vm = new Vue({
        el: '#app',
        data: {
            img: '',
            is_show:true
        },
        methods: {
            get_img() {
                this.img='http://127.0.0.1:8000/media/img/1.jpg'
            },
        },
        components: {child:{
            template: `
              <div>
              <h1>组件</h1>
              <img :src="my_img" alt="" height="300px">
              </div>`,
            props: ["my_img"],
        }}

    })

</script>
</html>
from django.contrib import admin
from django.urls import path,re_path
from app01.views import BookView,get_img
from django.views.static import serve
from django.conf import settings

urlpatterns = [
    path('admin/', admin.site.urls),
    path('books/', BookView.as_view({'get':'get'})),
    path('get_img/', get_img),
    re_path(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}),
]