Loading

Vue生命周期及组件

Vue 生命周期钩子

  • 钩子函数的由来

    每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。

    通俗的理解,Vue对象管理一个标签,把数据渲染到指定的位置,就好比你是这条街的城管就管这条街,后期的组件也是如此,对象管理某一个html片段;

  • 生命周期钩子函数

    创建前后,渲染前后,更新前后,销毁前后共八个

    钩子函数 描述
    beforeCreate 创建Vue实例之前调用
    created 创建Vue实例成功后调用(可以在此处发送异步请求后端数据)
    beforeMount 渲染DOM之前调用,虚拟DOM挂载前
    mounted 渲染DOM之后调用,虚拟DOM挂载后,看到页面
    beforeUpdate 重新渲染之前调用(数据更新等操作时,控制DOM重新渲染)
    updated 重新渲染完成之后调用
    beforeDestroy 销毁之前调用
    destroyed 销毁之后调用

    比如 created 钩子可以用来在一个实例被创建之后执行代码:

    new Vue({
      data: {
        a: 1
      },
      created: function () {
        // `this` 指向 vm 实例
        console.log('a is: ' + this.a)
      }
    })
    // => "a is: 1"
    

    也有一些其它的钩子,在实例生命周期的不同阶段被调用,如 mounted、updated 和 destroyed。生命周期钩子的 this 上下文指向调用它的 Vue 实例。

    不要在选项 property 或回调上使用箭头函数,比如 created: () => console.log(this.a) 或 vm.$watch('a', newValue => this.myMethod())。因为箭头函数并没有 this,this 会作为变量一直向上级词法作用域查找,直至找到为止,经常导致 Uncaught TypeError: Cannot read property of undefined 或 Uncaught TypeError: this.myMethod is not a function 之类的错误。
    

    注意

    • created创建出实例,才能发送请求从后端获取数据
    • mounted可以设置定时任务,延迟任务···
    • beforeDestroy设置取消定时任务···
  • 生命周期图示

    image

  • 钩子函数测试

    Vue对象没法看见效果过程, 定义一个组件来测试.
    钩子函数与参数同级.
    console.group()分组展示
    console.groupEnd() 结束分组
    
    this.属性   查看当前对象data属性中定义属性值.
    this.$属性, 查看当前对象的属性,
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Vue生命周期</title>
        <script src="js/vue.js"></script>
    </head>
    <body>
    
    <div id="app">
        <button @click="headerClick">组件(添加/删除)</button>
        <model1 v-if="is_show">展示组件</model1>
    </div>
    </body>
    <script>
        // 定义Vue对象 --作用--> 调用组件
        var vm = new Vue({
            el: '#app',
            data: {
                // 组件的开关
                is_show: false,
            },
            // 组件绑定的点击事件
            methods: {
                headerClick() {
                    // 一点开, 再点关
                    this.is_show = !this.is_show
                }
            }
        })
    
        // 定义组件
        Vue.component('model1',
            {
                template: `
                  <div>
                  <p>我的名字: {{ name }}</p>
                  <p>
                    <button @click="vary">点击修改名字</button>
                  </p>
                  </div>
                `,
    
                // 定义组件的变量
                data() {
                    return {
                        name: 'kid'
    
                    }
                },
    
                // 定义组件的方法
                methods: {
                    vary() {
                        this.name = 'qq'
                    },
    
    
                },
                 beforeCreate() {
                        console.group('当前状态:beforeCreate')
                        console.log('当前el状态:', this.$el)
                        console.log('当前data状态:', this.$data)
                        console.log('当前name状态:', this.name)
                        console.groupEnd()
                    },
                    created() {
                        console.group('当前状态:created')
                        console.log('当前el状态:', this.$el)
                        console.log('当前data状态:', this.$data)
                        console.log('当前name状态:', this.name)
                        console.groupEnd()
                    },
                    beforeMount() {
                        console.group('当前状态:beforeMount')
                        console.log('当前el状态:', this.$el)
                        console.log('当前data状态:', this.$data)
                        console.log('当前name状态:', this.name)
                        console.groupEnd()
                    },
                    mounted() {
                        console.group('当前状态:mounted')
                        console.log('当前el状态:', this.$el)
                        console.log('当前data状态:', this.$data)
                        console.log('当前name状态:', this.name)
                        console.groupEnd()
    
                    },
                    beforeUpdate() {
                        console.group('当前状态:beforeUpdate')
                        console.log('当前el状态:', this.$el)
                        console.log('当前data状态:', this.$data)
                        console.log('当前name状态:', this.name)
                        console.groupEnd()
                    },
                    updated() {
                        console.group('当前状态:updated')
                        console.log('当前el状态:', this.$el)
                        console.log('当前data状态:', this.$data)
                        console.log('当前name状态:', this.name)
                        console.groupEnd()
                    },
                    beforeDestroy() {
                        console.group('当前状态:beforeDestroy')
                        console.log('当前el状态:', this.$el)
                        console.log('当前data状态:', this.$data)
                        console.log('当前name状态:', this.name)
                        console.groupEnd()
                    },
                    destroyed() {
                        console.group('当前状态:destroyed')
                        console.log('当前el状态:', this.$el)
                        console.log('当前data状态:', this.$data)
                        console.log('当前name状态:', this.name)
                        console.groupEnd() 
                    },
            }
        )
    </script>
    </html>
    
    • 添加组件展示:

      image
    • 组件数据更新:

      image
    • 没建任务, 没有任务销毁, 看不到实际的效果.

      image
    • 创建定时任务销毁定时任务

      1. mounted钩子函数中创建任务
      2. beforeDestroy钩子函数重销毁创建的任务
      
      setInterval: 定时执行,每秒钟打印一下信息.
      
      组件销毁, 清理定时器
      clearInterval(this.f)
      this.f = null
      
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>Vue生命周期</title>
          <script src="js/vue.js"></script>
      </head>
      <body>
      
      <div id="app">
          <button @click="headerClick">组件(添加/删除)</button>
          <model1 v-if="is_show">展示组件</model1>
      </div>
      </body>
      <script>
          // 定义Vue对象 --作用--> 调用组件
          var vm = new Vue({
              el: '#app',
              data: {
                  // 组件的开关
                  is_show: false,
              },
              // 组件绑定的点击事件
              methods: {
                  headerClick() {
                      // 一点开, 再点关
                      this.is_show = !this.is_show
                  }
              }
          })
      
          // 定义组件
          Vue.component('model1',
              {
                  template: `
                    <div>{{text}}</div>
                  `,
      
                  // 定义组件的变量
                  data() {
                      return {
                          // 定义一个变量接收函数
                          func: null,
                          text: '打印信息中'
                      }
                  },
      
                  // 定义一个定时任务
                  mounted() {
                      //  匿名箭头函数
                      this.func = setInterval(()=>{
                          console.log('hello word!')
                      }, 1000)
      
                  },
      
                  // 销毁定时任务
                  beforeDestroy() {
                      // 清除定时任务
                      clearInterval(this.func)
                      // 清除值
                      this.func = null
                  },
              }
          )
      </script>
      </html>
      
      image

Vue与后端交互

  • 三种前后端交互方式

    • jquery的ajax方法发送请求(基本不用了)
    • js官方提供的fetch方法(原来XMLHttpRequest)(官方的,用的也少)
    • axios第三方,做ajax请求(推荐)
      # ajax:异步的xml请求,前后端交互就是xml格式,随着json格式发展,目前都是使用json格式
      # jquery的ajax方法   $.ajax()  方法---》只是方法名正好叫ajax
      # js原生可以写ajax请求,非常麻烦,考虑兼容性---》jquery
      

      示例

      • 后端
        from flask import Flask,make_response
        
        app = Flask(__name__)
        @app.route('/')
        def index():
        
            obj = make_response('Hello Vue!')
            # 处理跨域
            obj.headers['Access-Control-Allow-Origin'] = '*'
            return obj
        
        if __name__ == '__main__':
            app.run()
        
      • 前端
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>Title</title>
            <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
            <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
            <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
        
        </head>
        <body>
        <div id="app">
          <p style="font-size: 48px;align-content: center"> 从后端拿到的数据--->{{text}}</p>
        </div>
        
        </body>
        <script>
        
            var vm = new Vue({
                el: '#app',
                data: {
                    text: '',
                },
                created() {
                    // 方式一:
                    //向后端发请求,拿数据,拿回来赋值给text
                    $.ajax({
                        url:'http://127.0.0.1:5000/',
                        type:'get',
                        success: (data)=>{
                            console.log(data)
                            this.text=data
                        }
                    })
        
                    // 方式二:js原生的fetch
                    // fetch('http://127.0.0.1:5000/').then(res => res.json()).then(res => {
                    //     console.log(res)
                    //     this.text=res.name
                    //
                    // })
        
                    // 方式三 axios
        
                    // axios.get('http://127.0.0.1:5000').then(data => {
                    //     console.log(data.data)
                    //     this.text=data.data.name
                    // })
        
        
                }
        
        
            })
        </script>
        </html>
        
        image
  • 展示电影数据

    • 后端
      from flask import Flask,make_response,jsonify
      
      app=Flask(__name__)
      @app.route('/films')
      def films():
          import json
          with open('./movie.json','r',encoding='utf-8') as f:
              res=json.load(f)
          obj = make_response(jsonify(res))
          obj.headers['Access-Control-Allow-Origin']='*'
          return obj
      
      if __name__ == '__main__':
          app.run()
      
    • 前端
      <!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">
          <ul>
              <li v-for="film in films_list">
                  <p>电影名字是:{{film.name}}</p>
                  <img :src="film.poster" alt="" width="100px" height="150px">
                  <p>电影介绍:{{film.synopsis}}</p>
              </li>
          </ul>
      
      </div>
      
      </body>
      <script>
      
          var vm = new Vue({
              el: '#app',
              data: {
                  films_list:[]
              },
              created() {
                  axios.get('http://127.0.0.1:5000/films').then(res => {
                      console.log(res.data)
                      this.films_list=res.data.data.films
                  })
      
              }
          })
      </script>
      </html>
      
    • movie数据

      地址: https://m.maizuo.com/v5/?co=mzmovie#/city

      {"status":0,"data":{"films":[{"filmId":5931,"name":"致我的陌生恋人","poster":"https://pic.maizuo.com/usr/movie/923ddd6da070a705d533b48c9eb9996d.jpg","actors":[{"name":"雨果·热兰","role":"导演","avatarAddress":"https://pic.maizuo.com/usr/movie/e96d642a2c613bb38010394e77770a9d.jpg"},{"name":"弗朗索瓦·西维尔","role":"Raphaël Ramisse / Zoltan","avatarAddress":"https://pic.maizuo.com/usr/movie/9f20b16cbf161f28ad90e21dcd57abd2.jpg"},{"name":"约瑟芬·约比","role":"Olivia Marigny / Shadow","avatarAddress":"https://pic.maizuo.com/usr/movie/b0b7ee851580bce62c00985cf1a1c061.jpg"},{"name":"本杰明·拉维赫尼","role":"Félix / Gumpar","avatarAddress":"https://pic.maizuo.com/usr/movie/21ced090240371f98b1d92a842a2398a.jpg"},{"name":"卡米尔·勒鲁什","role":"Mélanie","avatarAddress":"https://pic.maizuo.com/usr/movie/f0a2cbd274934de44bc02568c751ea19.jpg"}],"director":"雨果·热兰","category":"喜剧|爱情","synopsis":"穿过千千万万时间线,跨越漫长岁月去寻找曾经的爱人。只是平行时空,重新认识,她还会爱上他吗?一次激烈的争吵,一场意外的时空旅行,拉斐尔(弗朗索瓦·西维尔 饰)从一名成功的畅销书作家,变成平庸的中学语文老师;妻子奥莉薇亚(约瑟芬·约比  饰)从家庭主妇成为了星光熠熠的著名钢琴家。再相遇,身份颠倒,不再是夫妻,平行时空又一次浪漫邂逅,拉斐尔能否守住最初的爱情?","filmType":{"name":"2D","value":1},"nation":"法国","language":"","videoId":"","premiereAt":1649894400,"timeType":3,"runtime":118,"item":{"name":"2D","type":1},"isPresale":false,"isSale":false},{"filmId":5920,"name":"边缘行者","poster":"https://pic.maizuo.com/usr/movie/afdef208d7b72a950b164c007e8a0837.jpg","actors":[{"name":"谭耀文","role":"演员","avatarAddress":"https://pic.maizuo.com/usr/movie/9bb5e7a0d1ae00cb64370802c0ca812c.jpg"},{"name":"黄明升","role":"导演","avatarAddress":"https://pic.maizuo.com/usr/movie/a1b031211683411b6aea7288cdaa0233.jpg"},{"name":"任贤齐","role":"演员","avatarAddress":"https://pic.maizuo.com/usr/movie/42ff2bb4fc35cfc4c569cce29b1dc574.jpg"},{"name":"任达华","role":"演员","avatarAddress":"https://pic.maizuo.com/usr/movie/56087e1d22305c93dc9c30441f0b60e0.jpg"},{"name":"方中信","role":"演员","avatarAddress":"https://pic.maizuo.com/usr/movie/cdd4b9595ba13f68a1d145902c811bbf.jpg"}],"director":"黄明升","category":"犯罪|动作","synopsis":"1997年回归前夕,多方势力矛盾激化,暴力事件频发。巨变当前,黑帮龙头林耀昌(任达华 饰)对亲信阿骆(任贤齐 饰)委以帮派重任。多重身份的阿骆在黑白边缘行走,一场除暴行动正悄然掀开反杀的序幕。","filmType":{"name":"2D","value":1},"nation":"中国香港,中国大陆","language":"","videoId":"","premiereAt":1649980800,"timeType":3,"runtime":113,"item":{"name":"2D","type":1},"isPresale":false,"isSale":false},{"filmId":5926,"name":"迷失1231","poster":"https://pic.maizuo.com/usr/movie/506cd1a0e038e6bb3a749d49a75a7c95.jpg","actors":[{"name":"徐晓陆","role":"导演","avatarAddress":"https://pic.maizuo.com/usr/movie/9c42c60f4faacc50222e9b3f53107571.jpg"},{"name":"孙飞翔","role":"杜扬羽","avatarAddress":"https://pic.maizuo.com/usr/movie/4fcc3790a4c01ec9e907ef53d2ef40d2.jpg"},{"name":"申容泽","role":"法朋顺","avatarAddress":"https://pic.maizuo.com/usr/movie/2edaa1e730f9cc5a806536e306919295.jpg"},{"name":"郭蓉","role":"柏小慧","avatarAddress":"https://pic.maizuo.com/usr/movie/67eeaa6708d3c4455a2eefa37e904728.jpg"},{"name":"管金麟","role":"冷凌","avatarAddress":"https://pic.maizuo.com/usr/movie/f4f9155d0ab1e1c495ef6163bef08f74.jpg"}],"director":"徐晓陆","category":"惊悚|恐怖","synopsis":"怪面魅影在幽暗午夜神秘游荡,黑衣飘摇,诡笑惊悚,不断侵扰尾随青年男主。或在废弃仓库,或在深悠长廊,一次次挥舞利斧,用索命代价带走无尽恐惧。更为吊诡的是,男主人公却深陷在同一个残酷的日子不能自拔,一次次逃亡,一次次被杀,恐惧不断升级,迷失在奇异时空,逃无可逃……当终极真相震撼揭幕,真正的恐惧才伴随着巨大痛苦彻底爆发!本片在青春时尚的快节奏叙事中,尽展密集吓点,又发人深省,是恐怖片迷必看佳作。","filmType":{"name":"2D","value":1},"nation":"中国大陆","language":"","videoId":"","premiereAt":1649980800,"timeType":3,"runtime":89,"item":{"name":"2D","type":1},"isPresale":false,"isSale":false},{"filmId":5928,"name":"人间世","poster":"https://pic.maizuo.com/usr/movie/27406332a32ebef989f179ff5d109676.jpg","actors":[{"name":"陶涛","role":"导演","avatarAddress":"https://pic.maizuo.com/usr/movie/0489f46c74aaab491eda50abd5611698.png"},{"name":"张琪","role":"导演","avatarAddress":"https://pic.maizuo.com/usr/movie/15758f0a8aaa7424bd9d7a33479ffa7d.jpg"},{"name":"秦博","role":"导演","avatarAddress":"https://pic.maizuo.com/usr/movie/c33bb8e7f4395b74fe9cdab7e4acf640.jpg"},{"name":"范士广","role":"导演","avatarAddress":"https://pic.maizuo.com/usr/movie/4f52c439d48cb25ef659659b5e93f6ed.png"}],"director":"陶涛|张琪|秦博|范士广","category":"纪录片","synopsis":"电影《人间世》由陶涛、张琪、秦博、范士广四位导演共同执导,陶涛,张琪联合监制,秦博、范士广任总策划。影片选取两位身患绝症的病人,将目光聚焦于她们的家庭,记录下她们人生最后的时光,书写了一首关乎爱的生命诗篇。电影《人间世》是一部不同于电视版的大银幕作品,秉承对生命的敬畏,以全新的主题立意,构建不一样的叙事视角与故事结构,将电影蒙太奇手法创造性融入真实感人的纪录影像,向电影中这些真实,可爱并飞扬着生命力量的人物致以最大的敬意。人间世,爱是感同身受的勇气,触手可及!","filmType":{"name":"2D","value":1},"nation":"中国大陆","language":"","videoId":"","premiereAt":1649980800,"timeType":3,"runtime":90,"item":{"name":"2D","type":1},"isPresale":false,"isSale":false},{"filmId":5932,"name":"幺妹住在十三寨","poster":"https://pic.maizuo.com/usr/movie/0ea0373776ca18fae9f1f70a856384a7.jpg","actors":[{"name":"余铁","role":"导演","avatarAddress":"https://pic.maizuo.com/usr/movie/0c51f7259fcbd8bffb4873f58b86a83f.jpg"},{"name":"廖梦妍","role":"演员","avatarAddress":"https://pic.maizuo.com/usr/movie/de93f62cf7cf8ee2da96da57a1912c75.jpg"},{"name":"刘天宝","role":"演员","avatarAddress":"https://pic.maizuo.com/usr/movie/804bb3db37f7158f7f00c2cc0c133007.jpg"},{"name":"覃诚芳","role":"冉芳","avatarAddress":"https://pic.maizuo.com/usr/movie/17e0648cdc8a31dac93222494be73618.png"},{"name":"陈炫羽","role":"卫小勇","avatarAddress":"https://pic.maizuo.com/usr/movie/909d88d0b952b489d9921d92343c522e.png"}],"director":"余铁","category":"剧情|歌舞","synopsis":"本片充分表现了男女主角在振兴乡村的大背景下,实现自已的人生理想作出的努力。曲折跌宕的情节,浪漫而幽默的语言,武陵山雄奇壮观的美景,丰富多彩的土家文化,一首首美丽动人的歌曲都将给您带来美的享受,这是一个把都市的繁华喧闹与山乡宁静之美相结合而展现的当今现代都市与民族山乡融合并进的故事。","filmType":{"name":"2D","value":1},"nation":"中国大陆","language":"","videoId":"","premiereAt":1649980800,"timeType":3,"runtime":104,"item":{"name":"2D","type":1},"isPresale":false,"isSale":false},{"filmId":5933,"name":"误杀瞒天记","poster":"https://pic.maizuo.com/usr/movie/de2be5cf14be8687cf26e5cfebcec04e.jpg","actors":[{"name":"尼西卡特·卡马特","role":"导演","avatarAddress":"https://pic.maizuo.com/usr/movie/5b80929a74bb703550815c91adba3f0f.jpg"},{"name":"阿贾耶·德乌干","role":"Vijay Salgaonkar","avatarAddress":"https://pic.maizuo.com/usr/movie/20a357055dafe5d11605ded8dff4f8b6.png"},{"name":"塔布","role":"Meera Deshmukh","avatarAddress":"https://pic.maizuo.com/usr/movie/86be9d9cd4bc5280998142c7d1935ad7.jpg"},{"name":"施芮娅·萨兰","role":"Nandini Salgaonkar","avatarAddress":"https://pic.maizuo.com/usr/movie/e9eff8814241cf00a750cc2d1f2aae1f.jpg"},{"name":"拉贾特·卡普尔","role":"Mahesh Deshmukh","avatarAddress":"https://pic.maizuo.com/usr/movie/67cb7c8a3512298a893360a985b0569d.jpg"}],"director":"尼西卡特·卡马特","category":"悬疑|犯罪","synopsis":"男主人公维杰经营着一家网络公司,有着幸福的家庭。某天,大女儿安玖不堪男孩萨姆骚扰而错手将其杀死。这场黑夜里的误杀,打破了维杰一家人安宁的生活。为了捍卫女儿和家庭,只有小学文凭的维杰,开始了一些列瞒天过海的计划。该片是电影《误杀》的印度原版,因其缜密的悬疑推理和精巧的反转叙事被奉为悬疑犯罪片经典,并被多国翻拍。","filmType":{"name":"2D","value":1},"nation":"印度","language":"","videoId":"","premiereAt":1649980800,"timeType":3,"runtime":143,"item":{"name":"2D","type":1},"isPresale":false,"isSale":false},{"filmId":5904,"name":"珠峰队长","poster":"https://pic.maizuo.com/usr/movie/e50ab3429a7a99964bd0307103241b3f.jpg","actors":[{"name":"苏拉王平","role":"演员","avatarAddress":"https://pic.maizuo.com/usr/movie/05be45da838f393a34ed61a92821187d.jpg"},{"name":"崔舟萍","role":"演员","avatarAddress":"https://pic.maizuo.com/usr/movie/e6c97b4b19e0a43359968c51af9716f6.jpg"},{"name":"小溪","role":"演员","avatarAddress":"https://pic.maizuo.com/usr/movie/965e2b23b595d7716edf8709bf74a60f.jpg"},{"name":"刘萍","role":"演员","avatarAddress":"https://pic.maizuo.com/usr/movie/fd01a35554cdee9a66bc9c213cb7908c.jpg"},{"name":"吴曦","role":"导演","avatarAddress":"https://pic.maizuo.com/usr/movie/e2ff16e4fe08b281c109c59c21d4909e.jpg"}],"director":"吴曦","category":"纪录片","synopsis":"每天生活两点一线的白领、卖掉自家小店的店主、背负沉重KPI的销售、在成功与失败间挣扎的创业者……8个普通人,带着各自的故事与梦想,在民间专业高山向导、队长苏拉王平的带领下,踏上了憧憬已久的珠峰之旅,也许,也是一次死亡之旅。他们在尼泊尔的珠峰南坡集结出发,穿越裂缝深不见底的恐怖冰川,攀上高达千米的蓝色冰壁,爬过山体岩石断面的“黄带”,朝着世界之巅一步步靠近。这支起初被外国队伍“看扁”的中国民间登山队,面对“窗口期”极短的恶劣天气和可能发生的冲顶“大堵车”,能否成为2019年全球第一支登顶珠峰的团队?本片是中国首部沉浸式体验攀登珠峰全程的电影,也是华语电影史上“最高难度”的纪录片——创下在8470米以上最高海拔完成无人机起飞航拍的新纪录。观众将跟随镜头“空降”珠峰攀登现场,与这群不甘平凡的普通人一起,为心中的热爱疯狂一次。","filmType":{"name":"2D","value":1},"nation":"中国大陆","language":"","videoId":"","premiereAt":1652400000,"timeType":3,"runtime":83,"item":{"name":"2D","type":1},"isPresale":false,"isSale":false},{"filmId":5916,"name":"新灰姑娘2","poster":"https://pic.maizuo.com/usr/movie/41a23e0bc5896e78777a0d3247308f32.jpg","actors":[{"name":"爱丽丝·布莱哈特","role":"导演","avatarAddress":"https://pic.maizuo.com/usr/movie/6d43b3ebf40eea8b0e7a9f667a73409c.jpg"},{"name":"蒋丽","role":"艾 拉","avatarAddress":"https://pic.maizuo.com/usr/movie/4ae6fd3988f8cd011366bf91bea793db.jpg"},{"name":"邵敏佳","role":"莉 莉","avatarAddress":"https://pic.maizuo.com/usr/movie/e5b7ed0517bd8d673b87d8958bf8bfcb.jpg"},{"name":"赵路","role":"痩鼠曼尼","avatarAddress":"https://pic.maizuo.com/usr/movie/09439815e94d6c5577a68fb4b0924acd.jpg"},{"name":"王和逸","role":"胖鼠沃尔特","avatarAddress":"https://pic.maizuo.com/usr/movie/e934ea82b775ea976b67bdfecf4ff80d.jpg"}],"director":"爱丽丝·布莱哈特","category":"动画","synopsis":"为了帮助王子艾利克斯解开魔咒,灰姑娘艾拉带着魔法师莉莉,以及沃尔特和曼尼两只老鼠朋友再度出发寻找生命宝石,但朋友莉莉却在冒险中为了保护艾拉而牺牲,拿回生命宝石的艾拉面临着一个选择,究竟是帮助王子,还是救回朋友?","filmType":{"name":"2D","value":1},"nation":"中国大陆","language":"","videoId":"","premiereAt":1654041600,"timeType":3,"runtime":90,"item":{"name":"2D","type":1},"isPresale":false,"isSale":false},{"filmId":3451,"name":"阿凡达2","poster":"https://pic.maizuo.com/usr/movie/c5da4eddf824824c21f42aebd4f4120f.jpg","actors":[{"name":"萨姆·沃辛顿","role":"杰克·萨利","avatarAddress":"https://pic.maizuo.com/usr/100003451/df050071a829cb47d7612e1e4c3f8b37.jpg"},{"name":"佐伊·索尔达娜","role":"奈蒂莉","avatarAddress":"https://pic.maizuo.com/usr/100003451/a457d0e419128720688a6d11712db4b4.jpg"},{"name":"西格妮·韦弗","role":"格蕾丝·奥格斯","avatarAddress":"https://pic.maizuo.com/usr/100003451/2ebc1d29d21743c960de288930921814.jpg"},{"name":"史蒂芬·朗","role":"迈尔斯·夸奇上校","avatarAddress":"https://pic.maizuo.com/usr/100003451/368a975d10ee8e0bf30b5d5906fb6527.jpg"}],"director":"詹姆斯·卡梅隆","category":"动作|科幻|奇幻|冒险","synopsis":"《阿凡达2》的剧情承接自第一部的5年之后。曾经的地球残疾军人杰克·萨利,如今已经是潘多拉星球纳美族一方部族的族长,并且与爱妻娜塔莉共同育有一对可爱的儿女,日子过得平淡而充实。然而某天,有个部族的兄弟在海岸附近巡逻时遭到利器割喉身亡。通过现场勘查,以及作为前海军陆战队员的敏锐直觉,杰克判断已经有人类的阿凡达混入了部落……","filmType":{"name":"2D","value":1},"nation":"美国","language":"英语","videoId":"","premiereAt":1671321600,"timeType":3,"runtime":90,"item":{"name":"2D","type":1},"isPresale":false,"isSale":false}],"total":9},"msg":"ok"}
      
      image

Vue 组件

  • 计算属性computed

    在Vue中我们可以使用插值来展示数据,插值的普通函数,只要页面一刷新,函数就会重新运算,不管和函数有关没关的值都会变,函数也会重新计算,导致运行效率降低;

    那么我们可以将自定义函数写在computed中来控制,把函数当成属性来用,调用不需要加括号,只有这个函数使用的属性(变量)发生变化,函数才重新运算,这样做可以减轻压力,减少资源浪费

    • 案例:首字母大写
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>计算属性</title>
          <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
          <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
          <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
          <script src="./vue/vue.js"></script>
      </head>
      <body>
      <div id="app">
          <div style="font-size: 20px">
              输入内容:<input type="text" v-model="mytext"> ----》 {{mytext.substring(0, 1).toUpperCase() + mytext.substring(1)}}
              <br><br>
              <p>函数绑定(会刷新页面,也不推荐):<input type="text" :value="getName()"></p>
              <p>计算属性(推荐):<input type="text" :value="getName1"></p>
          </div>
      
          <hr>
          <div style="font-size: 20px">
              <p>输入内容:<input type="text" v-model="mytext1"> -----》{{mytext1}}</p>
          </div>
      </div>
      </body>
      <script>
          var vm = new Vue({
              el: '#app',
              data: {
                  mytext: '',
                  mytext1: ''
              },
              methods: {
                  getName() {
                      console.log('函数方式,我执行了')
                      return this.mytext.substring(0, 1).toUpperCase() + this.mytext.substring(1)
                  }
              },
              //计算属性
              computed: {
                  getName1() {
                      console.log('计算属性,我执行了')
                      return this.mytext.substring(0, 1).toUpperCase() + this.mytext.substring(1)
                  }
      
              }
          })
      </script>
      </html>
      
      image

      我们可以发现只有和属性相关的才会打印,如果下面输入内容只是打印了普通函数,就算函数内和mytext1不相关

    • 案例:过滤案例
      <!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">
          <p><input type="text" v-model="myText"  placeholder="请输入要筛选的内容:"></p>
          <ul>
              <li v-for="data in newList">{{data}}</li>
          </ul>
      </div>
      </body>
      <script>
          var vm = new Vue({
              el: '#box',
              data: {
                  myText: '',
                  dataList: ['a', 'at', 'atom', 'be', 'beyond', 'cs', 'csrf'],
              },
      
              computed:{
      
                  newList(){
                      var _this = this
                      console.log('执行了',_this)
                       var datalist2 = _this.dataList.filter(function(item){
                          console.log(_this)
                           return item.indexOf(_this.myText) > -1
      
                      })
                      return datalist2
      
                  }
              }
          })
      </script>
      </html>
      
      image
  • 监听属性watch

    watch来设置监听属性,当mytext发生变化,就会执行和mytext绑定的函数方法

    <!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="mytext">--->{{mytext}}
    
    
    </div>
    
    </body>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                mytext: '',
            },
            watch: {
                // 只要mytext发生变化,就会执行该函数
                mytext: function () {
                    console.log('我变化了,执行')
    
                }
            }
    
    
        })
    </script>
    </html>
    

    image

  • 局部组件与全局组件

    • 局部组件

      写在components里的是局部组件,位置被限制,只能再局部使用

      比如如下例子中,Top组件只能在只能再id为app的标签(div)内使用, Top组件内如果想再定义子组件,只能在该组件内的template中的div内使用

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>Title</title>
          <script src="./js/vue.js"></script>
      </head>
      <body>
      <div id="app">
          <Top></Top>
          <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
          <Bottom></Bottom>
      </div>
      
      </body>
      <script>
          var vm = new Vue({
              el: '#app',
              data: {},
              // 定义再这里面的叫局部组件,只能再局部使用,只能再id为app的标签内使用
              components: {
                  'Top': {
                      //写在一个div里
                      template: `
                          <div>
                              <h1 style="background: pink;font-size: 60px;text-align: center">{{name}}</h1>
                              <hr>
                              <button @click="handleC">点我看美女</button>
                          </div>
                      `,
                      //data是函数,可以设置返回值
                      data() {
                          return {
                              name: "我是头部"
                          }
                      },
                      methods: {
                          handleC() {
                              alert('美女')
                          }
                      },
                  },
                  'Bottom': {
                      template: `
                          <div>
                              <hr>
                              <h1 style="background: green;font-size: 60px;text-align: center">{{name}}</h1>
      
                          </div>
                      `,
                      data() {
                          return {
                              name: "我是尾部"
                          }
                      },
      
                  },
      
              },
      
      
          })
      </script>
      </html>
      

      image

    • 全局组件

      任意位置都可以使用,但是也得是在vue实例托管的div范围内

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>Title</title>
          <script src="./js/vue.js"></script>
      </head>
      <body>
      <div id="app">
          <top></top>
      
      
      </div>
      
      </body>
      <script>
          // 定义全局组件,任意位置都可以用,局部内也可以使用
          Vue.component('top', {
                  template: `
                      <div>
                          <h1 style="background: pink;font-size: 60px;text-align: center">{{name}}</h1>
                          <hr>
                          <button @click="handleC">点我看美女</button>
                      </div>
                  `,
                  data() {
                      return {
                          name: "我是头部"
                      }
                  },
                  methods: {
                      handleC() {
                          alert('美女')
                      }
                  },
      
              },)
      
          var vm = new Vue({
              el: '#app',
          })
      </script>
      </html>
      

      image

  • 组件间通信

    组件间data数据不同享

    • 组件通信之父传子

      从父组件传递到子组件数据通过props自定义属性来实现

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>Title</title>
          <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
          <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
          <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
          <script src="./js/vue.js"></script>
      </head>
      <body>
      <div id="app">
          子组件显示:<top :value="handleName"></top>
          <hr>
          父组件输入内容:<input type="text" v-model="handleName">
      
      </div>
      
      </body>
      <script>
      
          Vue.component('top', {
              template: ` <div>
                          <h1 style="background: tomato;font-size: 30px;text-align: center">{{value}}</h1>
                          </div>             `,
              // 必须叫props,数组内放自定义属性的名字
              props:{
                  value: String,  // key是自定义属性名,value是类型名,如果是别的类型就报错
              },
              //props也可以写成数组的形式,不带验证功能
              // props:['value',]
          })
          var vm = new Vue({
              el: '#app',
              data: {
                  handleName: ''
              }
          })
      </script>
      </html>
      

      image

    • 组件通信之子传父

      通过自定义事件来实现子组件向父组件传递数据,在子组件中使用$emit('自定义事件',参数)来实现

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>Title</title>
          <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
          <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
          <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
          <script src="./js/vue.js"></script>
      </head>
      <body>
      <div id="app">
      <top @myevent="handleRecv"></top>
          <hr>
        <h1 style="background: green;font-size: 60px;text-align: center">父组件</h1>
       <p>接收子组件发送的数据:{{childText}}</p>
      </div>
      
      </body>
      <script>
      
          Vue.component('top', {
              template: ` <div>
                              <h1 style="background: tomato;font-size: 60px;text-align: center">{{myheader}}</h1>
                              <p>子组件输入内容:<input type="text" v-model="text"></p>
                              <p><button class="btn-success"  @click="handleSend">向父组件发送数据</button></p>
                          </div>             `,
              data(){
                  return {
                      myheader:'子组件',
                      text:''
                  }
              },
              methods:{
                  handleSend(){
                      //myevent是自定义事件,代表将子组件的text交给myevent事件处理
                      this.$emit('myevent',this.text)
                  }
              }
      
          })
          var vm = new Vue({
              el: '#app',
              data: {
                  //接收子组件的数据
                  childText:''
              },
              methods: {
                  handleRecv(data){
                      // 接收参数,赋值给父组件的childText
                      this.childText=data
                  }
              }
          })
      </script>
      </html>
      

      image

    • ref属性(组件间通信)

      • 普通标签使用

        普通标签使用ref属性,通过$refs获取到的就是ref属性所在的标签,获取到的是一个对象,如果多个标签写了ref属性,那么就将所有带ref属性的标签弄到一个对象中,可以对html进行操作设置等,如下示例:

        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>Title</title>
            <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
            <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
            <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
            <script src="./js/vue.js"></script>
        </head>
        <body>
        <div id="app">
            <h1 style="align-content: center">普通标签使用ref</h1>
            <p><input type="text" ref="myinput"></p>
            <p><img src="" height="100px" width="100px" ref="myimg"></p>
            <p><button @click="handleC">点我</button>
        </p>
        </div>
        </body>
        <script>
        
            let vm = new Vue({
                el: '#app',
                data: {
                     text:''
                },
                methods: {
                    handleC(){
                        console.log('我被点了')
                        console.log(this.$refs)  // 是所有标签写了ref属性的对象{myinput:真正的标签,myimg:真正的标签}
                        console.log(this.$refs.myinput.value)
                        //设置值
                        this.$refs.myinput.value='HammerZe'
                        //设置src属性,显示图片
                        this.$refs.myimg.src='https://img0.baidu.com/it/u=3608430476,1945954109&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=494'
                    }
                }
            })
        </script>
        </html>
        

        image

      • 组件使用ref属性

        ref属性,如果放在组件上,就是当前组件对象

        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>Title</title>
            <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
            <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
            <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
            <script src="./js/vue.js"></script>
        </head>
        <body>
        <div id="app">
        <!-- 组件使用ref属性   -->
        <top ref="top"></top>
        <p>通信:<input type="text" v-model="text"></p>
        <p>父组件按钮:<button @click="handleC">点我</button></p>
        </p>
        </div>
        </body>
        <script>
           Vue.component('top', {
                template: `
                    <div>
                        <h1>{{myheader}}</h1>
                        <p>子组件按钮:<button @click="handleC">点我看美女</button></p>
                        <hr>
                    </div>
                `,
                data() {
                    return {
                        myheader: "头部",
                    }
                },
                methods:{
                    handleC(){
                        alert("美女")
                    }
                }
        
        
        
            },)
            let vm = new Vue({
                el: '#app',
                data: {
                     text:''
                },
                methods: {
                //放在组件上
                handleC() {
                     console.log(this.$refs.top) //VueComponent {_uid: 1, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}
                    /*子传父*/
                    // 父组件拿子组件的值
                    console.log(this.$refs.top.myheader)
                    // this.text=this.$refs.top.myheader
                    // 父组件调用子组件的方法
                    this.$refs.top.handleC()
        
                    /*父传子*/
                    this.$refs.top.myheader=this.text
                }
                }
            })
        </script>
        </html>
        

        image

    • 事件总线(不常用)

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>Title</title>
          <script src="js/vue.js"></script>
      </head>
      <body>
      <div id="box">
          <child1></child1>
          <child2></child2>
      </div>
      </body>
      <script>
          var bus=new Vue() //new一个vue的实例,就是中央事件总线
          Vue.component('child1', {
              template: `<div>
                  <input type="text" ref="mytext">
                  <button @click="handleClick">点我</button>
              </div>`,
              methods:{
                  handleClick(){
                      bus.$emit('suibian',this.$refs.mytext.value) //发布消息,名字跟订阅消息名一致
                  }
              }
          })
          Vue.component('child2', {
              template: `<div>
                          <div>收到的消息 {{msg}}</div>
                          </div>`,
              data(){
                  return {msg:''}
              },
              mounted(){
                  //生命周期,当前组件dom创建完后悔执行
                  console.log('当前组件dom创建完后悔执行')
                  //订阅消息
                  bus.$on('suibian',(item)=>{
                      console.log('收到了',item)
                      this.msg=item
                  })
              }
          })
          var vm = new Vue({
              el: '#box',
              data: {},
              methods: {
                  handleClick() {
                      console.log(this)
                      //this.$refs.mytext 获取到input控件,取出value值
                      console.log(this.$refs.mytext.value)
                      console.log(this.$refs.mychild.text)
                      // this.$refs.mychild.add()
                      this.$refs.mychild.add('传递参数')
      
                  }
              }
      
          })
      </script>
      </html>
      
  • 动态组件和keep-alive

    • 动态组件:实现点击不同的连接显示不同的页面,实现跳转,使用component标签,用is属性绑定,指定哪个显示哪个
    • keep-alive:通过keep-alive标签实现组件不销毁,保留原来输入的内容
    • 示例
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>Title</title>
          <script src="./js/vue.js"></script>
      </head>
      <style>
          #menu {
              font-size: 18px;
              font-weight: bold;
          }
      
          #menu li {
              text-decoration: none; /*去掉前面的圆点*/
              list-style: none;
              float: left;
              margin-right: 20px;
      
          }
      
      </style>
      <body>
      <div id="app">
          <ul id="menu">
              <li @click="changeC('index')">首页</li> &nbsp;
              <li @click="changeC('order')" >订单</li>
              <li @click="changeC('good')">商品</li>
          </ul>
      
      
          <keep-alive>
              <component :is='who'></component>
          </keep-alive>
      
      
      </div>
      
      </body>
      <script>
          //三个组件
          Vue.component('index', {
              template: `
                  <div style="overflow:hidden;">
                      <h1>首页内容</h1>
                  </div>
              `,
          },)
          //保留输入的订单信息
          Vue.component('order', {
              template: `
                  <div>
                      <h1>订单内容</h1>
                      请输入要查询的订单:<input type="text">
                  </div>
              `,
          },)
          Vue.component('good', {
              template: `
                  <div>
                      <h1>商品内容</h1>
                  </div>
              `,
          },)
      
          var vm = new Vue({
              el: '#app',
              data: {
                  //默认显示index
                  who: 'index'
      
              },
              methods: {
                  changeC(data) {
                      this.who = data
                  }
              }
      
          })
      </script>
      </html>
      
      image

Vue 插槽

组件使用slot标签,显示组件标签的内容,可以类比block学习

  • 无名卡槽

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="js/vue.js"></script>
    </head>
    <body>
    <div id="box">
        <!-- 不使用插槽写的aaa不会显示,使用就会显示-->
        <child1>aaa</child1>
    
    </div>
    </body>
    <script>
    
        Vue.component('child1', {
            template: `<div>
              首页
              <slot></slot>
            </div>`,
    
        })
     var vm = new Vue({
            el: '#box',
    
        })
    </script>
    </html>
    

    image

  • 具名卡槽

    通过在标签内使用slot属性指定值,组件内使用solt标签通过name接收slot属性值

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="js/vue.js"></script>
    </head>
    <body>
    <div id="box">
    <!--    具名插槽,把p标签给a插槽,div标签给b插槽-->
        <navbar>
            <p slot="a">pppp</p>
            <div slot="b">bbbb</div>
        </navbar>
    </div>
    </body>
    <script>
        Vue.component('navbar', {
            template: `<div>
            <slot name="a"></slot>
              navbar
              <slot name="b"></slot>
            </div>`,
    
        })
    var vm = new Vue({
            el: '#box',
            data:{
    
            }
    
        })
    </script>
    </html>
    

总结

# 1 计算属性
      - computed--->把方法变成属性---》延缓计算
      - 在页面中直接使用函数,页面只要刷新,函数就会重新运行,使用计算属性--》只有当前函数使用的变量发生变化时,才重新运算

# 2 监听属性
      - watch:属性----》只要这个变量发生变化,就会执行方法

# 3 组件化开发
    - 局部组件:写在组件内部:Vue.components
    - 全局组件:Vue.component()
    - 组件有自己的html,css,js,相互不影响
    - template 一定要放在一个标签中
    - data必须是函数data(){retrun {} }
    - 各级组件的data数据是不共享的


# 4 组件间通信
    - 通过自定义属性:父传子---》自定义的属性写在自定义的组件上---》props:['自定义属性名']
    - 通过自定义事件:子传父---》子中调用this.$emit('自定义事件名',参数,参数)--》触发写在定义组件上的 @自定义事件名='函数'---》函数执行(父组件)
    - ref属性:
        - 放在普通标签---》通过this.$refs.属性值---》原生dom
        - 放在组件上---》通过this.$refs.属性值---》当前组价对象---》拿到组件中的值,执行组件中的方法

# 5 动态组件
    - 多个组件切换,通过动态组件的is来决定显示哪个组件
    - keep-alive:组件切换的时候不销毁
    
# 6 插槽
    - <组件>写内容</组件>---》如果定义了插槽---》替换到插槽中
    - 具名插槽---》给插槽名名字---》使用的时候,指定替换哪个插槽的内容
posted @ 2022-11-12 20:35  爱learn  阅读(195)  评论(0编辑  收藏  举报