Bootstrap

vue组件化总结

一.vue组件化思想

       如果我们将一个的页面的所有处理逻辑都放在一起,那么处理起来就变得非常复杂,而且也不利于后续的管理和扩展,如果我们把一个页面拆分成一个一个小的功能模块,每个模块完成对应的功能,组件之间相互独立,那么后期对这个页面的维护和管理也就变得简单了。

二.使用组件的步骤

1.创建组件构造器

调用Vue.extend()方法创建组件构造器

2.注册组件

调用Vue.component()方法注册组件

3.使用组件

在Vue实例的作用范围内使用组件

 三.组件化的使用

1.组件化的基本使用

<body>
    <div id="app">
      <!-- 3.使用组件 -->
        <my-cpn></my-cpn>
        <my-cpn></my-cpn>
        <my-cpn></my-cpn>
        <my-cpn></my-cpn>
      </div>

      <script src="./js/vue.js"></script>
      <script>
        //1.创建组件构造器对象
        const cpnC = Vue.extend({
        template: ` <div>
            <h2>标题标题标题</h2>
            <p>内容内容内容内容</p>
            <p>内容内容内容内容啊啊啊啊</p>
            <p>内容内容内容内容嘿嘿嘿嘿</p>
          </div>`
        })

        //2.注册组件
        Vue.component('my-cpn',cpnC)//my-cpn是组件的标签名
        new Vue({ el: '#app' })
        const app = new Vue({
            el: '#app',//用于挂在要管理的元素
                            })       
      </script> 
</body>

运行结果:

 步骤解析:

2.全局组件和局部组件

上面的案例是使用的全局组件,全局组件意味着可以在多个vue实例下使用。

那么怎么才算是局部组件?

在实例里面注册组件。在开发中一般用的局部组件。而且一般创建一个实例,不会创建多个实例。

<body>
    <div id="app">
      <!-- 3.使用组件 -->
        <my-cpn></my-cpn>
        <my-cpn></my-cpn>
        <my-cpn></my-cpn>
      </div>

      <script src="./js/vue.js"></script>
      <script>
        //1.创建组件构造器对象
        const cpnC = Vue.extend({
        template: ` <div>
            <h2>标题标题标题</h2>
            <p>内容内容内容内容</p>
            <p>内容内容内容内容hhhhh</p>
            <p>内容内容内容内容嘿嘿嘿嘿</p>
          </div>`
        })

        //2.注册组件

        const app = new Vue({
            el: '#app',//用于挂在要管理的元素
            components:{
              'my-cpn':cpnC
            }
                            })       
      </script> 
</body>

 运行结果:

 3.父组件和子组件

3.1父组件和子组件的区分

组件和组件之间是有层级关系的,一般的层级关系就是父子关系。

那怎么体现父子关系呢?

子组件是注册到父组件的components里面的。

3.2注册组件的语法糖

<body>
    <div id="app">
      <!-- 3.使用组件 -->
        <my-cpn></my-cpn>
        <my-cpn></my-cpn>
        <my-cpn></my-cpn>
        <my-cpn></my-cpn>
      </div>

      <script src="./js/vue.js"></script>
      <script>
        //1.创建组件构造器对象
        // const cpnC = Vue.extend()

        //2.注册组件
        Vue.component('my-cpn',{
        template: ` <div>
            <h2>标题标题标题</h2>
            <p>内容内容内容内容</p>
            <p>内容内容内容内容啊啊啊啊</p>
            <p>内容内容内容内容嘿嘿嘿嘿</p>
          </div>`
        })//my-cpn是组件的标签名
        const app = new Vue({
            el: '#app',//用于挂在要管理的元素
           
                            })         
      </script> 
</body>

这个语法糖直接把创建组件构造器对象这一步省略了,把构造器里面的模板的值赋给了注册组件。上面这个例子是全局组件的方法。

局部组件的话,直接在实例里面的component里面写模板内容就行了。

<body>
    <div id="app">
      <!-- 3.使用组件 -->
        <cpn2></cpn2>
      </div>

      <script src="./js/vue.js"></script>
      <script>
     
        new Vue({ el: '#app' })
        const app = new Vue({
            el: '#app',//用于挂在要管理的元素
            components:{
              'cpn2':{
                template:
                `<div>
                  <h2>我是标题1</h2>
                  <p>我是内容</p>
                  </div>`
              }
            }
                            })         
      </script> 
</body>

运行结果:

 这样写的话,子组件在父组件可以里面嵌套,template这一块会导致代码看上去很乱,那么我们需要把模板分离出来。

模板分离方法一:在注册组件前面用script标签把内容写出来,标签中type="text/x-template" ,定义id名,在components里面的template引用id名即可。(一般不用这个方法)

<body>
  <div id="app">
    <!-- 3.使用组件 -->
      <cpn2></cpn2>
    </div>

    <script src="./js/vue.js"></script>
   
    <script type="text/x-template" id="cpn">
      <div>
        <h2>我是标题</h2>
        <p>我是内容。。</p>
      </div>
    </script>
   
   <script>  
      const app = new Vue({
          el: '#app',//用于挂在要管理的元素
          components:{
            'cpn2':{
              template:
                `#cpn`
            }
          }
                          })         
    </script> 
</body>

运行结果:

模板分离方法二: 还是在注册界面前面用<template></template>标签,在标签内把模板内容写进去,并且需要id绑定。一般模板分离用这个方法。

<body>
  <div id="app">
    <!-- 3.使用组件 -->
      <cpn2></cpn2>
    </div>

    <script src="./js/vue.js"></script>
   
  <template id="cpn">
    <div>
      <h2>我是标题</h2>
      <p>我是内容。。</p>
    </div>
  </template>
   
   <script>  
      const app = new Vue({
          el: '#app',//用于挂在要管理的元素
          components:{
            'cpn2':{
              template:
                `#cpn`
            }
          }
                          })         
    </script> 
</body>

 运行结果是一样的。

3.3父子组件之间的通信

子组件是不能访问父组件或者vue的实例的,但是在开发中,往往一些数据需要从上层传递到下层,比如一个页面里面的一些内容不需要父组件展示,而是需要父组件下面的子组件展示。那么这个时候我们不会让子组件发送请求给父组件,而是让父组件将数据传递给子组件。

3.3.1如何进行父子组件的通信?

  • 通过props向子组件传递数据
  • 通过事件向父组件发送消息

1.通过props向子组件传递数据

注意:

  •  模板template必须有个根元素(代码中的div)。
  •  props的属性名是驼峰命名法的话,在显示的时候,在组件标签v-bind的时候需要按照驼峰命名法对应的属性名字来写。(尽量取名就用小写)
<body>
    <div id="app">
        <cpn v-bind:cnames="names" :cmessage="message"></cpn>
      </div>

      <template id='cpn'>
        <div>
          <ul>
            <li v-for="item in cnames">{{item}}</li>
          </ul>
          <h2>{{cmessage}}</h2>
        </div>
      </template>

      <script src="./js/vue.js"></script>
      <script>
        // 父传子,props
        const cpn ={
          template:`#cpn`,
          props:['cnames','cmessage']
        }

          const app = new Vue({
            el: '#app',//用于挂在要管理的元素
            data: {
              message: 'Hello Vue!',
              names:['京东','小米','美团']
            },
            components:{
              'cpn':cpn
            }
                            })             
      </script> 
</body>

 运行结果:

代码思路:首先在实例(父组件)里面准备数据(代码中为message和names),在实例中注册子组件cpn,在子组件的构造器添加props以及需要用到的变量名,在模板(template)里面使用这些变量,最后绑定在vue实例里面,用组件标签显示。

当然,props可以是对象,在对象里面对传进来的参数做一个类型限制。

    const cpn ={
          template:`#cpn`,
          props:{
            //1.类型限制
            cnames:Array,
            cmessage:String
          }
        }

或者类型限制的同时定义一个默认值。

 const cpn ={
          template:`#cpn`,
          props:{
            cmessage:{
              type:String,
              default:'aaaa',//默认值
              required:true//这句表示这个属性传值的时候必须传这个值
            }
          }}

            cnames:{
              type:Array,
              default:[]//在vue2.5.17版本下这个写法没有问题
            }

      如果类型是对象或者数组的时候,那么默认值必须是一个函数,函数里面要有返回值。

 cnames:{
              type:Array,
              default(){
                return []
              }
            }

2.通过事件向父组件发送消息

这个过程比父传子更常见,因为子组件一般会发生一些事件,比如用户点击事件之类的,子组件需要告诉父组件发生了这个事件,并且告诉父组件用户点击了什么,父组件根据子组件传过来的数据再去请求新的数据。

举个例子:在子组件定义几个按钮,点击按钮,控制台返回点击的信息。

<body>
  <!-- 父组件模板 -->
    <div id="app">
        <cpn ></cpn>
      </div>

<!-- 子组件模板 -->
      <template id='cpn'>
        <div>
          <button v-for="item in categories" @click="btnclick(item)">{{item.name}}</button>
        </div>
      </template>

      <script src="./js/vue.js"></script>
      <script>
        //子组件
        const cpn ={
          template:`#cpn`,
          props:{
           cnames:{
             type:Array
           } ,
           cmessage:{
             type:String
           }
          },
          data(){
            return{
              categories:[
                {id:'aaa',name:'电脑手机'},
                {id:'bbb',name:'热门推荐'},
                {id:'ccc',name:'家用家电'},
                {id:'ddd',name:'办公用品'},
              ]
            }
          },
          methods:{
            btnclick(item){
            console.log(item);
            }
          }
        }
        // 父组件
          const app = new Vue({
            el: '#app',//用于挂在要管理的元素
            data: {
              message: 'Hello Vue!',
              names:['京东','小米','美团']
            },
            components:{
              'cpn':cpn
            }
                            })             
      </script> 

自定义发射事件

代码思路:在子组件里面的method通过$emit()定义一个触发事件,发射事件名称为itemclick,参数为item。在父组件定义一个事件名为cpnclick的事件来监听(v-on)子组件模板的发射事件。

<body>
  <!-- 父组件模板 -->
    <div id="app">
        <cpn @itemclick="cpnclick"></cpn>
      </div>

<!-- 子组件模板 -->
      <template id='cpn'>
        <div>
          <button v-for="item in categories" @click="btnclick(item)">{{item.name}}</button>
        </div>
      </template>

      <script src="./js/vue.js"></script>
      <script>
        //子组件
        const cpn ={
          template:`#cpn`,
          props:{
           cnames:{
             type:Array
           } ,
           cmessage:{
             type:String
           }
          },
          data(){
            return{
              categories:[
                {id:'aaa',name:'电脑手机'},
                {id:'bbb',name:'热门推荐'},
                {id:'ccc',name:'家用家电'},
                {id:'ddd',name:'办公用品'},
              ]
            }
          },
          methods:{
            btnclick(item){
               this.$emit('itemclick',item)//发射一个事件,第一个参数为事件名称,第二个为事件参数
            }
          }
        }
        // 父组件
          const app = new Vue({
            el: '#app',//用于挂在要管理的元素
            data: {
              message: 'Hello Vue!',
              names:['京东','小米','美团']
            },
            components:{
              'cpn':cpn
            },
            methods:{
              cpnclick(item){
                console.log('cpnclick',item)
              }
            }
                            })             
      </script> 
</body>

打开网页随意点击一个按钮,在控制台可以看到点击的信息

3.3.2父子组件的访问方式

上面的父子通信方式都是通过子组件发射事件给父组件的,其实我们可以直接让父组件通过对象来访问子组件,或者子组件通过对象访问父组件。

1.父组件访问子组件:使用$clidren或$refs

父组件访问子组件一般用$refs,这个有点像class,$refs是对象类型,默认是一个空的对象,当给组件加 ref="aaa(id名)"时,在父组件里面调用 this.$refs.aaa.xxx就可以访问指定的子组件以及子组件里面的属性了。

举个栗子

<body>
    <div id="app">
        <div>
          <cpn ref="aaa">   
          </cpn>
          <button @click="btnclick">按钮</button>
        </div>
      </div>
      <template id="cpn">
        <div>
          我是子组件
        </div>
      </template>
      <script src="./js/vue.js"></script>
      <script>
          var app = new Vue({
            el: '#app',//用于挂在要管理的元素
            data: {
              message: 'Hello Vue!'//定义数据
            },
            methods:{
              btnclick(){
               console.log(this.$refs.aaa.name)
              }
            },

            components:{
              cpn:{
                template:`#cpn`,
                data(){
                  return{
                    name:'我是子组件的名字'
                  }
                },
              methods:{
                  showmessage(){
                    console.log('showmessage');
                  }
                }
              }
            }
         
                            })
                      
      </script> 

运行结果:点击按钮后

2.子组件访问父组件:$parent

几乎不用这个,这样用的话子组件的复用性就不强了。

补充:用$root可以访问根组件。

;