组件使用三个步骤:
需要在vue实例中使用
- 创建组件构造器
- 注册组件
- 使用组件
<body>
<div id="app">
<!--3.使用组件-->
<my-cpn></my-cpn>
<my-cpn></my-cpn>
<my-cpn></my-cpn>
</div>
<script>
//1.创建组件构造器
const cpnC = Vue.extend({
template: `
<div>
<h2>I am title</h2>
<p>I am content</p>
<p>I am content</p>
</div>
`
})
//2.注册组件(全局组件,意味着可以在多个Vue实例中使用)
Vue.component('my-cpn', cpnC)
//创建Vue实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {},
//局部组件
components: {
'cpn': cpnC,
},
});
</script>
</body>
- 全局组件:可以在多个vue实例中被使用
- 局部组件:只可以在被注册的vue实例中使用
父组件和子组件
组件之间的层级关系
vue实例可以看作是一个根组件
//父组件
const cpn2 = Vue.extend({
template: `
<div>
<h2>I am title222</h2>
<p>I am 哈哈哈哈哈哈</p>
<p>I am conte哈哈哈nt</p>
<cpn11></cpn11>
</div>
`,
//子组件
components: {
cpn11: cpn1
}
})
注册组件的语法糖
全局组件:
<script>
Vue.component('my-cpn', {
template: `
<div>
<h2>I am title</h2>
<p>I am 哈哈哈哈哈哈</p>
<p>I am conte哈哈哈nt</p>
</div> `
})
//创建Vue实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {},
//局部组件
components: {
'cpn': {
template: `
<div>
<h2>I am title222</h2>
<p>I am 哈哈哈哈哈哈</p>
<p>I am conte哈哈哈nt</p>
</div> `
}
},
});
</script>
省去了vue.extend()的步骤
模板的分离写法
<script type="text/x-template" id='cpn'>
<div>
<h2>I am title</h2>
<p>I am 哈哈哈哈哈哈</p>
<p>I am 模板的分离写法</p>
</div>
</script>
<script>
Vue.component('my-cpn', {
template: `#cpn`
})
<template id="cpn2">
<div>
<h2>I am title</h2>
<p>I am template</p>
<p>I am 模板的分离写法</p>
</div>
</template>
组件的data要为一个函数:
<template id="cpn">
<div>
<h2>I am {{title}}</h2>
<p>I am template</p>
<p>I am 模板的分离写法</p>
</div>
</template>
<script>
Vue.component('my-cpn', {
template: `#cpn`,
data() {
return {
title: 'aaaaaaaaaaa'
}
}
})
为什么要为函数:
防止组件间的数据相互干扰,保证数据独立。
父子组件的通信
父传子:通过props
子传父:通过$emit:events
父传子-props使用
<body>
<div id="app">
<button @click="changeData">change</button>
<!--使用组件-->
<my-cpn :name="myName" :age="myAge"></my-cpn>
<my-cpn></my-cpn>
</div>
<template id="cpn">
<div>
<h2>{{name}}</h2>
<h2>{{age}}</h2>
<h2>{{info}}</h2>
</div>
</template>
<script>
Vue.component('my-cpn', {
template: `#cpn`,
// props: ['name', 'age'],
props: {
name: {
type: String,
default: 'laaa'
},
age: {
//类型为对象或数组时,默认值必须为函数
type: Number,
default: 18,
//required为true表示必须传入
//required:true
},
info: {
//类型为对象或数组时,默认值必须为函数
type: Object,
default: function () {
return {
name: 'luo',
age: 22
}
}
}
}
})
//创建Vue实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
myName: 'luo',
myAge: 24
},
methods: {
changeData() {
this.myAge++
}
}
});
</script>
</body>
子传父-$emit
<body>
<div id="app">
<!--使用组件-->
<my-cpn :name="myName" :age="myAge" @inc="myCounter" @dec="myCounter"></my-cpn>
</div>
<template id="cpn">
<div>
<button @click="inc">+</button>
<button @click="dec">-</button>
</div>
</template>
<script>
Vue.component('my-cpn', {
template: `#cpn`,
props: {
},
data() {
},
methods: {
inc() {
this.counter++
this.$emit('inc', {
name: 'lai',
age: 66,
counter: this.counter
})
},
dec() {
this.counter--
this.$emit('dec', {
name: 'hua',
age: 88,
counter: this.counter
})
}
}
})
//创建Vue实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
},
methods: {
myCounter(info) {
console.log(info);
}
},
</script>
</body>
父子组件的访问方式
- 父访问子:$children或者 $refs (reference)
- 子访问父:$parent
$children–数组类型
包含所有子组件对象
<body>
<div id="app">
<button @click="getChildren">test</button>
<!--使用组件-->
<my-cpn @inc="myCounter" @dec="myCounter"></my-cpn>
<my-cpn></my-cpn>
</div>
<template id="cpn">
<div>
<button @click="inc">+</button>
<button @click="dec">-</button>
</div>
</template>
<script>
Vue.component('my-cpn', {
template: `#cpn`,
// props: ['name', 'age'],
props: {
}
},
data() {
return {
title: 'aaaaaaaaaaa',
counter: 0
}
},
methods: {
showMessage() {
console.log('test.......');
},
inc() {
this.counter++
this.$emit('inc', {
name: 'lai',
age: 66,
counter: this.counter
})
},
dec() {
this.counter--
this.$emit('dec', {
name: 'hua',
age: 88,
counter: this.counter
})
}
}
})
//创建Vue实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
myName: 'luo',
myAge: 24,
counter: 0
},
methods: {
getChildren() {
console.log(this.$children);
this.$children[0].inc()
this.$children[0].showMessage()
}
},
});
</script>
</body>
$children返回的是个数组,取特定组件数据时是按照排列顺序编号,在有许多组件的情况下不方便。
$refs
<my-cpn ref='a' :name="myName" :age="myAge" @inc="myCounter" @dec="myCounter"></my-cpn>
<my-cpn ref='b'></my-cpn>
getChildren() {
console.log(this.$refs);
this.$refs.a.showMessage()
this.$refs.b.showMessage()
},
首先给组件添加ref="name"属性,然后在父组件方法中调用该名称的组件即可。
子访问父-$parent
console.log(this.$parent);
不建议使用,降低了组件的复用性
slot 插槽
让封装的组件更具有拓展性
基本使用:
<div id="app">
<cpn>
<!--可以放置多个值-->
<button>test</button>
<h2>test</h2>
</cpn>
<cpn></cpn>
<cpn></cpn>
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h2>我是组件</h2>
<p>hhhhhhhhhh</p>
<slot>
<!--插槽默认值-->
<h2>slot default</h2>
</slot>
</div>
</template>