文章目录
一、定义
组件 (Component) 是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以表现为用 is 特性进行了扩展的原生 HTML 元素。所有的 Vue 组件同时也都是 Vue 的实例,所以可接受相同的选项对象 (除了一些根级特有的选项) 并提供相同的生命周期钩子。
二、全局组件
在很多 Vue 项目中,我们使用 Vue.component 来定义全局组件,紧接着用 new Vue({ el: '#container '}) 在每个页面内指定一个容器元素。
全局注册的组件可以用在其被注册之后的任何 (通过 new Vue) 新创建的 Vue 根实例,也包括其组件树中的所有子组件的模板中。
注册组件:
Vue.component( id, [definition] )
参数:
- {string} id
- {Function | Object} [definition]
data 必须是一个函数
当我们定义这个 组件时,你可能会发现它的 data 并不是像这样直接提供一个对象:
data:{
aaa:"h1"
},
取而代之的是,一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:
data(){
return {
aaa:"h1"
}
},
基本示例
(一、)定义一个名为con-a 的新组件
Vue.component("con-a",{
//这里的data要用return
data(){
return {
aaa:"h1"
}
},
template:"<h1>我是{{aaa}}里面的内容</h1>"//{{aaa}}是前面定义的东西
})
组件是可复用的 Vue 实例,且带有一个名字:在这个例子中是 <con-a>
。我们可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用:
<div id="all">
<con-a></con-a>
</div>
new Vue({
el:"#all",
})
结果
三、局部组件
Vue实例里面的component是:{}。局部组建无法被其他实例对象使用
示例
例:
<div id="all">
<con-a></con-a>
<con-b></con-b>
<con-a></con-a>
<con-b></con-b>
</div>
<script>
new Vue({
el:"#all",
components:{
"con-a":{template:"<h1>我是h1里面的内容</h1>"},
"con-b":{template:"<h2>我是h2里面的内容</h2>"}
}
})
</script>
结果
四、Vue组件的其他写法
使用template标签
<template>
元素 是一种用于保存客户端内容的机制,该内容在页面加载时不被渲染,但可以在运行时使用JavaScript进行实例化。
在此处的用法
<template id="conAB">
<h3>我是用template标签写的</h3>//多内容输出必须有一个根元素
</template>
全局组件
Vue.component("con-a-b",{template:"#conAB"})
局部组件
new Vue({
el:"#tem",
components:{
"com-a-b":{template:"#conAB"}
}
})
显示
<div id="tem">
<com-a-b></com-a-b>
<con-a-b></con-a-b>
</div>
结果
使用script标签
跟前一个仅仅在标签使用的不同,调用方法相同
<div id="tem">
<com-a-b></com-a-b>
<con-a-b></con-a-b>
</div>
<script type="text/template" id="conAB">
<h3>我是用template标签写的</h3>//多内容输出必须有一个根元素
</script>
<script>
Vue.component("con-a-b",{template:"#conAB"})
new Vue({
el:"#tem",
components:{
"com-a-b":{template:"#conAB"}
}
})
</script>
结果
五、组件的复用
你可以将组件进行任意次数的复用:
<div id="all">
<con-a></con-a>
<con-a></con-a>
<con-a></con-a>
</div>
六、通过 Prop 向子组件传递数据
props单向数据流,父组件向子组件传递数据
vue实例
new Vue({
el:"#co",
data:{
msg:"parent msg"
}
})
利用props获取父级中的数据
props可以是一个数据类型也可以是一个数组,也可以是对象,对象下的数据有3个属性type,default,require。其中default,require值都是布尔类型值。type有Number,String,Boolean,Array,Object,Function,Symbol。
<template id="comAB">
<h3>我是父级传递过来的数据->{{aaa}}</h3>
</template>
Vue.component("comAB",{
// props:["aaa"],
props:{
"aaa":String,
},
template:"#comAB"
})
<div id="co">
<com-a-b :aaa="msg"> </com-a-b>//
</div>
结果
问题:单项数据里,所以子级修改父级数据一般是不允许的
解决方法:父级传递一个对象或数组给子级
因为对象或数组是引用类型,指向的是同一个内存空间所以当props数据是这两个类型时,数据改变时子组件内改变是会影响父组件的。
示例:点击更改父级中的数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>prop父级向子级传递数据</title>
</head>
<body>
<div id="co">
我是父级中的数据 {{msg.a}}
<com-a-b :aaa="msg"> </com-a-b>
</div>
<template id="comAB">
<h3 @click="change">我是父级传递过来的数据->{{aaa.a}}</h3>
</template>
<script>
Vue.component("comAB",{
props:["aaa"],
template:"#comAB",
methods:{
change(){
this.aaa.a="zzz";
}
}
})
new Vue({
el:"#co",
data:{
msg:{a:"parent msg"}
}
})
</script>
</body>
</html>
还有一个注意项:Prop 的大小写
HTML 中的特性名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名:
例如:
<div id="co">
我是父元素中数据-> {{msg.a}}
<com-a-b :aa-a="msg"> </com-a-b>//此处讲aaA改为aa-a
</div>
<template id="comAB">
<h3 @click="change">我是父级传递过来的数据->{{aaA.a}}</h3>//此处利用驼峰式命名
</template>
<script>
Vue.component("comAB",{
props:["aaA"], //此处利用驼峰式命名
template:"#comAB",
methods:{
change(){
this.aaA.a="changes";//此处利用驼峰式命名
}
}
})
new Vue({
el:"#co",
data:{
msg:{a:"parent msg"}
}
})
</script>
七、父级获取子级数据
Vue 实例提供了一个自定义事件的系统来解决这个问题。
子组件通过this.$emit()派发事件,父组件利用v-on对事件进行监听,实现参数的传递
调用 $emit 方法并传入事件的名字,来向父级组件触发一个事件:
<template id="ch">
<h3 @click="send()">子级数据->{{cmsg}}</h3>
</template>
<script>
Vue.component("com",{
data(){
return {
cmsg:"cMsg"
}
},
template:"#ch",
methods:{
send(){
this.$emit("child-say",this.cmsg)
}
}
})
</script>
然后我们可以用 v-on 监听这个事件,就像监听一个原生 DOM 事件一样:
<div id="co">
<h3 >父级数据->{{pmsg}}</h3>
<com @child-say="show"></com>
</div>
<script>
new Vue({
el:"#co",
data:{
pmsg:"pMsg"
},
methods:{
show(msg){
this.pmsg=msg;
}
}
})
</script>
结果:点击自己元素,父级元素获得子级元素
八、子级与子级间数据传递
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>子级与子级间数据传递</title>
</head>
<body>
<div id="co">
<coma></coma>
<comb></comb>
</div>
<template id="cha">
<h3 @click="send()">子级A数据->{{cmsga}}</h3>
</template>
<template id="chb">
<h3 @click="send()">子级B数据->{{cmsgb}}</h3>
</template>
<script>
let ev=new Vue();
Vue.component("coma",{
data(){
return {cmsga:"cMsgA"}
},
template:"#cha",
methods:{
send(){
ev.$emit("a-say",this.cmsga)
}
},
mounted(){//此处是mounted()挂载结束后执行
ev.$on("b-say",msg=>{
this.cmsga=msg;
})
}
})
Vue.component("comb",{
data(){
return {cmsgb:"cMsgB"}
},
template:"#chb",
methods:{
send(){
ev.$emit("b-say",this.cmsgb)
}
},
mounted(){//此处是mounted()挂载结束后执行
ev.$on("a-say",msg=>{
this.cmsgb=msg;
})
}
})
new Vue({
el:"#co"
})
</script>
</body>
</html>