认识组件
组件化开发:
将一个完成的页面,划分成一个个的组件,最终由一个个组件来完成整个页面你的开发,这个过程就是组件化开发
优势:复用!!
也就是说组件只需要写一次,然后,用到组件的地方,只需要拿过去用就可以了
组成
一个组件由三部分组成:HTML+CSS+JS
两种注册组件的方式:
1 全局组件
2 局部组件
注册全局组件:
第一个参数:表示组件名称
第二个参数:是一个配置对象,这个配置对象类似于 Vue 构造函数中使用的配置对象
也就是说:在 Vue 构造函数中能够使用的配置项,几乎都可以用在组件中
template 作用:指定组件模板
注意:只能出现一个根节点
通过 data 指定组件中用到的数据
注意:组件中的数据data,是一个方法,通过方法的返回对象来作为组件数据
我的第一个全局组件
Document
注册局部组件
通过配置项 components: {}
//html
//js
Vue.component('wang',{
template:`
我是王婷,
`,
components:{
//组件名称
ting:{
//组件模板
template:`
我最美,{{wt}}
`,
//组件使用的数据
data(){
return {
wt:'确认过眼神,这是真的'
}
}
}
}
});
const vm = new Vue({
el: '#app',
data: {
msg:''
},
components:{
item:{
template:`
我是一个局部的组件:{{chang}}
`,
data(){
return{
chang:'验证通过'
}
}
}
}
})
两中组件的区别
1.全局组件可以在任意的地方使用
2.局部组件只能在所属组件的 模板 中使用
使用组件
组件使用中的细节点:
表单/ul/ol等中指定的标签
产生的原因:在tbody中只能使用tr标签,使用其他的标签,浏览器解析的时候,会把其他标签作为table外部标签解析出去,结构就会发生分离,ul和ol也是如此
使用is解决问题,例如tr标签
//html
//js
Vue.component('chang', {
template: `
常杰
李想
老丁
`
});
使用ref属性获取dom对象
//html
//js
Vue.component('chang', {
template: `
{{current}}
`,
data(){
return{
current:'常杰'
}
},
methods:{
handler(){
// alert('你触发了点击事件');
console.log(this.$refs.hello)
}
}
});
组件通讯:
组件是一个独立且封闭的个体,也就是说:默认情况下,组件只能使用自身的数据,而不能使用外部的数据
但是,在组件化开发过程中,两个组件通讯( 也就是两个组件使用对方法的数据 ),是很常见的问题。
这种问题就需要通过 组件通讯 机制来解决
组件通讯的三种情况:
1 父组件 传递数据给 子组件
2 子组件 传递数据给 父组件
3 非父子组件(兄弟组件)
父 -->子通讯:
父组件: Vue实例
子组件: child组件
步骤:
1 在子组件标签中添加要传递的属性
msg就是要传递的属性
表示传递动态数据给子组件
2 在子组件中通过 props 显示指定要接受的属性
props: ['msg']
3 此时,就可以在子组件中直接使用 msg 这个数据了
Document
父组件:{{ parentMsg }}
子 -->父通讯
·思路:父组件提供一个方法,让子组件调用,子组件调用方法的时候将数据作为参数传递,这样,父组件就拿到子组件中传递过来的数据了
function parent(data) {
console.log('子组件中传递过来的数据:', data)
}
子组件调用方法: parent( '要传递给父组件的数据' )
实现子组件给父组件传值的过程
1.首先给父组件注册一个方法,同时在data设置一个变量准备接收子组件传出的值
2.给子组件的标签上绑定自定义事件,并把方法作为事件函数传入
3.在子组件中设置模板。在模板中设置事件,触发子组件的方法,在子组件的方法中,获取到传入的自定义事件,并且触发这个事件,传递参数
4.子组件触发这个方法,并把数据作为方法的参数传出
5.在父组件中处理触发事件的操作
//html
我儿子给我发的信息:{{msg}}
//js
Vue.component('son',{
// 3.在子组件中设置模板。在模板中设置事件,触发子组件的方法,在子组件的方法中,获取到传入的自定义事件,并且触发这个事件,传递参数
template:`
我要给老爸发信息
`,
// 4.子组件触发这个方法,并把数据作为方法的参数传出
methods:{
send(){
this.$emit('pmsg',"老爸,我资金有点....")
}
}
});
const vm = new Vue({
el: '#app',
data: {
msg:'没啥用,就占个位'
},
// 1.首先给父组件注册一个方法,同时在data设置一个变量准备接收子组件传出的值
methods:{
// 5.在父组件中处理触发事件的操作
fn(data){
this.msg = data
}
}
})
小案例:
计数器实现的步骤
- 1.首先创建一个子组件count
- 2.在组件中创建模板,在模板中绑定事件handler,插入数据num
- 3.在组件中创建模板中调用的方法handler
- 4.在模板中设置数据num
- 5.在组件标签上注册事件change,并绑定handlerChange方法(非常重要)
- 6.在组件标签上添加属性ref为one/two(非常重要)
- 7.在Vue实例中,添加方法handlerChange,并通过this.$refs.绑定的名称获取数据
- 8.获取到子组件的数据进行操作
Document
{{total}}
其他通讯(非父子)
思路:
1 创建一个事件总线(空的Vue实例 bus)
2 哪个组件要接收数据,就注册事件
bus.$on(事件名称, () => {})
3 哪个组件要传递数据,就触发事件
bus.$emit(事件名称, 要传递的数据)
注意: 注册和触发事件的 bus 是同一个,事件名称也要相同
实际上,不管两个组件是什么关系,都可以通过 bus 方式来实现通讯!
步骤:
1.首先创建一个 空的vue实例的对象 bus
2.然后创建两个组件,一个临时用于接收 (wang) ,一个临时用于发送数据 (chang)
3.给两个组件设置好模板内容
4. 组件chang设置方法,在方法中通过bus.$emit获取事件,并设置触发事件的参数
5.在组件wang的钩子函数created中声明创建事件listen,并设置获取到参数后的处理
注意点:虽然用不到vm但是,必须声明创建这个实例,只有指定了vue的边界,代码才能生效
//html
//js
// 空Vue实例
// 事件总线
// 1.首先创建一个 空的vue实例的对象 即事件总线bus
let bus = new Vue();
// 2.然后创建两个组件,一个临时用于接收 (wang) ,一个临时用于发送数据 (chang)
Vue.component('chang',{
// 3.给两个组件设置好模板内容
template:`
我是常杰,我想对王婷说:
`,
// 4. 组件chang设置方法,在方法中通过bus.$emit获取事件,并设置触发事件的参数
methods:{
fn(){
bus.$emit('listen','那天我一直在等你')
}
}
});
Vue.component('wang',{
template:`
我是王婷,常杰对我说:{{msg}}
`,
data(){
return {
msg:'接收信息中,请等待...'
}
},
// 5.在组件wang的钩子函数created中声明创建事件listen,并设置获取到参数后的处理
created(){
bus.$on('listen',data=>{
this.msg = data
})
}
});
//没有用到数据,但是必须声明
const vm = new Vue({
el:"#app",
data:{
}
});
细节补充
props的属性
props:是只读的,在组件中使用的时候,只能读取,不能修改props的值( 赋值
)如果修改这个值,会报错!!!
如果props是一个引用类型的数据,不能直接赋值,但是,可以修改引用类型中某个属性的值。
单向数据流:
是说组件之间数据流动方向是从 父组件流动到 子组件
父组件可以通过 props 将数据传递给子组件,并且,当父组件中的这个数据改变
后,这个改变后的数据会自动的再流动到子组件中。也就是说:子组件会自动接收到最
新的props数据,并且自动更新
总结:
1.props是只读的属性,只能读取props的值,而不能直接修改props的值
如果是引用类型(对象、数组),可以直接修改对象中某个属性的值,但是,如果要求很严谨,也不应该直接修改对象中某个属性的值!!!
2.单项数据流: 两个组件之间的数据流动方向,方向是: 父 -> 子
命名
HTML 标签或属性都是不区分大小写的(大小写不敏感的)
不管你写的是大写字母的标签名或属性名,还是小写的,最终,都会被转化为小写字母
同样的,在 Vue 中,给组件传递属性的时候,如果属性名中包含大写字母,在解析的时候,也会被转化为小写字母,再作为属性传递给组件
如何给props命名:
1 使用纯小写字母
props: ['childmsg']
2 传递属性的时候,使用短横线连接多个单词,在子组件中通过 驼峰命名法 来接收这个数据(规范)
传递(短横线连接)
接收(驼峰命名法) props: ['childMsg']