组件高级
父子组件
语法:
components:{
‘parent’: {
template:’<div></div>’,
components:{
‘child’: {
template:’<div></div>’
}
}
}
}
父子组件的作用域
1.组件相当于完整的vue实例
2.组件与vue实例间作用域独立(组件与vue实例中data数据不互通)
3.父子组件间作用域相互独立
子组件的调用
子组件只能在父组件的模板(template)中进行调用
[外链图片转存失败(img-YHl5Zex6-1562157343966)(…/AppData/Roaming/Typora/typora-user-images/1561721699629.png)]
基本的父子组件
eg:
<!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">
<title>Document</title>
</head>
<body>
<div class="box">
<fu></fu>
</div>
<template id="fuDiv">
<div>
<p>{{fText}}</p>
<zi></zi>
</div>
</template>
<template id="ziDiv">
<div>
<p>{{zText}}</p>
</div>
</template>
</body>
</html>
<script src="./node_modules/vue/dist/vue.min.js"></script>
<script>
new Vue({
el: ".box",
data: {},
components: {
"fu": {
template: "#fuDiv",
data() {
return {
"fText": "我是父数据"
}
},
components: {
"zi": {
template: "#ziDiv",
data() {
return {
"zText": "我是子数据"
}
}
}
}
}
}
})
</script>
现在的组件ex其实可以用父组件和子组件来完成
<!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">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
.big {
position: fixed;
bottom: 0;
width: 100%;
border-top: 1px solid red;
height: 100px;
}
.small {
width: 20%;
float: left;
text-align: center;
}
</style>
</head>
<body>
<div class="box">
<father></father>
</div>
<template id="fTem">
<div>
<div class="big">
<son v-for="(v,i) in arr" :img-url="v.img" :title="v.title"></son>
</div>
</div>
</template>
<template id="sTem">
<div class="small">
![在这里插入图片描述]()
<p>{{title}}</p>
</div>
</template>
</body>
</html>
<script src=" ./node_modules/vue/dist/vue.min.js"> </script>
<script>
new Vue({
el: ".box",
data: {},
components: {
"father": {
template: "#fTem",
data() {
return {
arr: [
{ "img": "./img/1.png", "title": "首页" },
{ "img": "./img/2.png", "title": "首页" },
{ "img": "./img/3.png", "title": "首页" },
{ "img": "./img/4.png", "title": "首页" },
{ "img": "./img/5.png", "title": "首页" }
]
}
},
components: {
"son": {
template: "#sTem",
props: {
"title": String,
"imgUrl": String
}
}
}
}
}
})
</script>
父子组件中传值
1.父子组件间作用域相互独立所以没有办法直接调用,必须借助于自定义事件来进行传值
2.子组件传值给父组件叫逆向传值(是不允许的 必须要有事件触发才能传值)
3.父组件传值给子组件叫正向传值(不需要事件触发)
正向传值
props 选项
props选项用来声明它期待获得的数据props 本质:props 为元素属性
props 的声明
语法:如果是驼峰命名法需要把大写转小写前面加-
JS 中:
props:[‘message1’, ‘messAge2’…]
HTML 中:
<组件 message=‘val’mess-age2=‘val’></组件>
props 的使用
与 data 一样,props 可以用在模板中
可以在 vm 实例中像 this.message 这样使用
props 验证
我们可以为组件的 prop 指定验证要求,例如知道的这些数据的类型。
为了定制 prop 的验证方式,你可以为 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">
<title>Document</title>
</head>
<body>
<div id="demodiv">
<fu></fu>
</div>
<template id="futem">
<div>
<p>fufufuf</p>
<zi :zitext="futext" zinum="hahah"></zi>
</div>
</template>
<template id="zitem">
<div>
<p>{{zitext}}</p>
<p>{{zinum}}</p>
</div>
</template>
</body>
</html>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
new Vue({
el: "#demodiv",
data: {},
components: {
"fu": {
template: "#futem",
data() {
return {
futext: 1
}
},
components: {
"zi": {
template: "#zitem",
// props验证来完成props的定义
props: {
zitext: Number,
zinum: {
type: String,
default: "我是默认值"
}
}
}
}
}
}
})
</script>
注意:在进行props验证时为什么写的没有错但是没有错误提示?
生产版本也就是压缩版的文件删除了警告,所以使用非压缩版的js文件就可以看到错误
逆向传值
逆向传值就是子组件给父组件传递数据,那么在这个时候默认是不允许,必须要用自定义事件来传递,要进行传递的时候还需要使用事件来进行触发。
- 逆向传值,需要通过时间来触发一个自定义事件的抛出操作
- 父组件接受子组件抛出的内容
抛出自定义事件监 听
要传值必须要先抛出,在接收
语法:
this. e m i t ( ‘ e v e n t ’ , v a l ) = = = = emit(‘event’,val)== == emit(‘event’,val)====emit:实例方法,用来触发事件监听
接收自定义事件监听
语法:
<component @抛出的事件名=‘函数不加()不加()’>
fn:function(val){
}
val:自定义事件传递出的值
事件触发及接收原则:
谁触发的监听,由谁接收监听
eg:
<!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">
<title>Document</title>
</head>
<body>
<div class="box">
<fu></fu>
</div>
<template id="futem">
<div>
<p>我是父元素-------{{futext}}</p>
<zi @zipao="fufun"></zi>
</div>
</template>
<template id="zitem">
<div>
<p @click="zifun()">我是子元素-------{{zitext}}</p>
</div>
</template>
</body>
</html>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
new Vue({
el: ".box",
data: {},
components: {
"fu": {
template: "#futem",
data() {
return {
"futext": "我是父组件的数据",
}
},
methods:{
fufun(val){
this.futext=val;
}
},
components: {
"zi": {
template: "#zitem",
data() {
return {
"zitext": "我是子组件的数据",
}
},
methods:{
zifun(){
this.$emit("zipao",this.zitext)
}
}
}
}
}
}
})
</script>
slot槽口
作用:
用来混合父组件的内容与子组件自己的模板
内容不同数量也不同的时候使用
普通的槽口看起来更方便,但是不宜维护
语法:
声明组件模板:定义组件的时候留下slot等待调用的时候插入内容
[外链图片转存失败(img-nClKwrHq-1562157343968)(…/AppData/Roaming/Typora/typora-user-images/1561982611723.png)]
使用:
调用组件模板:调用的时候直接插入
[外链图片转存失败(img-ZhFNLV4Y-1562157343968)(…/AppData/Roaming/Typora/typora-user-images/1561982620184.png)]
eg:
<!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">
<title>Document</title>
</head>
<body>
<div class="box">
<fu>
<!-- 调用的时候需要使用slot属性 -->
<p slot="solta">哈哈哈</p>
</fu>
</div>
<template id="futem">
<div>
<p>{{futext}}</p>
<!-- 槽口只能有一个name属性,不能有其他的属性,这是规范 -->
<!-- 如果需要使用属性的话可以把他包裹起来,对父元素添加属性 -->
<slot name="solta"></slot>
</div>
</template>
</body>
</html>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
new Vue({
el: ".box",
data: {},
components: {
"fu": {
template: "#futem",
data() {
return {
"futext":"我是父组件的数据",
}
}
}
}
})
</script>
具名 slot
1.slot> 元素可以用一个特殊属性 name 来配置如何分发内容
2.多个slot可以有不同的名字
3.具名slot将匹配内容片段中有对应slot特性的元素