VUE03_组件化思想、全局|局部注册、组件之间传值(父传子、子传父、兄弟传兄弟)、匿名|具名|作用域插槽

①. 组件化思想

  • ①. 所谓组件化,就是把页面拆分成多个组件,每个组件自己管理所依赖的 CSS、JS、模板、图片等资源

  • ②. 组件与组件之间通过特定的规则进行数据传递、就会行成树状结构
    在这里插入图片描述

②. 全局注册

  • ①. Vue.component(‘组件名称’, { }) 第1个参数是标签名称,第2个参数是一个选项对象

  • ②. 注意事项:

  1. data必须是一个函数
  2. 组件模板必须是单个根元素(下面这个是错误的,没有根元素)
  3. 组件模板的内容可以是模板字符串
  • ③. 组件命名规则
  1. 如果使用驼峰式命名组件,那么在使用组件的时候,只能在字符串模板中用驼峰的方式使用组件
  2. 但是在普通的标签模板中,必须使用短横线的方式使用组件
  • ④. 案列演示
<body>
    <div id="app">
        <!--你可以将组件进行任意次数的复用:因为data中返回的是一个对象所以每个组件中的数据是私有的-->
        <button-count></button-count>
        <button-count></button-count>
        <!--必须使用短横线的方式使用组件-->
        <button-count></button-count>
    </div>
    <script src="../js/vue.js"></script>
    <script>
    Vue.component('button-count',{
        //1. data必须是一个函数
        data:function(){
            return{
               count:0
            }
        },
        //2. 组件模板必须是单个根元素(下面这个是错误的,没有根元素)
        //template:'<button @click="handle()">已经点击了{{count}}次了</button><button></button>',
        //3. 组件模板的内容可以是模板字符串
        //template:'<button @click="handle()">已经点击了{{count}}次了</button>',
        template:`
        <button @click="handle()">已经点击了{{count}}次了</button>
        `,
        methods:{
            handle(){
                this.count+=2
            }
        }

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

③. 局部注册

  • ①. 只能在当前注册它的vue实例中使用

  • ②. 注意:局部注册的组件、指令、过滤器等、都只能在父组件(它的实例)中使用

  • ③. 代码展示

 <div id="app">
        <hello-word></hello-word>
    </div>
    <script src="../js/vue.js"></script>
    <script>
    /*
    局部组件(局部组件只能在注册他的父组件中使用)
    */
    var  HelloWorld={
        data:function(){
            return{
               msg:'xiaozhi'
            }
        },
        template:'<div>{{msg}}</div>'
    };
    var vm=new Vue({
            el:'#app',
            data:{    
          
            },
            components:{
                'hello-word':HelloWorld
            }
    });
    </script>
</body>
</html>
import ComponentA from './ComponentA.vue'

export default {
  components: {
    ComponentA
  },
  // ...
}

④. 父组件向子组件传值

  • ①. 父组件发送的形式是以属性的形式绑定值到子组件身上

  • ②. 然后子组件用属性props接收

  • ③. 在props中使用驼峰形式,模板中需要使用短横线的形式字符串形式的模板中没有这个限制

  • ④. 数值与布尔值要通过v-bind动态获取、否则静态的是字符串

<body>
    <div id="app">
        <!-- 注意:p-number 和 p-boolean 如果前面不加v-bind绑定的话,类型是字符串类型 -->
        <menu-titile :pstring='pString' :pnumber='2' :pboolean=true :pfriut='pFruit' :pobject='pObject'></menu-titile>
    </div>
    <script src="../js/vue.js"></script>
    <script>

    Vue.component('menu-titile',{
        props:['pstring','pnumber','pboolean','pfriut','pobject'],
        template:`
        <div>
        <div>{{pstring}}</div>
        <div>{{typeof pnumber}}</div>
        <div>{{typeof pboolean}}</div>
        <ul>
            <li :key="index" v-for="(item,index) in pfriut">{{item}}</li>
        </ul>
        <ul>
            <li :key="index" v-for="(value,key,index) in pobject">{{key+"----"+value+"-----"+index}}</li>
        </ul>
     
        </div>
        `
    });    
    var vm=new Vue({
            el:'#app',
            data:{    
               pString:'xiaozhi',
               pFruit:['香蕉','葡萄','苹果'],
               pObject:{"name":"xiaozhi","age":24,"gender":"male"}
            }
    });
    </script>
</body>
</html>

⑤. 子组件向父组件传值

  • ①. 子组件用$emit()触发事件

  • ②. $emit() 第一个参数为 自定义的事件名称 第二个参数为需要传递的数据

  • ③. 父组件用v-on 监听子组件的事件

  • ④. 如果父组件获取子组件的值还可以通过: this.$refs.menuRef.的方式获取子组件中prop定义的内容

<div id="app">
    <div :style='{fontSize: fontSize + "px"}'>{{pmsg}}</div>
     <!-- 2 父组件用v-on 监听子组件的事件
		这里 enlarge-text  是从 $emit 中的第一个参数对应   handle 为对应的事件处理函数	
	-->	
    <menu-item ref=“menuRef” :parr='parr' @enlarge-text='handle($event)'></menu-item>
  </div>
  <script type="text/javascript" src="js/vue.js"></script>
  <script type="text/javascript">
    /*
      子组件向父组件传值-携带参数
    */
    
    Vue.component('menu-item', {
      props: ['parr'],
      template: `
        <div>
          <ul>
            <li :key='index' v-for='(item,index) in parr'>{{item}}</li>
          </ul>
			###  1、子组件用$emit()触发事件
			### 第一个参数为 自定义的事件名称   第二个参数为需要传递的数据  
          <button @click='$emit("enlarge-text", 5)'>扩大父组件中字体大小</button>
          <button @click='$emit("enlarge-text", 10)'>扩大父组件中字体大小</button>
        </div>
      `
    });
    var vm = new Vue({
      el: '#app',
      data: {
        pmsg: '父组件中内容',
        parr: ['apple','orange','banana'],
        fontSize: 10
      },
      methods: {
        handle: function(val){
          // 扩大字体大小
          this.fontSize += val;
        }
      }
    });
  </script>

⑥. 兄弟之间的传递

  • ①. 兄弟之间传递数据需要借助于事件中心,通过事件中心传递数据
    提供事件中心 var hub = new Vue()

  • ②. 传递数据方,通过一个事件触发hub.$emit(方法名,传递的数据)

  • ③. 接收数据方,通过mounted(){} 钩子中 触发hub.$on()方法名

  • ④. 销毁事件 通过hub.$off()方法名销毁之后无法进行传递数据

 <div id="app">
    <div>父组件</div>
    <div>
      <button @click='handle'>销毁事件</button>
    </div>
    <test-tom></test-tom>
    <test-jerry></test-jerry>
  </div>
  <script type="text/javascript" src="js/vue.js"></script>
  <script type="text/javascript">
    /*
      兄弟组件之间数据传递
    */
    //1、 提供事件中心
    var hub = new Vue();

    Vue.component('test-tom', {
      data: function(){
        return {
          num: 0
        }
      },
      template: `
        <div>
          <div>TOM:{{num}}</div>
          <div>
            <button @click='handle'>点击</button>
          </div>
        </div>
      `,
      methods: {
        handle: function(){
          //2、传递数据方,通过一个事件触发hub.$emit(方法名,传递的数据)   触发兄弟组件的事件
          hub.$emit('jerry-event', 2);
        }
      },
      mounted: function() {
       // 3、接收数据方,通过mounted(){} 钩子中  触发hub.$on(方法名
        hub.$on('tom-event',val=>   this.num += val);
      }
    });
    Vue.component('test-jerry', {
      data: function(){
        return {
          num: 0
        }
      },
      template: `
        <div>
          <div>JERRY:{{num}}</div>
          <div>
            <button @click='handle'>点击</button>
          </div>
        </div>
      `,
      methods: {
        handle: function(){
          //2、传递数据方,通过一个事件触发hub.$emit(方法名,传递的数据)   触发兄弟组件的事件
          hub.$emit('tom-event', 1);
        }
      },
      mounted: function() {
        // 3、接收数据方,通过mounted(){} 钩子中  触发hub.$on()方法名
        hub.$on('jerry-event', val => this.num += val);
      }
    });
    var vm = new Vue({
      el: '#app',
      data: {
        
      },
      methods: {
        handle: function(){
          //4、销毁事件 通过hub.$off()方法名销毁之后无法进行传递数据  
          hub.$off('tom-event');
          hub.$off('jerry-event');
        }
      }
    });
  </script>

⑦. 匿名插槽

  • ①. slot接收父组件开始与闭合中间的内容

  • ②. 使用该组件时:组件标签中间写的内容会传递到中

  • ③. 如果没有传递内容:solt中可自定义内容

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<!--
slot接收父组件开始与闭合中间的内容、
使用该组件时:组件标签中间写的内容会传递到中
如果没有传递内容:solt中可自定义内容
 -->
<body>
    <div id="app">
        <!-- 这里的所有组件标签中嵌套的内容会替换掉slot,如果不传值则使用slot中的默认值(slot接收父组件开始与闭合中间的内容) -->
        <alert-box>出现bug了</alert-box>
        <!-- 使用该组件时:组件标签中间写的内容会传递到中 -->
        <alert-box>出现了一个警告</alert-box>
        <!-- 如果没有传递内容:solt中可自定义内容 -->
        <alert-box></alert-box>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        Vue.component('alert-box', {
            //当组件渲染的时候,这个 <slot> 元素将会被替换为"组件标签中嵌套的内容"
            //插槽内可以包含任何模板代码,包括 HTML
            template: `
                <div>
                    <span>ERROR</span>
                    <slot>默认内容</slot>
                </div>
            `
        });
        var vm = new Vue({
            el: '#app',
            data: {

            }
        });
    </script>
</body>
</html>

⑧. 具名插槽

  • ①. 具有名字的插槽,使用中的"name"属性绑定元素
 <div id="app">
    <base-layout>
       <!-- 2、 通过slot属性来指定, 这个slot的值必须和下面slot组件得name值对应上
				如果没有匹配到 则放到匿名的插槽中   --> 
      <p slot='header'>标题信息</p>
      <p>主要内容1</p>
      <p>主要内容2</p>
      <p slot='footer'>底部信息信息</p>
    </base-layout>

    <base-layout>
      <!-- 注意点:template临时的包裹标签最终不会渲染到页面上     -->  
      <template slot='header'>
        <p>标题信息1</p>
        <p>标题信息2</p>
      </template>
      <p>主要内容1</p>
      <p>主要内容2</p>
      <template slot='footer'>
        <p>底部信息信息1</p>
        <p>底部信息信息2</p>
      </template>
    </base-layout>
  </div>
  <script type="text/javascript" src="js/vue.js"></script>
  <script type="text/javascript">
    /*
      具名插槽
    */
    Vue.component('base-layout', {
      template: `
        <div>
          <header>
			###	1、 使用 <slot> 中的 "name" 属性绑定元素 指定当前插槽的名字
            <slot name='header'></slot>
          </header>
          <main>
            <slot></slot>
          </main>
          <footer>
			###  注意点: 
			###  具名插槽的渲染顺序,完全取决于模板,而不是取决于父组件中元素的顺序
            <slot name='footer'></slot>
          </footer>
        </div>
      `
    });
    var vm = new Vue({
      el: '#app',
      data: {
        
      }
    });
  </script>
</body>
</html>

⑨. 作用域插槽

  • ①. 父组件对子组件加工处理

  • ②. 既可以复用子组件的slot,又可以使slot内容不一致

<body>
    <div id="app">
        <fruit-list :list='list'>
            <!-- 父组件中使用了<template>元素,而且包含scope="slotProps",
			slotProps在这里只是临时变量 -->
            <!-- 2、在父组件中通过slot-scope中的自定义值(slotProps)去接收solt传递过来的属性 -->
            <template slot-scope='slotProps'>
                <!-- 3、使用使用自定义属性去调用slot中接收过的数据、然后做操作 -->
                <strong class="current" v-if='slotProps.info.id==3'> {{slotProps.info.name}}</strong>
                <span v-else> {{slotProps.info.name}}</span>
            </template>

        </fruit-list>
    </div>
</body>
<script src="../js/vue.js"></script>
<script>
    //作用域插槽
    Vue.component('fruit-list', {
        props: ['list'],
        //   ### 1、在slto子组件中通过v-bind定义要传递的数据
        template:
            `
          <div>
            <li v-for='(item,index) in list' :key='item.id'>
             <slot :info='item'>{{item.name+"----"+index}}</slot>
            </li>
           </div>
          `
    })
    var vm = new Vue({
        el: '#app',
        data: {
            list: [{
                id: 1,
                name: 'apple',
            }, {
                id: 2,
                name: 'orange',
            }, {
                id: 3,
                name: 'bannana',
            },]
        }
    })
</script>
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

所得皆惊喜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值