什么是组件?
组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素, Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以是原生 HTML 元素的形式,以 is 特性扩展。
全局组件
注意所有加在Vue上的内容,必须写在实例挂载之前
全局组件在所有Vue实例的视图都是可以使用的
<div id="app">
<hello></hello>
<love></love>
</div>
=========JS==========
方法一:
let tmp=Vue.extend({
template:"<h1>HELLO</h1>"
});
//1.通过vue的extend这个方法创造一个模板 template:"真是的标签(自定义标签所代表的内容)"
Vue.component("hello",tmp);
Vue.component("自定义标签",模板)
//2.通过Vue中component将这个模板赋给当前自定义标签
let vv=new Vue({
el:"#app",
})
方法二:
Vue.component("love",{
template:"<h2>{{msg}}</h2>",
//组件中默认不可以使用Vue实例的数据,只能用自己组件中提供的数据
//可以写当前组件中的数据 data是个函数 return出一个对象,对象中就是我们想要的数据
data(){
return {
msg:"hello"
}
}
});
例子:
<div id="app">
<like></like>
</div>
<div id="app2">
<like></like>
</div>
=========JS==========
Vue.component("like",{
template:"
<ul><li>初见</li>
<li>相恋</li>
<li>相守</li></ul>"
});
let v1=new Vue({
el:"#app",
});
let v2=new Vue({
el:"#app2",
})
最终页面呈现:
初见
相恋
相守
初见
相恋
相守
局部组件
[局部组件-在Vue实例中添加组件,只在当前实例的视图中使用
]
局部组件也是不可以直接使用当前实例中的数据,只能使用当前
组件中自己data,也是一个函数
,return一个对象,这个对象中就是想要数据,每一个组件之间不可以直接相互使用
[看代码
]
<div id="app1">
<h2>{{msg}} {{wd}}</h2>
<hi></hi>
<hello></hello>
<bay></bay>
</div>
==========JS==========
var app1=new Vue({
el:"#app1",
data:{
msg:"ni",
wd:"hao",
h:"HI 你好"
},
components:{
//这里main可以写很多个组件每一个组件都是一个自定义标签名:{}
这里分别注册了3个组件"hi,hello,bay"
hi:{
template:"<h1>{{h}}</h1>",
data(){
return{
h:"大家好"
}
}
},
hello:{
template:"<h1>{{h}}</h1>",
data(){
return{
h:"吃了吗?"
}
}
},
bay:{
template:"<h1>bay-bay</h1>"
}
}
});
组件的嵌套
(父子组件)
[在一个组件中再注册(嵌套)一个组件
-父子组件]
在vue2.0中必须包一个根元素,不然就报错
[Component template should contain exactly one root element]
在2.0中同级组件是不可以直接相互使用的.
子组件不可以直接使用父组件的数据.
<div id="app">
<parent></parent> //父组件
</div>
============JS===========
var app=new Vue({
el:'#app',
components:{
parent:{
template:"<div>
<h1>PARENT</h1>
<child1></child1>
<child2></child2>
</div>",
在vue2.0中必须包一个根元素,不然就报错
在2.0中同级是不可以相互使用的
例如:template:"<p>CHILD1</p> <child2></child2>"是错误的
data(){
parent的数据
return{
msg:"我是一个好人"
}
},
components:{
子组件
child1:{
template:"<p>CHILD1:{{msg}}</p>",
报错 "msg" is not defined
子组件不可以使用父组件的数据
},
child2:{
template:"<p>CHILD2</p>"
}
}
}
}
})
[自定义HTML模板
]+[子组件获取父组件数据
]
组件中的模板
template
还可以写在HTML结构中,这样也避免了如果拼接内容过多,在Vue实例中显示杂乱的问题,同样也便于集中管理-这也叫做自定义HTML模板
看代码
<div id="app">
<parent></parent>
</div>
<!--自定义HTML结构模板-->
<template id="temp1">
<!--这里也是一样需要用一个根元素包起来-->
<div>
<!--这里出现的数据都是parent的数据-->
<h1>{{msg}}</h1>
<child1 :mm="msg" :num="n"></child1>
<!--这里就相当于给child1绑定了一个数据mm,值等于parent的msg-->
</div>
</template>
=============JS============
var app=new Vue({
el:"#app",
components:{
parent:{
template:"#temp1",
//告诉浏览器parent这个自定义标签代表的内容就是模板#temp1里面的html结构,
data(){
return{
msg:"我是老实人",
n:1
}
},
components:{
child1:{
template:"<p>{{mm}}的第{{num}}孩子 {{ss}}</p>",
//获取绑定的数据,绑定的数全部放在props中
//props:["num","mm"],
//props:["num",{"mm":"String"}]
//如果想规定数据的的类型
props:{mm:String},
data(){
return{
ss:"SS"
}
}
}
}
}
}
})
最终页面呈现:
我是老实人
我是老实人的第孩子 SS
子组件向父组件传数据(子父同步
)
[核心思想:子组件发射数据,由父组件来接收
]
[$emit("发射数据名",发射数据)
]数据发射属性
<div id="app1">
<parent></parent>
</div>
<template id="temp1">
<div>
<!--父组件默认不可使用子组件的数据-->
<h1>儿子你今年{{age}}岁</h1>
<!--你在发射数据的时候起的名字就在这里派上用场了 用@a来接收 我们需要把数据取出来 @a=函数get(你自己起的名字) 默认将数据传给函数get-->
<child1 @a="get"></child1>
</div>
</template>
==================JS================
思路:给子组件模板添加点击事件并绑定函数在函数内执行发射子组件数据,父组件模板上绑定一个接受子组件发射的数据函数,以此来达到数据同步的目的
var v1=new Vue({
el:"#app1",
components:{
parent:{
template:"#temp1",
data(){
return{
age:0
}
},
methods:{
get(res){
//res就是发射过来的数据 ==trueAge
//console.log(this);
console.log(res);
this.age=res;
}
},
components:{
child1:{
template:"<h3 @click='say'>我今年{{trueAge}}岁</h3>",
data(){
return{
trueAge:27
}
},
methods:{
say(){
//console.log(this);
//this就是当前组件child1
//$emit("发射出去数据我们给他起的名字",你想要发射出去的数据)
this.$emit("a",this.trueAge);
}
}
}
}
}
}
})
进阶例子:
子组件修改父组件数据
实现点击子组件后让父组件的内容变为与子组件相同
<div id="app">
<parent></parent>
</div>
<template id="temp1">
<div>
<h1>{{name.XX}}</h1>
<child1 :n="name"></child1>
</div>
</template>
</body>
</html>
<script src="js/vue2.0.js"></script>
<script>
var app=new Vue({
el:"#app",
components:{
parent:{
template:"#temp1",
data(){
return{
name:{XX:"xiuXiu"}
}
},
components:{
child1:{
template:"<h2 @click='change'>{{n.XX}}</h2>",
props:["n"],
methods:{
change(){
//this当前组件
this.n.XX="秀秀"
}
}
}
}
}
}
})
例子二:
<div id="app">
<parent></parent>
</div>
<template id="temp1">
<div>
<h1>{{name.XX}}</h1>
<child1 :n="name"></child1>
</div>
</template>
</body>
</html>
<script src="js/vue2.0.js"></script>
<script>
var app=new Vue({
el:"#app",
components:{
parent:{
template:"#temp1",
data(){
return{
name:{XX:"xiuXiu"}
}
},
components:{
child1:{
template:"<h2 @click='change'>{{n.XX}}</h2>",
props:["n"],
methods:{
change(){
//this当前组件
this.n.XX="秀秀"
}
}
}
}
}
}
})
componet & v-bind:is
[绑定指定组件中的模板
]
如果想在实例视图范围内显示指定组件中的模板可以使用<component :is="'组件名'"></component>
标签来实现,
标签中加上:is这个属性来绑定指定的组件内的模板
<div id="app">
<!--这里面出现的数据必须是当前实例的data中的数据-->
<button @click="flag='love2'">中文</button>
<button @click="flag='love1'">英文</button>
<component :is="flag"></component>
<component :is="'love1'"></component>
<!--<love1></love1>-->
<component :is="'love2'"></component>
<!--<love2></love2>-->
</div>
<template id="temp1">
<h1>I LOVE YOU</h1>
</template>
<template id="temp2">
<h1>我爱你!</h1>
</template>
==================JS===============
var app=new Vue({
el:"#app",
data:{
flag:"love1"
},
components:{
love1:{
template:"#temp1"
},
love2:{
template:"#temp2"
}
}
})
slot
使用 Slot
分发内容
为了让组件可以组合,我们需要一种方式来混合父组件的内容与子组件自己的模板。这个过程被称为 内容分发
使用特殊的<slot>
元素作为原始内容的插槽。
<slot>
元素可以用一个特殊的属性 name 来配置如何分发内容。多个 slot 可以有不同的名字。具名 slot 将匹配内容片段中有对应 slot 特性的元素。
仍然可以有一个匿名 slot ,它是默认 slot ,作为找不到匹配的内容片段的备用插槽。如果没有默认的 slot ,这些找不到匹配的内容片段将被抛弃。
<div id="app">
<love>我想都对你说:</love>
</div>
<div id="app1">
<love>
<p slot="slot1">亲爱的,你听好了!</p>
<p slot="slot2">嫁给我吧!</p>
</love>
</div>
<template id="temp">
<h1>
<!--会将自定标签的内容自动加在这里<slot></slot> 这个是个站位的,站的位置在哪里就写在哪里-->
<slot></slot>
I LOVE YOU
<!--<slot></slot>-->
</h1>
</template>
<template id="temp2">
<h1>
<slot name="slot1"></slot>
I LOVE YOU
<slot name="slot2"></slot>
</h1>
</template>
===============JS================
var app=new Vue({
el:"#app",
components:{
love:{
template:"#temp"
}
}
});
var app1=new Vue({
el:"#app1",
components:{
love:{
template:"#temp2"
}
}
})
组件之间进行数据发送
<div id="app">
<love1></love1>
<love2></love2>
</div>
<template id="love1">
<div>
{{msg}}
<button @click="goData">走你</button>
</div>
</template>
<template id="love2">
<div>{{msg}}</div>
</template>
==============JS===============
var a=new Vue();
//后面的$emit和$on方法是使用实例上的方法,必须保证这个实例是存在的.所有为了安全起见,使用是一个已经创建好的实例 a
var app=new Vue({
el:"#app",
components:{
love1:{
template:"#love1",
data(){
return{
msg:"I LOVE YOU"
}
},
methods:{
goData(){
a.$emit("m",this.msg);
}
}
},
love2:{
template:"#love2",
data(){
return{
msg:""
}
},
mounted:function () {
//使用箭头函数来处理
a.$on("m",(data)=>{
console.log(this);
this.msg=data;
})
}
}
}
})