目录
一,什么是组件
组件Component,可扩展HTML元素,封装可重用的代码。通俗的来说,组件将可重用的HTML元素封装成为标签方便复用;
组件的使用:
- 使用全局方法Vue.extend创建构造器;
- 再使用全局方法Vue.component注册组件;
注意,在Vue.component里需要指明组件的名称,组件名称不能使用内置标签名称,如body。推荐使用短横线命名规则。例:
- my-component 正确 (推荐)
- my-Component 错误
- mycomponent 正确
- Mycomponent 正确
- myComponent 错误
- MyComponent 错误
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>01_component</title>
</head>
<body>
<div id="sikiedu">
<h3>hello Vue1</h3>
<my-component></my-component>
<my-component-a></my-component-a>
</div>
</body>
<script type="text/javascript" src="../js/vue.js" ></script>
<script type="text/javascript">
//创建构造器
let myComponent = Vue.extend({
template : "<h1>hello Vue2</h1>"
});
//注册组件
Vue.component('my-component', myComponent);
//注册组件的简写
Vue.component('my-component-a', {
name : 'siki-edu',
template : "<h2>hello sikiedu</h2>"
})
new Vue({
data : {
msg : '123'
}
}).$mount("#sikiedu");
</script>
</html>
二,全局组件与局部组件
组件可分为全局组件与局部组件;
全局组件:
- 在全局API中的Vue.component注册;
- 该项目中所有Vue实例内均可以使用;
局部组件:
- 在Vue实例中的components选项中注册;
- 只能在本实例中使用;
全局组件和局部组件都可以存储数据,但是存储的方式与Vue实例中的data稍有不同;
组件里存储数据,data后需加上函数,数据写在函数体中。例:以下是在局部组件的data中,定义了name属性;
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>02_component</title>
</head>
<body>
<div id="sikiedu">
<my-component-b></my-component-b>
</div>
<div id="joey">
<my-component-a></my-component-a>
</div>
</body>
<script type="text/javascript" src="../js/vue.js" ></script>
<script type="text/javascript">
//注册组件的简写
Vue.component('my-component-a', {
template : "<h2>{{name}}</h2>",
data : function(){
return {
name : 'hello sikiedu11'
}
}
})
new Vue({
data : {
msg : '123'
},
components : {
"my-component-b" : {
template : "<h2>{{name}}</h2>",
data(){
return {
name : "my-component-b !!"
}
}
}
}
}).$mount("#sikiedu");
new Vue({
data : {
msg : 'abc'
}
}).$mount("#joey");
</script>
</html>
三,template模板引用
在component的template中书写大量的HTML元素很麻烦。
Vue提供了<template>标签,可以在里边书写HTML,然后通过ID指定到组建内的template属性上;
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>03_component_Template</title>
</head>
<body>
<div id="sikiedu">
<my-component-b></my-component-b>
<my-component-b></my-component-b>
</div>
</body>
<template id="my-template">
<div>
<h2>{{name}}</h2>
<button @click="count++">{{count}}</button>
<ul>
<li v-for="item in numArray">{{item}}</li>
</ul>
</div>
</template>
<script type="text/javascript" src="../js/vue.js" ></script>
<script type="text/javascript">
new Vue({
data : {
msg : '123'
},
components : {
"my-component-b" : {
template : "#my-template",
data(){
return {
name : "my-component-b !!",
numArray : [1, 2, 3, 4, 5],
count : 0
}
}
}
}
}).$mount("#sikiedu");
</script>
</html>
四,动态组件
在一个元素上挂载多个组件,根据不同状态进行切换的时候,可以使用动态组件;
动态组件的使用:需要使用内置组件<component></component>,根据 :is 的值决定显示哪个组件,:is的值是要显示的组件id;
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>04_dynamic_Component</title>
</head>
<body>
<div id="sikiedu">
<button @click="selectedName = 'my-component-a'"> a </button>
<button @click="selectedName = 'my-component-b'"> b </button>
<button @click="selectedName = 'my-component-c'"> c </button>
<component :is="selectedName"></component>
</div>
</body>
<script type="text/javascript" src="../js/vue.js" ></script>
<script type="text/javascript">
new Vue({
data : {
selectedName : 'my-component-a'
},
components : {
"my-component-a" : {
template : "<h1>hello Vue</h1>"
},
"my-component-b" : {
template : "<a href='http://www.sikiedu.com'>sikiedu官网</a>"
},
"my-component-c" : {
template : "<p>欢迎来到siki学院学习!</p>"
}
}
}).$mount("#sikiedu");
</script>
</html>
五,动态组件结合keep-alive
keep-alive:包裹动态组件时,会缓存不活动的组件示例,而不是销毁它们。
max:数字。最多可以缓存多少组件示例
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>05_keep-alive</title>
</head>
<body>
<div id="sikiedu">
<button @click="selectedName = 'my-component-a'"> a </button>
<button @click="selectedName = 'my-component-b'"> b </button>
<button @click="selectedName = 'my-component-c'"> c </button>
<keep-alive :max="2">
<component :is="selectedName"></component>
</keep-alive>
</div>
</body>
<script type="text/javascript" src="../js/vue.js" ></script>
<script type="text/javascript">
new Vue({
data : {
selectedName : 'my-component-a'
},
components : {
"my-component-a" : {
name : 'my-com-a',
template : "<h1>A : {{num}}</h1>",
data(){
return {
num : Math.ceil( Math.random() * 100)
}
}
},
"my-component-b" : {
template : "<a href='http://www.sikiedu.com'>B : {{num}}</a>",
data(){
return {
num : Math.ceil( Math.random() * 100)
}
}
},
"my-component-c" : {
template : "<p>C : {{num}}</p>",
data(){
return {
num : Math.ceil( Math.random() * 100)
}
}
}
}
}).$mount("#sikiedu");
</script>
</html>
这个示例的结果自己调试,录屏有点麻烦 。。
六,父子组件的关系
在Vue的组件内也可以定义组件,这种关系成为父子组件的关系;
如果在一个Vue实例中定义了component-a,然后在component-a中定义了component-b,那他们的关系就是:
Vue实例 -- 根组件 root
component-a – 相对于root 这是子组件,相对于component-b这是 父组件
component-b -- 子组件
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>06_fatherAndChild</title>
</head>
<body>
<div id="sikiedu">
<father-component></father-component>
</div>
</body>
<template id="father-template">
<div>
<h1>father component</h1>
myData : <span>{{name}}</span>
<hr />
<child-component></child-component>
</div>
</template>
<template id="child-template">
<div>
<h2>child component</h2>
fatherData : <span>{{name}}</span>
</div>
</template>
<script type="text/javascript" src="../js/vue.js" ></script>
<script type="text/javascript">
new Vue({
data : {
},
components : {
"father-component" : {
template : "#father-template",
data:()=>({
name:"joey"
}),
components : {
"child-component" : {
template : "#child-template",
data(){
return{
name:"lijiang"
}
}
}
}
}
}
}).$mount("#sikiedu");
</script>
</html>
七,组件通信 - 父组件向子组件传值
父组件向子组件传值:父组件通过属性向下传值的方式和子组件通信;
使用步骤:
- 定义组件:现有自定义组件com-a、com-b,com-a是com-b的父组件;
- 准备获取数据:com-b要获取父组件data中的NAME属性;
- 在<com-b :name=“NAME”></com-b> 使用v-bind 绑定NAME属性,红色部分为属性名称,可以随意写。
- 在子组件定义部分里添加选项,值是个字符串数组 props:[‘name’],将上边红色的属性名称写在这里;
- 之后就可定义在子组件中使用name属性了;
例1:
结果:
例2:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>07_fatherToChild</title>
</head>
<body>
<div id="sikiedu">
<father-component :msg="msg"></father-component>
</div>
</body>
<template id="father-template">
<div>
<h1>father component</h1>
myData : <span>{{NAME}} , {{id}} , {{user.username}}</span><br />
fatherDate : <span>{{msg}}</span><br />
<input type="text" v-model="NAME"/>
<hr />
<child-component :username="NAME" :id="id" :user="user"></child-component>
</div>
</template>
<template id="child-template">
<div>
<h2>child component</h2>
fatherData : <span>{{username}} , {{id}} , {{user.username}}</span>
</div>
</template>
<script type="text/javascript" src="../js/vue.js" ></script>
<script type="text/javascript">
new Vue({
data : {
msg : 'helloVue'
},
components : {
"father-component" : {
template : "#father-template",
data(){
return {
id : 1,
NAME : 'joey',
user : {
username : 'sikiedu-joey',
password : '123123'
}
}
},
props : ['msg'],
components : {
"child-component" : {
template : "#child-template",
props : ['username', 'id', 'user']
}
}
}
}
}).$mount("#sikiedu");
</script>
</html>
推荐文章:https://blog.csdn.net/qq_42492055/article/details/82558971 (父子间传值)
props选项高级选项配置
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>08_props</title>
</head>
<body>
<div id="sikiedu">
<father-component></father-component>
</div>
</body>
<template id="father-template">
<div>
<h1>father component</h1>
myData :
<span>
{{name}} ,
{{id}} ,
{{user.username}} ,
{{age}}
</span><br /><hr />
<child-component :id="id" :age="age"></child-component>
</div>
</template>
<template id="child-template">
<div>
<h2>child component</h2>
fatherData :
<span>
{{name}} ,
{{id}} ,
{{user.username}},
{{age}}
</span>
</div>
</template>
<script type="text/javascript" src="../js/vue.js" ></script>
<script type="text/javascript">
new Vue({
data : {
},
components : {
"father-component" : {
template : "#father-template",
data(){
return {
id : '01',
name : 'joey',
user : {
username : 'lijiang',
password : '123123'
},
age : 18
}
},
props : ['msg'],
components : {
"child-component" : {
template : "#child-template",
props : {
name : {
type : String,
default : "siki"
},
id : [Number, String],
user : {
type : Object,
default : function(){
return {username : 'lain', password : '123123'};
}
},
age : {
type : Number,
validator : function(value){
return value >= 0;
}
}
}
}
}
}
}
}).$mount("#sikiedu");
</script>
</html>
八,组件通信 -子组件向父组件传值
子组件向父组件传值:子组件通过$.emit()方法以事件形式向父组件发送消息传值;
使用步骤:
- 定义组件:现有自定义组件com-a、com-b,com-a是com-b的父组件;
- 准备获取数据:父组件com-a要获取子组件data中的height属性;
- 在子组件com-b中,需要用$.emit()方法将数据以事件的形式发送,$.emit('sendData', data, data…),红色的部分事件名可自定义,数据可传递多个;
- 在父组件中使用子组件的地方 <com-b @自定义事件名='getData'></com-b> 监听子组件自定义的事件,并且在方法中获取数据;
- 在父组件data定义height属性;
- 在父组件中实现getData(height)方法,方法参数是子组件传递的数据,例如这里直有一个height,然后为this.height赋值;
- 赋值完毕后就可以使用了;
例1:
父组件:
例2:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>09_childToFather</title>
</head>
<body>
<div id="sikiedu">
<father-component></father-component>
</div>
</body>
<template id="father-template">
<div>
<h1>father component</h1>
myData :
<span>
{{name}} ,
{{id}} ,
{{user.username}} ,
{{age}}
</span><br />
childData :
<span>
{{width}},
{{height}}
</span><hr />
<child-component :id="id" :age="age" @send-event="getData"></child-component>
</div>
</template>
<template id="child-template">
<div>
<h2>child component</h2>
fatherData :
<span>
{{name}} ,
{{id}} ,
{{user.username}},
{{age}}
</span><br />
myData :
<span>
{{width}},
{{height}}
</span><br />
<button @click="sendData">向父组件发送数据</button>
</div>
</template>
<script type="text/javascript" src="../js/vue.js" ></script>
<script type="text/javascript">
new Vue({
data : {
},
components : {
"father-component" : {
template : "#father-template",
methods : {
getData(width, height){
this.width = width;
this.height = height;
}
},
data(){
return {
id : '01',
name : 'joey',
user : {
username : 'lijiang',
password : '123123'
},
age : 18,
width : 0,
height : 0
}
},
components : {
"child-component" : {
template : "#child-template",
methods : {
sendData(){
console.log(this);
this.$emit('send-event', this.width, this.height);
}
},
data(){
return {
width : 50,
height : 100
}
},
props : {
name : {
type : String,
default : "siki"
},
id : [Number, String],
user : {
type : Object,
default : function(){
return {username : 'lain', password : '123123'};
}
},
age : {
type : Number,
validator : function(value){
return value >= 0;
}
}
}
}
}
}
}
}).$mount("#sikiedu");
</script>
</html>
九,单向数据流
单向数据流:父组件值的更新,会影响到子组件,反之则不行;
修改子组件的值:
- 局部数据:在子组件中定义新的数据,将父组件传过来的值赋值给新定义的数据,之后操作这个新数据;
- 如果对数据进行简单的操作,可以使用计算属性;
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>10_one-Way Data Flow</title>
</head>
<body>
<div id="sikiedu">
<father-component ></father-component>
</div>
</body>
<template id="father-template">
<div>
<h1>father component</h1>
myData : <span>{{name}}</span><br />
<input type="text" v-model="name"/><hr />
<child-component :name="name"></child-component>
</div>
</template>
<template id="child-template">
<div>
<h2>child component</h2>
fatherData : <span>{{childUpperName}}</span><br />
<input type="text" v-model="childUpperName"/><hr />
</div>
</template>
<script type="text/javascript" src="../js/vue.js" ></script>
<script type="text/javascript">
new Vue({
data : {
msg : 'helloVue'
},
components : {
"father-component" : {
template : "#father-template",
data(){
return {
name : 'joey'
}
},
props : ['msg'],
components : {
"child-component" : {
template : "#child-template",
props : ['name'],
data(){
return {
childName : this.name
}
},
computed : {
childUpperName(){
return this.name.toString().toUpperCase();
}
}
}
}
}
}
}).$mount("#sikiedu");
</script>
</html>
单向数据流子组件数据同步到父组件
修改子组件的prop,同步到父组件:
- 使用.sync修饰符;
- 将要操作的数据封装成一个对象再操作;
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>11_one-Way Data Flow_01</title>
</head>
<body>
<div id="sikiedu">
<father-component ></father-component>
</div>
</body>
<template id="father-template">
<div>
<h1>father component</h1>
name : <span>{{name}}</span><br />
<input type="text" v-model="name"/><br />
userID : <span>{{user.id}}</span><br />
<input type="text" v-model="user.id"/><br />
<hr />
<child-component :name.sync="name" :user="user"></child-component>
</div>
</template>
<template id="child-template">
<div>
<h2>child component</h2>
fatherData : <span>{{childName}}</span><br />
<input type="text" v-model="childName"/><br />
userID : <span>{{user.id}}</span><br />
<input type="text" v-model="user.id"/><br />
<hr />
</div>
</template>
<script type="text/javascript" src="../js/vue.js" ></script>
<script type="text/javascript">
new Vue({
data : {
msg : 'helloVue'
},
components : {
"father-component" : {
template : "#father-template",
data(){
return {
name : 'joey',
user : {
id : 1
}
}
},
props : ['msg'],
components : {
"child-component" : {
template : "#child-template",
props : ['name', 'user'],
data(){
return {
childName : this.name
}
},
computed : {
childUpperName(){
return this.name.toString().toUpperCase();
}
},
updated(){
this.$emit('update:name', this.childName);
}
}
}
}
}
}).$mount("#sikiedu");
</script>
</html>
十,非父子关系组件通信
Vue中不同的组件,即使不存在父子关系也可以相互通信,我们称为非父子关系通信;
我们需要借助一个空Vue实例,在不同的组件中,使用相同的Vue实例来发送/监听事件,达到数据通信的目的;
例1:
运行结果:
例2:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>12_non-fatherAndSon</title>
</head>
<body>
<div id="sikiedu">
<my-component-a></my-component-a>
<my-component-b></my-component-b>
</div>
</body>
<template id="template-a">
<div>
<h1>my-component-a</h1>
comA name : <span>{{name}}</span><br />
<button @click="sendData">发送数据给comB</button>
<hr />
</div>
</template>
<template id="template-b">
<div>
<h2>my-component-b</h2>
comB name : <span>{{nameB}}</span>
<hr />
</div>
</template>
<script type="text/javascript" src="../js/vue.js" ></script>
<script type="text/javascript">
let comA = {
template : "#template-a",
data(){
return {
name : "joey"
}
},
methods : {
sendData(){
vm.$emit('send-event-a', this.name);
}
}
}
let comB = {
template : "#template-b",
data(){
return {
nameB : ''
}
},
mounted(){
vm.$on('send-event-a', name => {
console.log(this);
this.nameB = name;
})
}
}
let vm = new Vue({
data : {
msg : 'sikiedu'
}
});
new Vue({
data : {
},
components : {
"my-component-a" : comA,
"my-component-b" : comB
}
}).$mount("#sikiedu");
</script>
</html>
十一,使用slot分发内容
有时候我们需要在自定义组件内书写一些内容,例如:
<com-a>
<h1>title</h1>
</com-a>
如果想获取上面代码片段中h1标签的内容该怎么办呢?Vue提供了一个极为方便的内置组件<slot>;
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>13_slot</title>
</head>
<body>
<div id="sikiedu">
<my-component-a>
<h1 slot="title">我才是大标题</h1>
<ul slot="ulli">
<li>a</li>
<li>b</li>
<li>c</li>
</ul>
<!-- <a href="#" slot="a">点击我传送</a> -->
</my-component-a>
</div>
</body>
<template id="template-a">
<div>
<slot name="a">数据为空</slot>
<slot name="title">数据为空</slot>
<h1>my-component-a</h1>
<slot name="ulli">数据为空</slot>
</div>
</template>
<script type="text/javascript" src="../js/vue.js" ></script>
<script type="text/javascript">
let comA = {
template : "#template-a"
}
new Vue({
data : {
},
components : {
"my-component-a" : comA
}
}).$mount("#sikiedu");
</script>
</html>
这里推荐一篇关于slot的资料,感觉还不错:https://blog.csdn.net/kingov/article/details/78293384