组件化-组件-组件注册-is-动态组件-动态缓存-组件嵌套-组件的数据-组件通信

  1. 组件

    • Vue有两大核心内容

      • 指令
      • 组件
    • 什么是组件化?【 为什么要用组件 】

      • 为了避免多人开发造成的冲突
      • 为了加快开发效率
      • 为了便利更新和维护
      • 组件化: 就是使用具有独立功能的一个整体【 组件 】来进行项目开发的一个趋势 【 流行 】
    • 什么是组件?

      • 组件是一个html css js img 等的一个聚合体
      • 在Vue中使用了一个叫做单文件组件的技术来实现组件
        • 它是一个 xxx.vue 文件
        • 这个文件在浏览器中不能运行,必须经过编译【 gulp webpack 】才能运行
    • Vue里面是如何实现组件的?

      • 扩展: Vue.extend() 它就是对Vue功能的扩展,这个扩展就是组件

        <script>
          /* 
            1. 通过实例化Vue构造器函数得到一个Vue实例,这个实例我们称之
               为'根实例',它是最大的父级
            2. 这个根实例是以标签的形式存在的,我们也称之为' 根组件 '
            3. 根实例也是一个组件,但是我们得到只是根组件
            4. Vue.extend() 它就是对Vue功能的扩展,这个扩展就是组件
            5. Vue.extend如何使用?
                  - 通过new Vue.extend() 发现和其和new Vue是一样的 
                  - 组件就是一个以标签化呈现的东西,所以我应该像标签一样使用
                  - 但是无论是  html3  还是  html5 肯定不会同意它随意来个标签的
                  - Vue会将组件编译成html结构 
                  - Vue的这个处理过程,我们称之为 ' 组件注册 '
        
            总结: 
              1. Vue是通过Vue.extend() 来实现组件的
              2. Vue的组件的使用时需要注册的
          */
            
          //下面两个基本一样  
          //所以不用new Vue来扩展组件,直接vue.extend()
          console.log( Vue ) 
                /*
                ƒ Vue (options) {
                    if (!(this instanceof Vue)
                    ) {
                      warn('Vue is a constructor and should be called with the `new` keyword');
                    }
                    this._init(options);}
                */
          console.log( Vue.extend())
        	/*
                ƒ VueComponent (options) {
                    this._init(options);
                  }
        	*/
          new Vue({
            el: '#app'
          })
        </script>
        
    • Vue中是如何使用组件的?

      • 组件注册

        • 全局注册:在当前页的所有根实例里面都可以引用

          //1、用vue.extend()
          const Hellooo = vue.extend({
              template:'<div>这是全局组件</div>'
          })
          //vue.component('组件名',组件配置项)
          vue.component('Hello',Hellooo)//这里是注册部分
          //然后再到vue的根实例#app中使用组件<Hello></Hello>即可
          
          new Vue({
              el: '#app'
            })
          
          //2、全局注册的简写方式
          vue.component('Hello',{
              template:'<div>这是全局组件</div>'
          })
          
          //3、上面这两种,在写的过程种都没有代码提示,为了有,一般
          将template拿出来,在el在body中的位置下面,写一个<template>
          标签,就类似于new Vue中的el,不要写在了#app根实例里面,不然,
          还不待放到组件中就直接解析
          <body>
              <div id="app">
              </div>
              
              <template id="hahaha">
              	<div>这里是全局组件</div>
              </template>
          </body>
          
          vue.component('Hello',{
              template:'#hahaha'
          })
          
        • 局部注册:在当前根实例里面才能有用

          //局部注册,写在VM里面
          new Vue({//VM
              el: '#app',
              components: { //局部注册组件的选项,注意这里是带有"s"的
                // 组件名: 组件选项
                'Hello': {
                  template: '<div> Hello 这里是局部注册 </div>'
                }
              }
            })
          
      • 组件的起名

        1. 大驼峰 HeadTitle 使用时 <head-title></head-title>
        2. 小写横杠 head-title 使用时 <head-title></head-title>
        3. 一个单词 Hello 使用时 <hello></hello> 或者 <Hello></Hello>【 推荐这种,大写可以和原生标签区分 】
        4. 不要用和原生标签一样的名称
  2. 组件通信 【 使用组件实现todolist 】

  3. 组件的使用规则?

    • 具有直接父子级关系的标签,会出现渲染问题,我们通过is属性来解决
    • 如:ul>li、ol>li、dl>dt|dd、select>option、table>tr>td
    <body>
      <div id="app">
        <table border="1"> 
          <tr>
            <td>1</td>
            <td>2</td>
            <td>3</td>
          </tr>
          <tr is = "Hello"></tr>
            <!--这里不是直接写<Hello></Hello>,不然会出问题,用is属性-->   
        </table>
      </div>
    </body>
    
    <script src="vue.js"></script>
    <script>
      /* 
        业务: 给上面的表格增加一个行,这一行用一个组件表示
     
        通过以上案例发现: 组件在父子级是有直接关系的标签中是不能直接解析的,
        会出问题
      */
      Vue.component('Hello',{
        template: ` <tr>
                      <td>4</td>
                      <td>5</td>
                      <td>6</td>
                    </tr>
    			 `
      })
    
      new Vue({
        el: '#app'
      })
    </script>
    
  4. 动态组件

    • 动态组件指的是通过 Vue 提供的 component组件 + is 属性来
      实现(vue中component组件是内置的,不需要注册)

    • keep-alive组件实现缓存(在频繁切换时,可以加快反应速度)

      <!--例子,点击按钮,切换登录方式-->
      <body>
        <div id="app">
            <button @click="typechange">点击切换登录方式</button>
            <keep-alive>
              <component :is="type"></component>
            </keep-alive>
        </div>
      
        <template id="phonelogin">
          <div>手机号登录</div>
        </template>
      </body>
      
      <script src="vue.js"></script>
      <script>
        Vue.component('userlogin',{//全局组件
          template:'<div>账号密码登录</div>'
        })
        new Vue({
          el: '#app',
          data:{
            type:'phonelogin'
          },
          methods: {
            typechange () {
              this.type=(this.type==='phonelogin')&&'userlogin'||'phonelogin'
            }
          },
          components:{//局部组件
            'phonelogin':{
              template:'#phonelogin'
            }
          }
        })
      </script>
      

5、组件嵌套:(子组件以标签的形式要在父组件的模板中使用)

<body>
  <div id="app">
    <Father></Father>
  </div>
    
  <template id="father">
    <!-- 唯一根元素div -->
    <div>
      <h3> 这里是父组件 </h3>
      <hr>
      <Son></Son><!--子组件以标签的形式要在父组件的**模板中**使用-->
    </div>
  </template>

  <template id="son">
    <div>
      <h3> 这里是子组件 </h3>
    </div>
  </template>
</body>

<script>
  //1、全局注册
  Vue.component('Father',{
    template: '#father'
  })

  Vue.component('Son',{
    template: '#son'
  })

  new Vue({
    el: '#app'
  })
</script>

<script>
 //2、局部注册,注意这里的组件注册的写法,子组件是在父组件里面注册的
  new Vue({
    el: '#app',
    components: {
      'Father': {
        template: '#father',
        components: {
          'Son': {
            template: '#son'
          }
        }
      }
    }
  })
</script>

6、组件中的数据

1. 为什么组件中的data选项是一个函数,而根实例中是对象?
          原因: 
              1. 组件是一个独立的整体,那么数据也应该是一个独立的 
              2. 多人开发,数据如果不是独立的,那么数据会冲突 
              3. javascript最大的特点: 函数式编程,而函数本身就有一个独立作用域
2. 为什么组件中的data函数要有返回值,并且返回值是一个对象,不能是其他的吗?
          原因: 
            1. 因为data选项要经过es5的Object.defineProperty 属性进行getter和setter设置,
                如果不是对象,就不能进行后续操作 

3. 数据中数据的使用
        组件的数据,使用范围只能在组件的模板中
Vue.component('Hello',{
    template: '#hello',
    data () {
      return {//要有返回值
        msg: '今天热的要死'  // 组件的数据,使用范围只能在组件的模板中
      }
    }
  })
  new Vue({
    el: '#app'
  })

7、组件通信:

  1. 父子组件通信:(利用props)

    <body>
      <div id="app">
        <Father/>
      </div>
    
      <!-- father 组件  --start -->
        <template id="father">
          <div>
            <h3> 这里是父组件 </h3>
            <Son :aa = "money"></Son><!--在父组件的模板中,用 v-bind 
            将父组件的数据绑定在子组件身上-->
          </div>
        </template>
      <!-- father 组件  --end -->
    
      <!-- son组件  --start -->
        <template id="son">
          <div>
            <h4> 这里是子组件 </h4>
            <p> 老爸给了我  {{ aa }} 生活费 </p>
          </div>
        </template>
      <!-- son组件  --end -->
    </body>
    
    <script src="vue.js"></script>
    <script>
      /* 
        父子组件通信
          1. 父组件中定义一个数据
          2. 在父组件的模板中,用 v-bind 将父组件的数据绑定在子组件身上
              <Son :aa = "money"></Son>,aa为自定义的一个属性
          3. 在子组件的选项中,通过props选项来接收这个属性
          4. 这个属性可以在子组件的模板中以全局变量的形式使用
       */
      Vue.component('Father',{
        template: '#father',
        data () {
          return {
            money: 3000
          }
        }
      })
    
      Vue.component('Son',{
        template: '#son',
        props: ['aa']//子组件用props来接收
        //下面还可以做相关属性验证
        // props: {
        //   'aa': Number //属性验证  
        // }
        // props: {
        //   'aa': {
        //     validator ( val ) {
        //       return val > 2000 
        //     }
        //   }
        // }
      })
      new Vue({
        el: '#app'
      })
    </script>
    
  2. 子父组件通信:(利用父组件的自定义事件)

    //子父通信流程
            //1. 先在子组件中定义一个数据
              Vue.component('Son',{
                template: '#son',
                data () {
                  return {
                    money: 1000
                  }
                }
              })
            //2. 在父组件中也定义一个数据,这个数据用来接收子组件传递过来的数据
             Vue.component('Father',{
                template: '#father',
                data () {
                  return {
                    bank: null
                  }
                }
              })
            //3. 在父组件中定义一个事件处理程序,用于改变父组件定义的数据,
               //这个事件处理程序是有参数的,这个参数就是子组件传递过来的数据
    
              Vue.component('Father',{
                template: '#father',
                data () {
                  return {
                    bank: null
                  }
                },
                methods: {
                  bankAdd ( val ) { //val就是子组件给的数据
                    this.bank += val 
                  }
                }
              })
            //4. 将这个事件处理程序通过自定义事件绑定的形式绑定在子组件身上
    
              <Son @aa = "bankAdd"></Son>
              
            //5. 在子组件中定义一个事件处理程序,这事件处理程序中通过
            // this.$emit来触发自定义事件,并传递一个参数给父组件
    
              Vue.component('Son',{
                template: '#son',
                data () {
                  return {
                    money: 1000
                  }
                },
                methods: {
                  give () {
                    // this.$emit('aa',传递给父组件的参数)
                    this.$emit('aa',this.money)
                  }
                }
              })
    		//6、触发子组件身上的事件就触发了父组件身上的自定义事件
              <template id="son">
                <div>
                  <h4> 这里是子组件 </h4>
                  <button @click = " give "> 给老爸红包 </button>
                </div>
              </template>
    
  3. 非父子组件通信:(利用 ref 链和bus事件总线)

    <!--ref链:-->
    <!--只能son的数据控制自己,而son通过ref和id将自己的一些方法和数据绑定在了
    父组件的Vuecomponent上,再在父组件的模板中,以属性绑定的形式将这个可以
    控制son组件数据的方法绑定在了girl组件上,girl可以通过父子组件通信的方法以
    props来接收,那么这个方法也在girl上了,这时再触发这个事件,girl就可以控制
    son了-->
    <body>
      <div id="app">
        <Father></Father>
      </div>
    
      <template id="father">
        <div><!--唯一根元素-->
          <h3>这里是father组件</h3>
          <button @click="print">输出this</button>
          <hr>
          <Girl :cry="emitflagchange"></Girl>
          <hr>
          <Son ref="son"></Son><!--这里是ref绑定的为id-->
        </div>
      </template
    
      <template id="girl">
        <div>
          <h3>这里是girl组件</h3>
          <button @click="cry">姐姐揍弟弟</button>
        </div>
      </template>
    
      <template id="son">
        <div>
          <h3>这里是son组件</h3>
          <button @click="flagchange">自己揍自己</button>
          <br>
          <img v-show="flag"  style = "width: 100px;height: 100px;" src="https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1564471527&di=2c4707955cefb24c325842ea288b9647&src=http://b-ssl.duitang.com/uploads/item/201702/16/20170216145320_wyNiK.jpeg" alt="">
        </div>
      </template>
    
    </body>
    <script src="../../lib/vue.js"></script>
    <script>
      
      Vue.component('Father',{
        template:'#father',
        data () {
          return {
    
          }
        },
        methods:{
          print () {
            console.log(this.$refs.son)
          },
          emitflagchange () {
            this.$refs.son.flagchange()
          }
        }
      })
    
      Vue.component('Girl',{
        template:'#girl',
        data () {
          return {
    
          }
        },
        props:['cry'],//接收父组件传来的数据
        methods:{
          p () {
            console.log(this)
          }
        }
      })
    
      Vue.component('Son',{
        template:'#son',
        data () {
          return {
            flag:false
          }
        },
        methods: {
          flagchange () {
            this.flag=!this.flag
          }
        }
      })
    
      new Vue({
        el: '#app'
      })
    </script>
    
    //bus事件总线
    
    <body>
      <div id="app">
        <Girl></Girl>
        <Son></Son>
      </div>
    
      <template id="girl">
        <div>
          <h3>这里是girl组件</h3>
          <button @click="hit">揍弟弟</button>
        </div>
      </template>
    
      <template id="son">
        <div>
          <h3>这里是son组件</h3>
          <button @click="cry">自己揍自己</button>
          <br>
          <img style = "width: 100px;height: 100px;" v-show = "flag" src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1564481613744&di=22ebae5b3c4655691a1244e46682d7c9&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201702%2F16%2F20170216145320_wyNiK.jpeg" alt="">
        </div>
      </template>
    </body>
    <script src="../../lib/vue.js"></script>
    
    <script>
      var bus = new Vue()//用bus将两个组件串联起来
      console.log(bus)
    
      Vue.component('Girl',{
        template:'#girl',
        methods:{
          hit () {
            bus.$emit('abc')
          }
        }
      })
    
      Vue.component('Son',{
        template:'#son',
        data () {
          return {
            flag:true
          }
        },
        methods:{
          cry () {
            this.flag=!this.flag
          }
        },
        mounted() {
          var _this=this//保存this,因为this到下面函数里会变化
          // bus.$on(自定义事件的名称,自定义事件的处理程序)
          bus.$on('abc',function(){// 通过$on自定义一个叫做abc的事件 
            _this.cry()
          })
        },
      })
    
      new Vue({
        el: '#app'
      })
    </script>
    
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值