Vue之组件

组件
    1.组件(component)是Vue最强大的功能,组件可以扩展HTML元素,封装可重用的代码,在较高层面上,组件是自定义元素,Vue编译器为它添加新特性,在有些情况下,组件也可以是原生的HTML形式,以is特性扩展。
    2.使用组件
        1.全局组件:Vue.component
        <div id="box">
                <hello></hello>
        </div>
    //vue组件component。全局组件,可以在多个定义的Vue根元素里面使用,状态没办法在状态中进行共享,name不能在VM的根元素data中定义,data如果要在组件中使用就必须设置成一个function而不是对象
    Vue.component('hello',{
        template:`
        <div>
            我是hello全局组件,实现data里面的对象通信,data中的name为{{name}}
            <hellochild></hellochild>
        </div>`,
        data:function(){//data必须要设置成方法才能让状态共享
            return{
                name:'xiaowang',
            }
        },
        //也可以写子组件
        components:{
            'hellochild':{
                template:``,
            }
        },
        methods: {
        },
    })
        2.局部组件
        <div id="box">
                <hello3></hello3>
        </div>
    var vm = new Vue({
        el:'#box',
        data:{
            myText:'',
        },
        components:{
            'hello3':{
                template:`
                <div>我是属性的hello3局部组件,</div>`,
            },
        }
    });
        3.data必须是函数
        4.注意点
            1.自定义组件需要有一个root element
            2.父子组件的data无法共享,
            3.组件有data,methods,computed。。但是data必须是一个函数
        5.组件意味着协同工作,通常父子组件会是这样的关系,组件A在它的模板中使用了组件B,它们之间必然需要通信,父组件要给子组件传递数据,子组件需要将组件内发生的事情告知父组件。然后,在一个良好定义的接口中将父子组件解耦是很重要的,这保证了各个组件在相对独立的空间书写和理解,也大幅度的提高了组件的可维护性和重用性。在Vue中,父子组件通信可总结为,props down,events up,父组件通过props给子组件传递信息,而子组件则通过events给父组件报告数据
    3.prop
        <div id="box">
            <!-- 设置子组件的属性,通过使用props来进行通信 -->
            <hello2 name="sarah" age="100"></hello2>
        </div>
    var vm = new Vue({
        el:'#box',
        data:{
            name:'xiaolv',
        },
        //局部组件,只能在vm #box这个根元素中使用
        components:{
            'hello2':{
                template:`
                <div>
                    我是属性name为{{name}},age为{{age}}的hello2局部组件,用来实现子组件的属性绑定
                </div>`,
            //组件中属性的通信,
            props:['name','age'],
            },
        },
        
    });
        1.prop传递数据,props:["name"]
        2.单向数据流,防止组件无意间改变了父组件的状态。
            注意:不要在子组件修改prop-单向数据流
        3.prop验证 props:{name:Number},我们可以为组件props指定验证规格,如果传入的数据不符合规格,Vue会发出警告,当组件给其他人使用时,这很有用,要指定验证规格,要使用对象形式,而不能使用字符串数组。
                props:{
                    name:String,
                    age:Number
                },
    4.自定义事件
        1.使用$on(eventname)监听事件
          使用$emit(eventname)触发事件
    <div id="box">
        <!-- 设置父组件监控子组件的方法名event -->
        <hello @event="handleParentClick"></hello>
    </div>
    Vue.component('hello',{
        //在template这个key值可以写HTML的DOM结构,用es6的字符串模板,chrome是支持的,如果不支持的浏览器可以用wellpack
        template:`
        <div>
            我是hello全局组件,实现data里面的对象通信,data中的name为{{name}}
            <ul>实现data对象中dataList的属性遍历
                <li v-for="data in dataList">{{data}}</li>
                <li><button @click="handleclick">用event和emit实现父子组件通信click事件</button></li>
            </ul>
        </div>`,
        data:function(){//必须要设置成方法才能让状态共享
            return{
                name:'xiaowang',
                dataList:['aaa','bbb','ccc'],
            }
        },
        methods: {
            handleclick(){
                //子组件事件分发,使用父组件方法中的函数名event,因为将来一个子组件可能会有很多的触发事件,所以要对应每一个方法名,也可以给父元素的方法传送数据,逗号后面跟上需要传送的数据。父元素中加入形参data就行
                this.$emit('event',this.name);
            },
        },
    })
    var vm = new Vue({
        el:'#box',
        data:{
            name:'xiaolv',
        },
        methods:{
            //父组件监听子组件hello的事件
            handleParentClick(data){
                console.log('parentClick' + data);
            },
        },
        
    });
        2.v-model父子通信
            props:["value"];
            this.$emit("input","***");
             <input v-model="something"/> 实际上等于下面语法糖 <input v-bind:value="something" v-on:input="something = $event.target.value"/> 
    <!-- 用v-model父子通信, -->
    <div id="box2">
        <!-- 用v-model来实现父子组件的通信,将会更简单,在父元素data中添加myText的字符串属性 -->
        <p>用v-model来实现父子组件的通信,我是父组件data中的myText值{{myText}},可以接收来自子组件hello3的input中的值{{myText}}</p>
        <hello3 v-model="myText"></hello3>
    </div>
    //用来实现v-model父组件和子组件的通信
    var vm2 = new Vue({
        el:'#box2',
        data:{
            myText:'',
        },
        components:{
            //用来实现v-model的父子组件通信
            'hello3':{
                template:`
                <div>
                    //我是属性的hello3局部组件,用来实现v-model父组件和子组件的通信
                    <input type="text" :value="value" @input="handleInput"/>
                </div>`,
                //如果要实现父子组件通信,这里的值必须用value,它会将父组件中data中的myText值传递给子组件的中的input中:value的值,如果要实现子组件对父组件的传递信息则要添加@input="handleInput",并且在子组件的methods方法中添加handleInput方法this.$emit('input',ev.target.value);
                props:['value'],
                methods:{
                    handleInput(ev){
                        //因为监听事件v-model实际会分成v-on:input
                        this.$emit('input',ev.target.value);
                    }
                },
            },
        }
    });
        3.非父子通信
            1.中央事件总线 bus = new Vue();
                注意:mounted生命周期中进行监听
<!-- 非父子通信,可以使用子传父,然后父传子的方式,也可以使用中央bus的方法,其实就是创建一个空Vue然后监听事件。 -->
    <div id="box3">
        <zujian1></zujian1>
        <zujian2></zujian2>
    </div>
    //非父子通信,用中央bus来实现,这种方式只适用于简单的场景,如果是大型的网站的项目,我们必须要用Vuex做状态管理。
    var bus = new Vue();//声明一个bus总线来调度通信
    var vm3 = new Vue({
        el:'#box3',
        data:{
            name:'ak47',
        },
        components:{
            zujian1:{
                data:function(){
                    return{
                        name:'我是组件1的data中的name',
                    }
                },
                template:`<div>我是组件1
                <button @click="handleClick">实现非父子通信</button>
                </div>`,
                
                methods:{
                    handleClick(){
                        //用一个Vue的空组件来发送一个xiaoming的事件
                        bus.$emit('xiaoming',this.name)
                    },
                },
            },
            zujian2:{
                template:`<div>我是组件2</div>`,
                //只要是组件都会有生命周期,当DOM组件渲染挂载完成的时候,这个声明周期就会自动的执行,声明周期的钩子函数,
                mounted() {
                    console.log('来自钩子函数');
                    //用Vue的空控件bus来监听$on 接收 xiaoming这个事件
                    bus.$on('xiaoming',function(value){
                        console.log(value);
                    });
                },
            },
        },
    });
            2.vuex状态管理 
      非父子通信,用中央bus来实现,这种方式只适用于简单的场景,如果是大型的网站的项目,我们必须要用Vuex做状态管理
    5.插槽分发内容
        为了让组件可以组合,我们需要一种方式来混合父组件的内容与子组件自己的模板,这个过程就叫做内容分发。(或transclution,如果你熟悉angular)。Vue实现了一个内容分发API,参照了当前Web组件规范草案,使用特殊的<slot>元素作为原始内容的插槽
            1.单个slot
            2.具名slot
    <!-- 实现内容分发,直接在组件中写如button,这样直接在元素中写指令的时候,就不存在什么父子组件传递信息的问题,直接在父组件调用methods方法就可以了。 -->
    <div id="box4">
        <zujian>
            <button @click="handleClick" slot="leftBtn">leftbutton</button>
            <div>我在中间</div>
            <button @click="handleClick" slot="rightBtn">rightbutton</button>
        </zujian>
    </div>
    /* 插槽分发内容 */
    var vm4 = new Vue({
        el:'#box4',
        data:{

        },
        methods:{
            handleClick(){
                console.log(11);
            }
        },
        components:{
            zujian:{
                template:`<div>我是组件
                <slot name="leftBtn"></slot>//具名slot
                <slot></slot>//单个slot
                <slot name="rightBtn"></slot>
                </div>`,//在字符串模板中写如slot插槽,在html中插入zujian这个元素会自动插入这个位置,可以给插槽具名,让对应的元素插入这个插槽
            },
        }
    });
    6.动态组件
        1.component元素,动态的绑定多个组件到它的is的属性
        2.keep-alive,保留状态,避免被重复渲染。
        html,body{width: 100%;height: 100%;}
        #box5{overflow-x: hidden;}
        #box5 ul{display: flex;width: 100%;height: 40px;position: fixed;left: 0;bottom: 0;}
        #box5 ul li{flex: 1;height: 40px;line-height: 40px;background: #333;list-style: none;}
        /* css动画效果animate,确保html元素transition的name和类开始名字一致bounce */
        .bounce-enter-active{animation: bounce-in .5s;}
        .bounce-leave-active{animation: bounce-in .5s reverse;}
        @keyframes bounce-in {
            0%{transform: scale(0);}
            50%{transform: scale(1.5);}
            100%{transform: scale(1);}
        }
    <!-- 动态组件,使用component组件,在components的组件中定义好每个组件和名字,用v-bind它的属性is的值来自定义的来动态的实现切换页面,在footer的点击事件中传入相应的值是和子组件的名字一一对应的。 每次点击都会重新创建页面和销毁前一个页面,但是如果页面内容中有需要保持内容的信息存在,比如在home页中有一个输入框文本按钮,需要用到keep-alive来实现内容的缓存-->
    <div id="box5">
        <keep-alive>
            <!-- 可以呈现的组件添加一个过渡效果,这里实现的是多组件的过渡效果 -->
            <transition name="bounce" mode="out-in">
                <component :is="current"></component>
            </transition>
        </keep-alive>
        <footer>
            <ul>
                <li @click="handleClick('home')">home</li>
                <li  @click="handleClick('list')">list</li>
                <li  @click="handleClick('shopcart')">shopcart</li>
            </ul>
        </footer>
    </div>
    /* 动态组件 */
    var vm5 = new Vue({
        el:'#box5',
        data:{
            current:'home',
        },
        components:{
            home:{
                template:`<div>我是home<input type="text"/>
                </div>`,
            },
            list:{
                template:`<div>我是list</div>`,
            },
            shopcart:{
                template:`<div>我是shopcart</div>`,
            },
        },
        methods:{
            handleClick(data){
                this.current = data;
            },
        },
    })

 

posted @ 2019-10-29 14:21  solaris-wwf  阅读(176)  评论(0)    收藏  举报