Vue组件使用组件定义&组件传值&组件插槽

定义全局组件

注意:

1.无论哪种方式定义组件,template属性的HTML结构中必须有且只有唯一一个根元素,否则会报错
2.在组件中定义data属性和Vue实例中不同,必须是定义一个方法,在方法中返回一个对象,如方式三中定义的.
3.局部注册的组件只能在注册它的父组件中使用.

方式一

	<dvi id="app">
        <my-component></my-component>
    </dvi>
    <script>
    	//使用Vue.extend来创建全局的vue组件对象
        var mycomponent = Vue.extend({
        //通过template属性指定组件要展示的HTML结构
            template: '

这是一个自定义的组件

'
}); //定义全局组件,Vue.component(组件名称,创建的Vue组件对象) //组件名称使用驼峰命名时,在引用组件时必须改写为my-component格式 Vue.component('myComponent', mycomponent); let vm = new Vue({ el: '#app', data: { } }); </script>

方式二

<div id="app">
        <mycomponent></mycomponent>
    </div>
    <script>
    	//这种方式实际上还是跟第一种方式一样,只是省略了先创建Vue组件对象,直接在组件定义时使用字面量的形式传递Vue组件对象参数
        Vue.component('mycomponent', {
            template: '

这是方式二创建的Vue组件

'
}); let vm = new Vue({ el: '#app' }); </script>

方式三

	<template id="temp">
        <div>
            <a href="">登录</a> | <a href="">注册</a>
            <div>{{msg}}</div>
        </div>
    </template>
    <div id="app">
        <mycomponet></mycomponet>
    </div>
    <script>
        Vue.component('mycomponet', {
            template: '#temp',
            data: function () {
                return {
                    msg: '组件定义中data属性返回的数据'
                }
            }
        });
        let vm = new Vue({
            el: '#app'
        });
    </script>

定义私有组件

	<div id="app">
        <mycomponent></mycomponent>

    </div>
    <template id="teml">
        <div>
            <h1>这是定义的私有组件</h1>
        </div>
    </template>
    <script>
        let vm = new Vue({
            el: '#app',
            components: {
                mycomponent: {
                    template: '#teml'
                }
            }
        });
    </script>

组件切换

方式一利用v-if,v-else:这样只能操作两个组件的切换,有局限性

	<div id="app">
        <input type="button" value="登录" @click="flag = true">
        <input type="button" value="注册" @click="flag = false">
        <login v-if="flag"></login>
        <register v-else="flag"></register>
    </div>
    <script>
        let vm = new Vue({
            el: '#app',
            data: {
                flag: false
            },
            components: {
                login: {
                    template: '

登录页面

'
}, register: { template: '

注册页面

'
} } }); </script>

方式二:利用元素的:is属性

	<div id="app">
        <input type="button" value="登录" @click="comName = 'login'">
        <input type="button" value="注册" @click="comName = 'register'">
        //是vue提供来展示对应名称的组件
        //:is属性用来指定要展示的组件的名称
        <components :is="comName"></components>
    </div>
    <script>
        let vm = new Vue({
            el: '#app',
            data: {
                // flag: false
                comName: ''
            },
            components: {
                login: {
                    template: '

登录页面

'
}, register: { template: '

注册页面

'
} } }); </script>

组件切换的动画

1,使用元素将要实现动画效果的组件包裹起来
2.通过元素的mode属性设置组件切换的模式

		.v-enter,
        .v-leave-to {
            opacity: 0;
            transform: translateX(100px);
        }

        .v-enter-active,
        .v-leave-active {
            transition: all 1s ease;
        }
		<transition mode="out-in">
            <components :is="comName"></components>
       	</transition>

组件传值

父组件向子组件传值

默认情况下,子组件无法直接访问到父组件data中的数据和methods中的方法,需要在引用子组件时通过v-bind:将要传递的数据绑定到子组件,然后在子组件的props中定义才可以使用

	<div id="app">
        <!-- 在引用子组件时,通过v-bind将要传递给子组件的数据以属性绑定的形式传递到子组件中 -->
        <mycomponent :parentmsg="msg"></mycomponent>
    </div>
    <script>
        let vm = new Vue({
            el: '#app',
            data: {
                msg: '这是父组件data中的msg数据'
            },
            components: {
                mycomponent: {
                    template: '

这是子组件!----{{parentmsg}}

'
, //把父组件中传递过来的数据先在props中定义,才能使用这个数据 //子组件props中的所有数据都是父组件传递给子组件的 //props中的数据都是只读的,无法重新赋值 props: ['parentmsg'] } } }); </script>

子组件向父组件中传递数据

原理:父组件将方法的引用,传递到子组件内部,子组件在内部调用父组件传递过来的方法,同时把要发送给父组件的数据,在触发方法的时候当作参数传递进去
this.$emit(‘自定义的事件名称’,参数1,参数2,…);触发绑定的自定义事件

	<template id="teml">
        <div>
            <h2>这是子组件</h2>
            <input type="button" value="这是子组件的按钮" v-on:click="sendMsg">
        </div>
    </template>
    <div id="app">
        //2.在子组件中v-on绑定自定义事件并且指向父组件中的方法
        //如果子组件触发事件时传递了参数,在父组件的方法中用必须用$event接收,可以省略不写,比如
        //但是如果方法后面跟了()则必须写
        <mycom v-on:parfun="getMsg($event)"></mycom>
    </div>
    <script>
        let vm = new Vue({
            el: '#app',
            data: {
                parentMsg: ''
            },
            methods: {
                //4.在父组件中定义的方法中接受传递过来的参数,这样就可以接收到子组件中的数据
                getMsg: function (data) {
                    console.log(data);
                    this.parentMsg = data;
                }
            },
            //1.定义一个子组件
            components: {
                mycom: {
                    template: '#teml',
                    data: function () {
                        return {
                            sonMsg: '这是子组件中的msg'
                        }
                    },
                    methods: {
                        sendMsg: function () {
                            //3.在子组件定义的方法中使用this.$emit触发自定义的事件实际就是触发事件指向的父组件中的方法,并且将data中的数据作为参数传递过去
                            //this.$emit('自定义的事件名称',参数1,参数2...)
                            this.$emit('parfun', this.sonMsg);
                        }
                    },
                }

            }
        });
    </script>

Vue父子组件通讯,遵循单向数据流,就是说只能从父组件到子组件,不能直接在子组件中修改父组件的数据,子组件要修改父组件中的数据,需要通过$emit(),触发自定义事件.

非父子组件之间传值

Vue组件使用组件定义&组件传值&组件插槽_第1张图片

 <div id="app">
        <test-tom></test-tom>
        <test-jerry></test-jerry>
    </div>
    <template id="tomTmpl">
        <div>
            <span>tom{{count}}</span>
            <input type="button" value="点击" @click="add()">
        </div>
    </template>
    <template id="jerryTmpl">
        <div>
            <span>jerry{{count}}</span>
            <input type="button" value="点击" @click="add()">
        </div>
    </template>
    <script>
        //1.定义事件中心,用来监听和触发自定义事件
        var hub = new Vue();
        let vm = new Vue({
            el: '#app',
            components: {
                'test-tom': {
                    template: '#tomTmpl',
                    data() {
                        return {
                            count: 0,
                            num: 3
                        }
                    },
                    methods: {
                        //3.定义一个方法,在方法内通过事件中心hub触发其他组件的自定义事件,并且传值过去
                        add: function () {
                            hub.$emit('add-jerry', this.num);
                        }
                    },
                    mounted() {
                        //2.定义自定义事件,$on(事件名称,事件处理函数),自定义事件可以在其他组件中通过事件中心hub被触发并且接收参数
                        hub.$on('add-tom', (val) => {
                            this.count += val;
                        });
                    },
                },
                'test-jerry': {
                    template: '#jerryTmpl',
                    data() {
                        return {
                            count: 0,
                            num: 1
                        }
                    },
                    //2.定义自定义事件,$on(事件名称,事件处理函数),自定义事件可以在其他组件中通过事件中心hub被触发并且接收参数
                    mounted() {
                        hub.$on('add-jerry', (val) => {
                            this.count += val;
                        })
                    },
                    methods: {
                        //3.定义一个方法,在方法内通过事件中心hub触发其他组件的自定义事件,并且传值过去
                        add: function () {
                            hub.$emit('add-tom', this.num);
                        }
                    },
                }
            }
        });
    </script>

销毁事件

	hub.$off('add-tom');
    hub.$off('add-jerry');

跨级传值

provide / inject这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深(普通组件传值只能父子或兄弟关系),并在起上下游关系成立的时间里始终生效。

provide 选项应该是:一个对象或返回一个对象的函数
inject 选项应该是:一个字符串数组,或 一个对象,对象的 key 是本地的绑定名
父组件中提供
  provide() {  //重要一步,在父组件中注入一个变量或函数
    return {
     msg: "demo"
      // 提示:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。
    }
  },
子组件中引入
  export default {
    inject: ['msg'],  // 子孙组件中使用inject接住变量即可,可直接在本组件调用或更改父组件传过来的变量
  }

运行顺序:
1.data
2.provide
3.created // 在这个阶段$el还未生成,在这先处理privide的逻辑,子孙组件才可以取到inject的值
4.mounted

组件插槽

插槽基本用法

	<div id="app">
        <!-- 2.组件标签中嵌套的内容会替换掉模板中所有的<slot>元素,如果组件标签中没有嵌套的内容,则会使用模板中slot中默认的值,如果都没有值,页面中不会渲染 -->
        <alert-box>有一个bug</alert-box>
        <alert-box>有一个警告</alert-box>
        <alert-box></alert-box>

    </div>
    <script>
        Vue.component('alert-box', {
            template: `
                
ERROR: //1.在子组件模板中定义元素(插槽),插槽内可以包含任何模板代码,包括HTML,当组件渲染时,元素将会被组件标签中嵌套的内容替换
`
, }); let vm = new Vue({ el: '#app', }); </script>

具名插槽

使用 中的 “name” 属性绑定元素

		<base-layout>
            <!-- 2.组件标签中嵌套的内容会替换掉模板中所有的<slot>元素,如果组件标签中没有嵌套的内容,则会使用模板中slot中默认的值,如果都没有值,页面中不会渲染 -->
            <!-- 通过slot属性来匹配子组件模板中插槽的那么属性,如果没有匹配到则不会渲染 -->
            <p slot="header">标题信息</p>
            <!-- 没有定义slot属性的内容会替换子组件模板中没有定义name属性的slot元素 -->
            <p>主要内容1</p>
            <p>主要内容2</p>
            <p slot="footer">底部信息信息</p>
        </base-layout>
        <base-layout>
        <!-- template元素是临时的包裹标签最终不会渲染到页面上 -->
            <template slot="header">
                <div>标题信息1</div>
                <div>标题信息2</div>
            </template>
            <div>主要内容1</div>
            <div>主要内容2</div>
            <template slot='footer'>
                <p>底部信息信息1</p>
                <p>底部信息信息2</p>
            </template>
        </base-layout>
    </div>
    <template id="tmpl">
        <div>
            <header>
                <!-- 1.在子组件模板中定义<slot>元素(插槽),插槽内可以包含任何模板代码,包括HTML,当组件渲染时,<slot>元素将会被组件标签中嵌套的内容替换 -->
                <!-- 使用name属性指定当前插槽的名字 -->
                <slot name="header1"></slot>
            </header>
            <main>
                <slot></slot>
            </main>
            <footer>
                <slot name="footer"></slot>
            </footer>
        </div>
    </template>
    <script>
        Vue.component('base-layout', {
            template: '#tmpl',
        });
        let vm = new Vue({
            el: '#app',
        });
    </script>

作用域插槽

  • 父组件对子组件加工处理
  • 既可以复用子组件的slot,又可以使slot内容不一致
<div id="app">
        <fruit-list :list="list">
            <!-- 2.slot-scope属性可以获取到子组件模板中<slot>元素自定义属性info绑定的数据 ,slotProps是变量,slotProps.info指向子组件模板中<slot>元素自定义属性info绑定的数据-->
            <template slot-scope="slotProps">
                <strong v-if="slotProps.info.id == 2" class="current">{{slotProps.info.name}}</strong>
            </template>
        </fruit-list>
    </div>
    <template id="tmpl">
        <div>
            <li v-for="item in list" :key="item.id">
                <!-- 1.定义<slot>元素,并且绑定自定义属性info, -->
                <slot :info="item">{{item.name}}</slot>
            </li>
        </div>
    </template>
    <script>
        Vue.component('fruit-list', {
            template: '#tmpl',
            props: ['list']
        });
        let vm = new Vue({
            el: '#app',
            data: {
                list: [{
                    id: 1,
                    name: 'apple'
                }, {
                    id: 2,
                    name: 'orange'
                }, {
                    id: 3,
                    name: 'banana'
                }]
            }
        });
    </script>

你可能感兴趣的:(Vue组件使用组件定义&组件传值&组件插槽)