1、创建一个组件
- 首先要创建一个根组件进行挂载
- 再创建一个子组件,完成子组件的逻辑
- 子组件主要使用template模板来完成布局和逻辑
- 把子组件通过根组件.component的方法挂载到根组件上
<body>
<div id="app">
<div class="component">
<button-counter></button-counter>
</div>
</div>
<script>
const app=Vue.createApp({
data(){
return {
msg:''
}
},
})
app.component('button-counter',{
data(){
return {
count:0,
}
},
methods:{
addcount(){
this.count++
}
},
template:`
<button @click="addcount">你点击了按钮{{count}}次</button>
`
})
app.mount('#app')
</script>
</body>
2、页面中存放多个vue实例,虽然这样不合适
<body>
<div id="app">
</div>
<div id="root">
</div>
<script>
const app=Vue.createApp({
data(){
return {
msg:'我是模板111'
}
},
template:`<p>模板1{{msg}}</p>`
}).mount('#app')
const root=Vue.createApp({
data(){
return {
msg:'我是模板222'
}
},
template:`<p>模板2{{msg}}</p>`
}).mount('#root')
</script>
</body>
3、全局组件
全局组件:全局注册,可以在页面级页面中的子组件中使用 局部组件:只能在他定义的子组件中使用,不能在页面中使用
全局组件案例:
<body>
<div id="app">
<div id="home">
<button-counter></button-counter>
<span>首页</span>
</div>
<div id="message">
<button-counter></button-counter>
<span>消息</span>
</div>
<div id="mine">
<button-counter></button-counter>
<span>我的</span>
</div>
<button-counter></button-counter>
</div>
<script>
const app=Vue.createApp({
data(){
return {
msg:''
}
}
})
app.component('button-counter',{
data(){
return {
count:0
}
},
methods:{
add(){
this.count++
}
},
template:`<button @click="add">点击增加计数{{count}}</button>`,
})
app.mount('#app')
</script>
</body>
4、局部组件
- 局部组件是通过常量来接收的,在页面根对象中注册(在components里注册,一定要是键值对的形式,简写出问题)
- 局部组件不可以在不在局部注册的情况下嵌套,全局组件可以嵌套,
- 如果局部组件要嵌套,必须在自己被嵌套的组件内部注册components。
<body>
<div id="app">
<p>====使用全局组件====</p>
<button-counter></button-counter>
<p>====使用局部组件====</p>
<area-com></area-com>
</div>
<script>
const area={
data(){
return {
}
},
template: `<p>这是个局部组件</p>`
}
const app=Vue.createApp({
data(){
return {
msg:''
}
},
components:{
'area-com':area
},
})
app.component('button-counter',{
data(){
return {
count:0
}
},
methods:{
add(){
this.count++
}
},
template:`<button @click="add">点击增加计数{{count}}</button>`,
})
app.mount('#app')
</script>
</body>
局部组件嵌套案例
<body>
<div id="app">
<p>====使用全局组件====</p>
<button-counter></button-counter>
<p>====使用局部组件====</p>
<area-com></area-com>
<dance-com></dance-com>
</div>
<script>
const dancer={
data(){
return{
}
},
template:`<p>这是另外一个局部组件</p>`
}
const area={
data(){
return {
}
},
components: {
'dance-com':dancer
},
template: `
<b><dance-com></dance-com></b>
<p>这是个局部组件</p>`
}
const app=Vue.createApp({
data(){
return {
msg:''
}
},
components:{
'area-com':area,
'dance-com':dancer
},
})
app.component('button-counter',{
data(){
return {
count:0
}
},
methods:{
add(){
this.count++
}
},
template:`<button @click="add">点击增加计数{{count}}</button>`,
})
app.mount('#app')
</script>
</body>
5、父子组件
父子组件中注册的子组件,不要在实例中直接去使用,也就是说,只能把组件用在template模板中
6、组件标签化
- 使用script标签,也就是把template模板内的内容,独立到script标签里去了,从而减少组件内代码量
<body>
<div id="app">
<dancer-com></dancer-com>
</div>
<!--把模板标签化了,这里一定要使用taype=’text/template’-->
<script type="text/template" id="dancer">
<p>这是dancer组件</p>
</script>
<script>
const dancer={
data(){
return{
}
},
template:'#dancer'
}
const app=Vue.createApp({
data(){
return {
msg:''
}
},
components:{
'dancer-com':dancer
},
})
app.mount('#app')
</script>
</body>
- 使用template标签,也就是把template模板内的内容,独立到template标签里去了,从而减少组件内代码量
<body>
<div id="app">
<dancer-com></dancer-com>
</div>
<!--把模板标签化了,这里一定要使用taype=’text/template’-->
<template id="dancer">
<p>这是dancer组件,使用template标签容纳</p>
</template>
<script>
const dancer={
data(){
return{
}
},
template:'#dancer'
}
const app=Vue.createApp({
data(){
return {
msg:''
}
},
components:{
'dancer-com':dancer
},
})
app.mount('#app')
</script>
</body>
7、组件data数据共享问题
组件内部data数据只能组件自己使用,不能共享出去,实际上就是组件具有封装性
<body>
<div id="app">
<p>{{msg}}</p>
<p>-----------</p>
<dancer-com></dancer-com>
</div>
<!--把模板标签化了,这里一定要使用taype=’text/template’-->
<template id="dancer">
<p>{{msg}}</p>
<p>这是dancer组件,使用template标签容纳</p>
</template>
<script>
const dancer={
data(){
return{
msg:'子组件dancer定义的内容'
}
},
template:'#dancer'
}
const app=Vue.createApp({
data(){
return {
msg:'页面中定义的数据'
}
},
components:{
'dancer-com':dancer
},
})
app.mount('#app')
</script>
</body>
8、组件的data选项必须是函数
- 主要是为了数据能够隔离开,没创建一个新的组件就开创一个新的对象,而不是共用一个对象。
- 共用一个对象的结果就是每个组件内部的数据会受到其他组件的修改,应为多个组件指向同一个内存堆控件
9、组件间通讯
不要在子组件中直接修改父组件的状态数据() 数据和处理数据的函数应该在同一模块内
组件通信的常用方式:
- props
- 自定义事件
- 消息订阅与发布
- vuex(消息和状态管理机制)
10、组件间通讯-props
11、组件间通讯-props–只指定名称
步骤
- 在页面中定义数据
- 在组件中定义props(可以是数组,也可以是对象)
- 在html中引用组件,并以属性及属性值的形式向props传值(键名是数组元素名称)
- 传值完毕后,在子组件的template中引用该props数组元素的名称
<body>
<div id="app">
<!--这里要使用绑定语法-->
<study-com :university="msg1" :course="msg2"></study-com>
</div>
<!--把模板标签化了,这里一定要使用taype=’text/template’-->
<template id="study">
<p>--------</p>
<h3>这是一个子组件</h3>
<h3>{{university}}</h3>
<h3 v-for="(item,index) in course" :key="index">{{item}}</h3>
<p>--------</p>
</template>
<script>
const study={
data(){
return {
}
},
props:['university','course'],
template:'#study'
}
const app=Vue.createApp({
data(){
return {
msg1:'北京大学',
msg2:['JavaScript','ios','android']
}
},
components:{
'study-com':study
},
})
app.mount('#app')
</script>
</body>
12、父子组件间通讯-props–指定名称和类型
<body>
<div id="app">
<uni-com :uni="msg1" :courses="msg2"></uni-com>
<uni-com :uni="msg3" :courses="msg4"></uni-com>
</div>
<!--把模板标签化了,这里一定要使用taype=’text/template’-->
<template id="university">
<p>这是一个子组件</p>
<h3>这里显示学校名称 {{uni}}</h3>
<p>这里遍历学院名称</p>
<ul>
<li v-for="(item,index) in courses" :key="index" >{{item}}</li>
</ul>
</template>
<script>
const university={
data(){
return {
}
},
props:{
uni:String,
courses:Array
},
template:'#university'
}
const app=Vue.createApp({
data(){
return {
msg1:'清华大学',
msg2:['经管学院','建筑学院','文法学院'],
msg3:'北京大学',
msg4:['数学学院','考古','新闻传播学院'],
}
},
components:{
'uni-com':university
}
})
app.mount('#app')
</script>
</body>
更复杂的形式,对props传来的数据做名称,类型,必须与否等,默认值的限定
<body>
<div id="app">
<uni-com :uni="msg1" :courses="msg2"></uni-com>
<uni-com :uni="msg3" :courses="msg4"></uni-com>
</div>
<!--把模板标签化了,这里一定要使用taype=’text/template’-->
<template id="university">
<p>这是一个子组件</p>
<h3>这里显示学校名称 {{uni}}</h3>
<p>这里遍历学院名称</p>
<ul>
<li v-for="(item,index) in courses" :key="index" >{{item}}</li>
</ul>
</template>
<script>
const university={
data(){
return {
}
},
props:{
uni: {
type:String,
default:'天津大学',
required:true
},
courses: {
type:Array,
default: [],
required: true
}
},
template:'#university'
}
const app=Vue.createApp({
data(){
return {
msg1:'清华大学',
msg2:['经管学院','建筑学院','文法学院'],
msg3:'北京大学',
msg4:['数学学院','考古','新闻传播学院'],
}
},
components:{
'uni-com':university
}
})
app.mount('#app')
</script>
</body>
13、props注意事项
String Number Boolean Array Object Date Function Symbol 自定义类型
- 此方式用于父组件向子组件传递数据
- 所有标签属性都会成为组件对象的属性,模板页面可以直接引用
- 如果需要向非子后代传递数据必须多层逐层传递
- 兄弟组件间也不能直接props通信,必须借助父组件才可以
14、子组件通过自定义事件向父组件传递数据
只适合父子组件之间的数据传递(实际上是子向父传递),不适合隔代组件和兄弟组件传递数据 两个步骤
@click=“***”
this.$emit('函数名',{数据对象}
2、子组件触发事件
@btnclick='deletep'
deletep(){
相关逻辑
}
案例1:接受发射的事件,但不接受数据
<body>
<div id="app">
<subcom @recivefromsub="revicefunction"></subcom>
</div>
<!--把模板标签化了,这里一定要使用taype=’text/template’-->
<template id="mysub">
<p>=============</p>
<h3>这是我的子组件</h3>
<button @click="btnClickForEmit">发射一个自定义事件给父组件</button>
<p>=============</p>
</template>
<script>
const sub={
data(){
return {
}
},
methods: {
btnClickForEmit(){
this.$emit('recivefromsub')
}
},
template:'#mysub'
}
const app=Vue.createApp({
data(){
return {
msg:'默认信息'
}
},
methods: {
revicefunction(){
console.log('接受到了子组件发射过来的数据,但没有接受数据')
}
},
components:{
'subcom':sub
}
})
app.mount('#app')
</script>
</body>
案例2:接受发射的事件,同时接受数据(数据可以是个对象也可以是其他数据类型)
- 子组件发射时间的过程中,同时也发送数据额
- 父组件使用发射过来的自定义事件名,同时也接受了传递的数据,并在回调函数隐含了一个datas(名字自取)的参数。
<body>
<div id="app">
<subcom @recivefromsub="revicefunction"></subcom>
</div>
<!--把模板标签化了,这里一定要使用taype=’text/template’-->
<template id="mysub">
<p>=============</p>
<h3>这是我的子组件</h3>
<button @click="btnClickForEmit">发射一个自定义事件给父组件</button>
<p>=============</p>
</template>
<script>
const sub={
data(){
return {
}
},
methods: {
btnClickForEmit(){
const obj={
name:'子组件的数据信息',
intro:'可以使用一个对象来传递数据信息'
}
this.$emit('recivefromsub',obj)
}
},
template:'#mysub'
}
const app=Vue.createApp({
data(){
return {
msg:'默认信息'
}
},
methods: {
revicefunction(datas){
console.log('接受到了子组件发射过来的数据')
console.log(datas)
}
},
components:{
'subcom':sub
}
})
app.mount('#app')
</script>
</body>
15、组件通信之PubSub发布订阅(见后续章节)
16、父子组件相互访问–父组件访问子组件$refs
主要步骤
<subcom ref=‘info’></subcom>
2、在父组件通过事件,在回调函数中通过this.$refs获取这个ref信息
this.$refs
获取来的信息在this.
r
e
f
s
.
i
n
f
o
.
m
s
g
中
此
外
也
可
以
获
取
子
组
件
的
方
法
,
方
法
存
在
于
t
h
i
s
.
refs.info.msg中 此外也可以获取子组件的方法,方法存在于this.
refs.info.msg中此外也可以获取子组件的方法,方法存在于this.refs.info.方法名
<body>
<div id="app">
<!-- 给子组件绑定一个ref-->
<subcom ref="info"></subcom>
<button @click="getChildrenCom">获取子组件</button>
</div>
<!--把模板标签化了,这里一定要使用taype=’text/template’-->
<template id="sub">
<p>======</p>
<h3>这是一个子组件</h3>
<button @click="clickSub">点击了子组件的按钮</button>
<p>======</p>
</template>
<script>
const sub={
data(){
return {
msg: '子组件的信息'
}
},
methods: {
printinfo(){
console.log('来自子组件中的方法')
},
clickSub(){
alert('点击了子组件的按钮')
}
},
template:'#sub'
}
const app=Vue.createApp({
data(){
return {
msg:'默认信息'
}
},
methods: {
getChildrenCom(){
console.log(this.$refs.info.msg)
this.$refs.info.printinfo()
}
},
components:{
'subcom':sub
}
})
app.mount('#app')
</script>
</body>
17、父子组件相互访问–子组件访问父组件$parent
一般不建议子组件访问父组件,会破坏父组件的复用性
<body>
<div id="app">
<sub-Box></sub-Box>
</div>
<!--把模板标签化了-->
<template id="subbutton">
<h3>这是第一个subbutton子组件</h3>
<button @click="subtbclickTime">点击了按钮{{count}}次</button>
</template>
<!--把模板标签化了-->
<template id="subBox">
<p>这是subBox组件</p>
<subbuttoncom></subbuttoncom>
</template>
<script>
const subbutton={
data(){
return {
count:0
}
},
methods:{
subtbclickTime(){
this.count++
console.log(this.$root.msg)
}
},
template:'#subbutton'
}
const subBox={
data(){
return {
parentInfo:'父组件的默认信息'
}
},
components: {
'subbuttoncom':subbutton
},
template:'#subBox',
}
const app=Vue.createApp({
data(){
return {
msg:'这是根组件的默认信息'
}
},
components:{
'subBox':subBox
}
})
app.mount('#app')
</script>
</body>
|