vue组件的详细介绍

核心目标

为了可重用性高,减少重复性开发,我们可以按照template、style、script的拆分方式,放置到对应的.vue文件中。

组件概括

vue组件可以理解为预先定义好的ViewModel类。一个组件可以预定义很多选项,最核心的有:
  1. 模板template:模板反映了数据和最终展现给用户的DOM之间的映射关系,
  2. 初始数据data:一个组件的初始数据状态,对于可重复的组件来说,通常是私有的状态。
  3. 接收的外部的参数(props):组件之间通过参数来进行数据的传递和共享,参数默认是单项绑定,但也可以显示声明为双向绑定。
  4. 方法(methods):对数据的改动操作一般都在组件内进行。可以通过v-on指令将用户输入事件和组件方法进行绑定。
  5. 生命周期函数(钩子函数):一个组件会触发多个生命周期函数,在这些钩子函数中可以封装一些自定义逻辑。可以理解为controller的逻辑被分散到了这些钩子函数中。

注册组件

注册组件就是利用Vue.component()方法,先传入一个自定义组件的名字,然后传入这个组件的配置。

(组件名不要带有大写字母,多个单词使用中划线my-dom)

  • 全局组件
    (直接使用Vue.component()创建的组件,所有的Vue实例都可以使用。)
    (一般写插件的时候全局组件使用多一些)
 Vue.component('mycomponent',{      //自定义组件名mycomponent
    template: `<div>这是一个自定义组件</div>`,
    data () {
      return {
        message: 'hello world'
      }
    }
  })
  • 局部注册组件
    使用三部曲1.创建这个组件;2.注册这个组件;3.使用这个组件;
<div id="app">
    <mycomponent></mycomponent>   //3.组件的使用
    <my-component></my-component>    //3.组件的使用
</div>
<script>
  //1.创建这个组件
  let  mycomponent={
      template: `<div>这是一个局部的自定义组件,只能在当前Vue实例中使用{{aa}}</div>`,
      data(){
        return {'aa':'hello'}
      }
   };

  let  app = new Vue({
    el: '#app',
    data: {
    },
    components: {
      mycomponent,//2.注册这个组件
      }
    }
  })
</script>
  • 模板的要求:组件的模板只能有一个根元素。
template: `<div>
                元素1.....
                元素2.....
                元素3.....
           </div>`,
  • 组件中的data必须是函数。
data:function(){
            return {'aaa':'bbb'}//template中可以使用aaa
        },
  • 组件的属性props。
    Vue组件通过props属性来声明一个自己的属性,然后父组件就可以往里面传递数据。
<div id="app1">
    动态操作属性:name是变量(读取实例中data的值)
    <hello :n="name"></hello>
</div>
<div id="app2">
    静态的属性:name是常量(就是name)
    <hello n="name"></hello>
</div>
<script>
    Vue.component('hello',{
        props:['n'],//通过父组件传过来的数据 name变量
        data:function(){
            return {'aaa':'bbb'}
        },
        template:'<p>{{aaa}} {{n}}</p>'
    })
    var app1=new Vue({
        el:'#app1',
        data:{
            name:'haha'
        }
    })
    var app2=new Vue({
        el:'#app2',
        data:{
            name:'haha'
        }
    })
</script>

渲染结果


props.png
  • props的验证。

组件之间的通信

子组件给父组件传递数据,利用事件的订阅发布模式
  • 1.给子组件的template上的元素绑定事件(如click),执行子组件的方法(如changeData),子组件的方法中发射一个事件(如s),传一个数据(如lalala);
  • 2.父组件中,定义一个方法(如getData)用来拿到子组件的数据。
  • 3.在自定义的组件上绑定子组件传过去的事件(s),执行事件(s)执行的是getData函数,getData函数中拿到数据(data,就是子组件传过去的lalala)。
<div id="app">
    <parent></parent>
</div>
<template id="parent">
    <div>
        <p>父组件{{msg}}</p>//点击子组件触发getData获取到子组件转来的msg数据,绑定到父组件上
        <children @s="getData"></children>
    </div>
</template>
<script>
    var app=new Vue({
        el:'#app',
        components:{
            parent:{
                template:'#parent',
                data(){
                    return {msg:'aaa'};
                },
                methods:{
                    getData(data){
                        alert(data);//子组件传过来的数据
                        this.msg=data;
                    }
                },
                components:{
                    children:{
                        template:'<p @click="changeData">子组件</p>',
                        methods:{
                            changeData(){
                                this.$emit('s','lalala');//传递给父组件
                            }
                        }
                    }
                }
            }
        }
    })
</script>
父组件给子组件传递数据(利用props属性)
<div id="app">
    <parent></parent>
</div>

<script>
    var app=new Vue({
        el:'#app',
        components:{//一个父组件里边可以包含多个子组件
            parent:{
                template:'<h1 >{{msg}},父组件<children :n="msg"></children></h1>',
                data:function(){//父组件的数据 传给子组件
                    return {msg:'hello'}
                },
                components:{
                  children:{
                      props:['n'],//根据props拿到父组件中写的动态属性拿到数据
                      template:'<h2>{{n}},子组件</h2>',
                  }
                }
            }
        }
    })
兄弟组件之间传递数据 (事件车---原理也是事件的订阅发布模式)
注意:
  • 每一个vue的实例都是独立的;相互之间不能直接进行改变数据;
  • 给两个不同的组件找一个载体;把共同的方法放在这个载体上;
  • 这个载体就是 let eventBus = new Vue; // 创建一个新的vue实例;
  • 在这个新的实例上,有 $on: 订阅 $emit: 发布;
  • $on的绑定要基于钩子函数,一般放在created或者mounted上
<div id="app">
    <tmp1></tmp1>
    <tmp2></tmp2>
</div>

<script>
    var eventBus=new Vue();
    var app = new Vue({
        el: '#app',
        data: {},
        components: {
            tmp1: {
                template: "<h1>组件1{{msg}}</h1>",
                data(){
                    return {msg:""}
                },
                mounted(){//钩子函数,页面一加载进来的时候就已经绑定好了
                   eventBus.$on('aaa',(data)=>{
                        this.msg=data;
                    })
                }
            },
            tmp2: {
                template: "<h1 @click='sendData'>组件2{{msg}}</h1>",
                data(){
                    return {msg: 'hello'}
                },
                methods:{
                    sendData(){
                        //发布数据
                        eventBus.$emit('aaa',this.msg)
                    }
                }
            }
        }
    })
</script>

数据同步(子组件的数据和父组件保持一致)

数据同步的核心:父组件给子组件传递“引用数据类型的数据”;
<div id="app">
<parent></parent>
</div>
<template id="parent">
<div>
    <h1>父组件 <mark>{{msg.name}}</mark></h1>
    <children :n="msg"></children>
</div>
</template>
<template id="children">
    <h2 @click="changeData">子组件 {{n.name}}</h2>
</template>
<script>
    //数据同步的核心:父组件给子组件传递“引用数据类型的数据”;
    var app=new Vue({
        el:'#app',
        components:{
            parent:{
                template:'#parent',
                data(){
                    return {msg:{name:'hahha'}}
                },
                components:{
                    children:{
                        props:['n'],
                        template:'#children',
                        methods:{
                            changeData(){
                                this.n.name='lallala'
                            },
                        }
                    }

                }
            }
        }
    })
</script>
数据不同步(不直接使用父组件传的值,用data属性再自己的组件内做一个中间变量,防止报错)
<parent></parent>
</div>
<template id="parent">
<div>
    <h1>父组件 <mark>{{msg}}</mark></h1>
    <children :n="msg"></children>
</div>
</template>
<script>
    //数据不同步的核心:中间变量接收避免报错;
    var app=new Vue({
        el:'#app',
        components:{
            parent:{
                template:'#parent',
                data(){
                    return {msg:'hahha'}
                },
                components:{
                    children:{
                        props:['n'],
                        template:'<h2 @click="changeData">子组件 {{b}}</h2>',
                        data(){
                            return {b:this.n}
                        },
                        methods:{
                            changeData(){
                                this.b='lallala'
                            },
                        }
                    }
                }
            }
        }
    })
</script>

组件切换

js动态控制template(也可以用is属性控制)
<div id="app">
    <div class="container">
        <div @click="comp='zujian1'">显示组件1</div>
        <div @click="comp='zujian2'">显示组件2</div>
    </div>
    <!--aaa标签是核心,必须得写,通过is决定显示那个组件-->
    <aaa :is="comp"></aaa>
</div>

<script>
    var app=new Vue({
        el:'#app',
        data:{
            comp:'zujian2',
        },
        components:{
            zujian1:{
                template:'<h1>组件1</h1>'
            },
            zujian2:{
                template:'<h1>组件2</h1>'
            }
        }
    })
</script>

插槽(slot官网有详细介绍)

slot相当于子组件设置了一个地方,如果在调用它的时候,往它的开闭标签之间放了东西,那么它就把这些东西放到slot中。
  1. 当子组件中没有slot时,父组件放在子组件标签内的东西将被丢弃;
  2. 子组件的slot标签内可以放置内容,当父组件没有放置内容在子组件标签内时,slot中的内容会渲染出来;
  3. 当父组件在子组件标签内放置了内容时,slot中的内容被丢弃
    实例:
<div id="app">
    <hello>//使用组件
        lalalala
        <!--给插槽起好名字-->
        <div slot="div1">1111111111111</div>
        <div slot="div2">2222222222222</div>
    </hello>
</div>
<template id="temp1">//模板
    <h1>
        hello
        <!--无名插槽-->
        <slot></slot>
        <!--有名插槽 可以根据插槽切换顺序-->
        <slot name="div2"></slot>
        <slot name="div1"></slot>
    </h1>
</template>
<script>
    var app=new Vue({
        el:'#app',
        data:{

        },
        components:{
            hello:{
                template:"#temp1"
            }
        }
    })

组件文件示例

父组件.vue

<template>
    <div class="">
        <div class="home-container">
            <Banner></Banner>
            <quick-link :allAmount="allAmount"> </quick-link>
            <Recommended></Recommended>
        </div>
       <m-footer></m-footer>
    </div>
</template>

<script>
    import axios from 'axios'
    import MFooter from '../footer.vue'
    import Banner from './banner.vue'
    import QuickLink from './quickLink.vue'
    import Recommended from './recommended.vue'
    import {setSession} from '../../common/userCenter'
    import {loadAppHomeAct,loadStatisticalData} from '../../api/api'
    export default {
        data(){
            return{
                allAmount:[]
            }
        },
        components:{
            MFooter,
            Banner,
            QuickLink,
            Recommended
        },
        created(){
            this.fetchCookies();
        },
        methods:{
           getQueryString: function (name) {
                var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
                var url=decodeURIComponent(window.location.search);
                var r = url.substr(1).match(reg);
                if (r != null) return (r[2]);
                return "";
            }
        }
    }
</script>

<style>
    @import "home.css";
</style>

链接到路由配置

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容