10-04-vue组件

组件

什么是组件

在html中,我们学习的单元是标签。 可以把Html中的标签当成最小最小最小的组件。
在vue中,我们学习的单元是组件
组件就是我们自己扩展的 “HTML 元素”,封装可重用的代码。
在较高层面上,组件是自定义元素, Vue.js 的编译器为它添加特殊功能。
组件(Component)是 Vue.js 最强大的功能之一。
在vue当中,一切都是组件,写项目就是在写组件。
一个组件本质就是一个对象。
区别:

  • 根组件(vue的实例)它有el。而子组件中有template
  • data的写法不同。根组件中就是对象,子组件中是函数。

子组件中,同样可以也包含子组件

什么是根组件

let vm = new Vue({}) 我们得到 的vm是一个Vue的一个对象(或者叫实例)
它也可以理解为一个组件,只不过它是一切其它的组件的根组件
一个项目就通常只有一个根组件

子组件

  • 全局组件 全局注册一个子组件
  • 局部组件 局部注册一个子组件

组件三步曲:

  1. 定义组件 难
  2. 注册组件 Vue.component(“my-header” ) 全局注册 在所有的根组件中都可以使用
  3. 使用组件 使用组件就是在使用标签

定义组件template 下,data必须是一个函数,而且必须返回一个对象。

全局子组件

全局:所有的vue实例都可以使用
在使用一个组件时,当成自定义标签就OK了
在这里插入图片描述
自定义标签默认都是行内的,都是女标签。
可以通过vue.extend与vue.component来定义组件。

<body>
<!--是根组件的模板-->
<div id="app1">
    <!--3)使用子组件-->
    <my-header></my-header>
</div>
<div id="app2">
    <!--3)使用子组件-->
    <my-header></my-header>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
    // 定义一个全局组件  一个组件就是一个JS对象
    // Vue.component();第1个参数是组件的名字,第2个参数代表这个组件
    // 组件指的是:
    /*      一个组件就是一个JS对象
            {
                // tempplate 指定子组件的模板
                template:"<div>{{msg}}</div>",
                data(){		//在自组件中data 必须是函数,必须返回对象
                    return{
                        msg:"hello 子组件"
                    }
                }
            }
    */
    // Vue.component 表示注册一个组件
    Vue.component("my-header",{
        // tempplate指定子组件的模板
        template:"<div>{{msg}}</div>",
        data(){
            return{
                msg:"hello 子组件"
            }
        }
    });
        // 1)定义组件
    let myComponent = {
        template: "<div>{{msg}} <button @click='f1'>点击</button></div>", // 当前组件模板
        data(){ return { msg:"hello component" } }, // 给当前组件提供数据
        methods:{ f1(){console.log("f1....")} }, // 当前组件模板中使用到的方法
    }
    // 2)注册组件  注册分全局注册和局部注册   由于是全局注册,意味着在所有的根组件对应的模板中都可以使用
    Vue.component("my-header",myComponent);
    let vm1 = new Vue({
        el:"#app1",
    })
    let vm2 = new Vue({
        el:"#app2",
    })
</script>
</body>

组件的名字:

  1. 组件的定义时的名字
  2. 组件的注册时的名字
  3. 组件使用时,使用的是注册时的名字

我们很少会用全局组件,因为,在一个页面中,我们只会设置一个vue实例。

局部子组件

局部子组件就是说注册一个组件,这个组件只属于某个根组件
局部组件就是要去配置一下components这个选项。(就和配置 methods,data,filters,computed 一样)

<div id="app1">
    <!-- 3)使用子组件-->
    <my-header></my-header>
</div>
<script>
    // 1) 定义子组件
    let myComponet = {
        template:"<div>{{msg}}</div>",
        data(){ return{ msg:"hello 局部注册子组件" } }
    }
    let vm1 = new Vue({
        el:"#app1",
        // 2)局部注册一个子组件
        components:{
            "my-header":myComponet
        }
    })
</script>

template

<body>
<!--根组件模板-->
<div id="app">
    <abc></abc>
</div>
<!--子组件模板-->	//常用
<!--<template id="test">
    <div>
        <div>我是一个div</div>
        <p>我是一个p标签</p>
        <h1>我是一个h1</h1>
    </div>
</template>-->
<script type="text/html" id="test">
    <div>
        <div>我是一个div</div>
        <p>我是一个p标签</p>
        <h1>我是一个h1</h1>
    </div>
</script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
    let com = {
        /*template:"<div><div>div</div><span>span</span></div>",*/
        template:"#test"
    }
    let vm = new Vue({
        el:"#app",
        components:{
            "abc":com
        }
    })
</script>
</body>

配置template注意点:

  • template指令模板时,必须使用根标签包起来,否则报错:Component template should contain exactly one root element.

template指定模板常见的方式:

  • template:后面写字符串
template:"<div><div>div</div><span>span</span></div>"
  • 把模板定义到外面,在template引用
A)<template id="test">	//常用
     <div>
     	<div>我是一个div</div>
     	<p>我是一个p标签</p>
     	<h1>我是一个h1</h1>
     	</div>
  </template>
B)<script type="text/html" id="test">
       <div>
           <div>我是一个div</div>
           <p>我是一个p标签</p>
           <h1>我是一个h1</h1>
        </div>
   </script>

组件的名字

!--根组件模板-->
<div id="app">
    <!--现在下面的写法不OK  后面还是这样的写法-->
    <!--<MyHeader></MyHeader>-->

    <!--现在,手动换成小驼峰也不OK-->
    <!--<myHeader></myHeader>-->

    <!--中划线命名是OK-->
    <my-header></my-header>
    <my-footer></my-footer>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
    // MyHeader 定义组件时的名字
    let MyHeader = {
        template:"<div>MyHeader...</div>"
    }
    let vm = new Vue({
        el:"#app",
        components:{
            // MyHeader 注册组件时的名字和定义组件时名字一样
            MyHeader,
            "my-footer":{
                template: "<div>MyFooter....</div>"
            }
        }
    })
</script>

使用组件三步曲之名字:

  • 定义组件时,最好使用大驼峰命名

  • 注册时,可以和定义组件时名字一样

  • 目前来说,使用组件时,不要使用大驼峰,但是后面,我们会使用大驼峰

    如果说,定义组件和注册组件都是大驼峰,使用组件时,名字换成中划线
    在这里插入图片描述

子组件中的数据项

与vm实例中的data语法不同:
子组件中的data是一个函数,在其中写return { }。这是固定写法:

let 组件名 = {
   template:””,
   data:function(){
      return {
             //数据项
		}
	}
}

如果你在data中使用到了this,那么,你的data函数不能简写,简写后的箭头函数中没有this。

组件的嵌套

在一个组件中使用 components 去注册另一个组件,就可以使用注册的那个组件了

<!--根组件模板-->
<div id="app">
    <Father></Father>
</div>
<!--Father组件对应的模板-->
<template id="father">
    <div>
        <h1>Father组件 ---》{{fatherData}}</h1>
        <Son></Son>
    </div>
</template>
<!--Son组件对应的模板-->
<template id="son">
    <div>
        <h1>Son组件 ---》{{sonData}}</h1>
    </div>
</template>
<script>
    let Son = {     // 定义Son组件对象
        template:"#son",
        data(){ return { sonData:"Son组件中的data" } }
    }
    let Father = {   // 定义Father组件对象
        template:"#father",
        data(){ return { fatherData:"Father组件中的data" } },
        components:{
            Son     // 在Father组件中注册Son组件  
            // 就可以在Father组件所对应的模板中使用Son组件
        }
    }
    let vm = new Vue({
        el:"#app",
        components:{
            Father,
        }
    })
</script>

组件数据传递 - 父传子

完整代码简介

根组件作为父组件。父子之间不能正常共享数据的,父中的数据在子中是没有办法使用。

一个组件中的数据,默认情况下,只能让本组件所对应的模板使用,其它组件所对应的模板不能使用。但是可能通过一定的段,让子组件也可以使用父组件所对应的数据,也就是说需要把父组件中的数据传递到子组件,让子组件使用。这叫父传子。如果说把子组件中数据,传递给父组件,让父组件使用,那叫做子传父

<!--根组件模板-->
<div id="app">
    <Father></Father>
</div>
<!--Father组件对应的模板-->
<template id="father">
    <div>
        <h1>Father组件 ---》{{fatherData}}</h1>
        <Son :xxx="fatherData"></Son>
    </div>
</template>
<!--Son组件对应的模板-->
<template id="son">
    <div>
        <h1>Son组件 ---》{{sonData}}</h1>
        <!--你在SON组件中使用Father组件中数据就报错-->
        <!--<h2>要Son组件中使用Father组件中的数据 -&#45;&#45;》 {{fatherData}}</h2>-->
        <h2>使用父组件传递过来的数据:{{xxx}}</h2>
    </div>
</template>
<script>
    let Son = {
        template:"#son",
        props:{
            // fatherData是接收的数据   String是对数据检验
            // 我期待父组件传给子组件的数据的类型是String
            xxx:String
        },
        data(){ return { sonData:"Son组件中的data" } }
    }
    let Father = {
        template:"#father",
        data(){ return { fatherData:"Father组件中的data" } },
        components:{
            Son
        }
    }
    let vm = new Vue({
        el:"#app",
        components:{
            Father,
        }
    })
</script>

HTML中标签:

<h1 title="hello"></h1>  title="hello" html中自带的属性
<h1 abc="123"></h1>  abc="123" html中自定义属性
<Son abc="123"></Son>  <Son>不是html中的标签  组件
<Son abc="123"></Son>  abc="123" 自定义属性
<Son title="hello"></Son>  title="hello" 自定义属性

传输步骤

传递数据就靠自定义属性
第一步:在父组件所对应模板中使用子组件,属性位置绑定父组件中的数据

<template id="father">
  <div>
    <h1>Father组件 ---{{fatherData}}</h1>
    <Son :xxx="fatherData"></Son>
  </div>
</template>

第二步:在子组件中通过props接收数据,如下:

let Son = {
   template:"#son",
     rops:{
      // fatherData是接收的数据   String是对数据检验
       // 期待父组件传给子组件的数据的类型是String
      xxx:String
    },
   data(){ return { sonData:"Son组件中的data" } }
}

第三步:在子组件所对应的模板中就可以使用父组件传递过来的数据了

  <template id="son">
    <div>
      <h1>Son组件 ---{{sonData}}</h1>
      <h2>使用父组件传递过来的数据:{{xxx}}</h2>
    </div>
  </template>

props:

一个组件的配置项,作用:接收父组件传递过来数据。 如父组件中绑定了一个数据:

props:{
    xxx:{
        type:String,  // 期待父组件传递过来一个String类型的数据
        // required:true, // 必须要求父传递数据
        default:"lalala",  // 配置默认值
    }
},		//type:[String,Number] 表示string和number都可以

单个可以简写:

props:{
       xxx:Number
}

步骤传输

  1. 在父组件中,正常定义自己的数据
    父中有数据了,就意味着在父的视图中就可以得到数据了
  2. 在父组件的模板中通过属性绑定把数据绑定到子组件上
  3. 在子组件中定义props属性。用来接收父组件传递的数据
  4. 在子组件模板中使用数据
  5. 在子组件中的函数中使用数据

父传子有一个核心 子组件中的props配置项
父子传递,讲究”你情我愿”,父需要绑定数据,子需要接收数据

组件数据传递 - 子传父

自定义属性-自定义事件

HTML标签才有自带属性
只要不是HTML标签,里面写的都叫自定义属性

<button title="haha">登录</button>  title="haha" 标签自带属性
<Son title="haha"></Son>  title="haha" 自定义属性

标签的点击事件
给html标签上button按钮绑定一个点击事件,当我们点击时,调用f1方法,不需要写代码,只需要鼠标点击就会触发点击事件

<button @click="f1"></button>  html标签   click自带事件

非HTML标签的自定义事件
不能说:给Son上绑定一个点击事件
给Son组件上绑定了一个自定义事件, 需要写代码去触发这个自定义事件

<Son @click="f1"></Son> 不是html标签  自定义事件
<Son @Hello="f1"></Son> 不是html标签  @Hello="f1  自定义事件  订阅事件

事件分两类:

  • 浏览器自带的事件 click 点击了
  • 自定义事件 Hello 需要写代码触发Hello事件 发布订阅

发布订阅难点:

<Son hello="ff"></Son>	 	自定义属性	值是 "ff" 字符串
<Son :hello="ff"></Son>		自定义属性  值是  ff  对应的数据
<Son @hello="ff"></Son>	自定义事件  事件发生时执行 ff 方法

子传父完整代码

<!--根组件模板-->
<div id="app">
    <Father></Father>
</div>
<!--Father组件对应的模板-->
<template id="father">
    <div>
        <h1>Father组件 ---》{{fatherData}}</h1>
        <h3>来自于子组件的数据:{{datafromson}}</h3>
        <hr>
        <!--hello是一个自定义事件,需要写代码触发这个自定义事件,当这个事件发生时,会调用f1方法-->
        <!--订阅一个事件-->
        <Son @hello="ff"></Son>
    </div>
</template>
<!--Son组件对应的模板-->
<template id="son">
    <div>
        <h1>Son组件 ---》{{sonData}}</h1>
        <button @click="sf">点击</button>
    </div>
</template>
<script>
    let Son = {
        template:"#son",
        data(){ return { sonData:"Son组件中的data" } },
        methods:{	// this.$emit() 触发一个自定义事件  
            sf(){	 // 在发布时就可以传递数据了
                this.$emit("hello",this.sonData)
            }	//this当前组件对象,vue中默认挂了 $emit
        }
    }
    let Father = {
        template:"#father",
        data(){ return { fatherData:"Father组件中的data",datafromson:"", } },
        methods:{
            ff(msg){
                console.log("ff....: ",msg);
                this.datafromson = msg;
            }
        },
        components:{
            Son
        }
    }
    let vm = new Vue({
        el:"#app",
        components:{
            Father,
        }
    })
</script>

重点步骤

在子模板的里面使用点击事件,点击调用方法,然后方法会触法一个自定义事件{ this.$emit(“自定义”)},可以传递参数。这个自定义事件在父模板使用子模板时绑定到子模板上的,这个自定义事件写在父模板的方法里面,形参就是接收的数据。

  1. 子组件的模板绑定一个天生点击事件,点击时调用子的方法 ff1

    <button @click="ff1">点击</button>
    
  2. 在子组件的方法中的 ff1 中使用 this.$emit(“ange”),触发该自定义事件:发布

    ff1(){ this.$emit( "ange" ,this.sonData)}  传递数据sonData
    
  3. 在父组件的模板中使用子组件,用触发的自定义事件去调用父的方法 ff2 : 订阅

    <Son @ange="ff2"></Son>	父模板使用子组件
    
    data(){ dataformson:"")
    ff2(msg) {console.log(msg);	方法2接收子传递的数据
    this.dataformson = msg	}	接收的数据赋值给父组件
    

父传子和子传父

父传子:

  1. 在父组件对应的模板中绑定自定义属性
  2. 在子组件中通过props接收自定义属性(数据)
  3. 在子组件中就可以使用这些数据

子传父:

  1. 在父组件对应的模板中子组件上绑定自定义事件
  2. 在子组件中触发自定义事件,触发自定义事件时,可以携带数据
  3. 在父组件中,当自定义事件发生时,调用监听器,监听器的形就是接收到的数据

vue中组件通信方案:

  1. 父传子 绑定自定义属性 + props接收
  2. 子传子 绑定自定义事件 + this.$emit() 触发自定义事件并携带数据
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值