组件是什么?
在 Vue 里,一个组件本质上是一个拥有预定义选项并且可复用的 Vue 实例。它提供了一种抽象,让我们可以使用独立可复用的小组件来构建大型应用,任意类型的应用界面都可以抽象为一个组件树。官网图:
组件的注册
- 全局注册组件
Vue.component(组件的名字, 组件的配置)
- 局部注册组件
Vue实例中有一个components选项可以注册局部组件,注册后该组件就是这个Vue实例的子组件,也就是局部组件。
Vue.component(父组件的名字, {
components: {
yh-button: {//y-button 是子组件的名字
key:value //组件的配置项
}
}
})
组件的调用
将组件名当成自定义标签使用即可,可以复用多次, 只写一个的话需要用 / 闭合
<div id="app">
<!-- 这是调用组件-->
<yh-button></yh-button>
<yh-button></yh-button>
<yh-button />
</div>
<script>
new Vue({
el: "app"
})
//这是注册组件
Vue.component('yh-button',{
template:`
<button>按钮</button>
`
}
<script>
组件的注意事项
- 全局注册组件时,必须要放置在 new Vue 之前
- 组件的配置没有 el 选项,因为后续调用组件在哪里,这个组件的挂载点就是哪里。
- 必须有 template 或者 render 选项,用来规定组件的模板内容。
- 组件的template模板只能有一个根元素,多个根元素会导致无法构成一颗树。
- data 选项必须是一个函数返回对象的形式,防止调用多次造成全局污染。
Vue.component('yh-button',{
template:`
<button>按钮</button>
`,
data () {
return {
key:value //数据
}
}
}
- 组件名不能是现有的html标签名,也不能是其他已经注册过的组件名。
- 组件名可以使用短横线写法与驼峰写法,但是调用组件时需要使用短横线写法。下列三种情况时例外:
- 写在 template 选项中
- 写在 里面的
- 写在.vue 后缀的单文件组件中
组件之间的通信方式
要了解组件的通信方式前先了解props选项
在不了解组件之前我们要考虑数据应该放在 data 中还是 computed 中,但是了解组件之后,组件的数据
就要考虑应该是 data 还是 props 还是 computed。prop 就是 props 中的具体一个参数,任何值都可以传递给任何 props中的prop,当一个值传递给一个 prop 属性的时候,它就变成了那个组件实例的一个属性。如果将组件看成是一个函数,那 props 就是这个函数接收到的参数集合。
示例:组件定义时如何设置形参,就是设置 props 选项
<div id="app">
</div>
<script>
Vue.component("hello", {
props: ["name", "age", "sex"],
template: `
<div>
<p>hello, 我的名字是 {{ name }} 我的年龄是 {{ age }} 我的性别是 {{ sex }}</p>
</div>
`,
});
let vm = new Vue({
el: "#app",
template: `
<div id="app">
<hello name="张三" age="18"></hello>
<hello name="李四" age="18" sex="男"></hello>
<hello name="王五" age="18" sex="男"></hello>
</div>
`,
});
</script>
props也可以写成对象的形式,这种写法可以prop校验
//prop校验
props: {
// key 是prop {} 配置校验
key: {
type: String, //type是类型也可以写出数组[String, Number]
default: 'default',//default是默认项
required: true //true 为必填
// 自定义验证函数
validator: function (value) {
// value 是 当前的 prop
return /^张三$/.test(value) //这里 return 布尔值 一般可以做大小、正则之类的一些判断
}
}
}
单向数据流
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
root ->prop-> hello √
hello ->prop-> root ×
父子组件通信
直接使用 prop 传递数据给子组件即可
<div id="app">
<parent></parent>
</div>
<script>
Vue.component("parent", {
data() {
return {
son1Name: "张一",
son2Name: "张二",
son3Name: "张三",
};
},
template: `
<div>
<son :name="son1Name"></son>
<son :name="son2Name"></son>
<son :name="son3Name"></son>
</div>
`,
});
Vue.component("son", {
props: {
name: {
type: String,
required: true,
}
},
template: `
<div>
<p>我是儿子,我的名字是 {{ name }} ,父亲取的</p>
</div>
`,
});
let vm = new Vue({
el: "#app",
});
</script>
子父组件通信
- 子组件不能直接去修改 prop 数据。
- 子组件通过 $emit(自定义事件名字,数据) 去触发一个自定义事件。
- 父组件在调用子组件时,监听这个自定义事件 。<son @事件名字=“事件处理函数”>
- 父组件收到之后再去决定修改。(父组件修改自己的data中的数据是没有任何问题的)
<div id="app">
<parent></parent>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script>
Vue.component('son',{
template: `
<button @click="fn1">按钮</button>
`,
methods: {
// 自定义事件处理函数, event 是触发这个事件时,传递过来的 payload
fn1(event) {
this.$emit('hello', event)
}
}
})
Vue.component('parent',{
template: `
<div>
<son @hello="fn2"></son>
</div>
`,
methods: {
fn2(payload) {
console.log(123)
console.log(payload)
}
}
})
new Vue({
el: '#app'
})
</script>
兄弟组件之间的通信
-
最简单粗暴的方式:找他们的爹
使用$emit: 子组件1 -> 通知 -> root -> prop -> 子组件2 -
推荐,中央事件管理器(中央事件总线)
-
适用于: 亲兄弟之间或者关系特别复杂的组件之间
-
先创建一个空的vue实例对象。也就是不需要额外配置什么选项。(后期可使用vuex)
const bus = new Vue()
A B 两个组件,A 通信 B
先在 B 组件的 created 中去通过 bus 来监听一个自定义事件
bus.$on(eventName, callback)
eventName 要监听的事件的名字
callback 事件触发时的一个回调函数
payload 事件触发时传递过来的 payload 参数在 A 组件的某个时候去触发自定义事件
bus.$emit(eventName, payload)
eventName 要触发的事件的名字
payload 触发事件时传递过去的参数
-
<div id="app">
<son1></son1>
<son2></son2>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script>
let bus = new Vue()
//子组件1
Vue.component('son1',{
data () {
return {
num: 1
}
},
template: `
<button @click="fn1">按钮</button>
`,
methods: {
fn1() {
this.num++
bus.$emit('hello', this.num )
}
}
})
//子组件2
Vue.component('son2', {
data () {
return {
num: 1,
}
},
template: `
<div>
{{ num }}
</div>
`,
created () {
bus.$on('hello', (num) => {
this.num = num
})
}
})
new Vue({
el: '#app'
})
</script>
点击前
点击后
结尾
如果文章中有什么不足或者错误的地方欢迎大家留言分享。如果我的文章能帮到你的话那就给我个点赞和关注,谢谢朋友们的支持。