Vue 组件化
组件是可复用的 Vue 实例
- 组件的目的是为了复用
- 组件与
new Vue()接收相同的选项,例如data、computed、watch、methods以及生命周期钩子等 (仅有的例外是像el这样根实例特有的选项。 )
组件间通信
1.父组件-->子组件
- 通过
Props向子组件传递数据(常用)
// 子组件注册 prop
export default {
name: 'HelloWorld',
props: {
msg: String
}
}
// 父组件把数据作为一个自定义attribute传递进来
<hello-World msg="Welcome to Your Vue.js App"/>
- $refs(常用)
<!-- 父组件 -->
<template>
<hello-World msg="Welcome to Your Vue.js App" ref="hw"/>
</template>
<script>
// 得到子组件
mounted() {
this.$refs.hw
}
</script>
- $children(不常用,导致组件间耦合性太高)
<!-- 父组件 -->
<template>
<hello-World msg="Welcome to Your Vue.js App"/>
</template>
<script>
mounted() {
// 得到第一个子组件
this.$children[0]
}
</script>
当前实例的直接子组件。需要注意 $children 并不保证顺序,也不是响应式的
2.子组件-->父组件
- 自定义事件(常用)
// 子组件调用内建的 $emit 方法触发事件
<button @click="$emit('custom-event')">click</button>
<button @click="$emit('custom-event', 'hello')">click</button>
// 父级组件可以像处理 native DOM 事件一样, 监听子组件实例的任意事件
<hello-World msg="Welcome to Your Vue.js App" @custom-event="handleEvent"/>
// 自定义事件传过来的值
handleEvent(msg){
console.log('父组件', msg);
}
3.兄弟组件
- 通过共同祖辈组件
$parent或$root(不常用,导致组件间耦合性太高)
<!-- child1 -->
<template>
<button @click="handleClick">click</button>
</template>
<script>
export default {
name: "Child1",
methods: {
handleClick() {
this.$parent.$emit("msg-from-child1", "hello");
}
}
};
</script>
<!-- child2 -->
<script>
created() {
this.$parent.$on("msg-from-child1", msg => {
console.log(msg);
});
}
</script>
4.祖先和后代之间
provide/inject
// 祖先
provide: {
foo: "bar"
}
// 后代
inject: ["foo"]
provide 和 inject 主要在开发高阶插件/组件库时使用。并不推荐用于普通应用程序代码中。
5.任意两个组件间的通信
- 事件总线(常用)
class Bus {
constructor() {
this.callbacks = {};
}
$on(name, fn) {
this.callbacks[name] = this.callbacks[name] || [];
this.callbacks[name].push(fn);
}
$emit(name, args) {
if (this.callbacks[name]) {
this.callbacks[name].forEach(cb => cb(args));
}
}
}
Vue.prototype.$bus = new Bus();
//或者
Vue.prototype.$bus = new Vue();
Vuex(常用)
插槽slot
作用分发内容
1.匿名插槽
<!-- CustomButton.vue -->
<!-- 子组件 -->
<button type="submit">
<!-- 匿名插槽 -->
<slot></slot>
<!-- 后备内容 -->
<!-- <slot>Submit</slot>-->
</button>
<!-- 父组件 -->
<custom-button>save</custom-button>
2.具名插槽
<!-- CustomCard.vue -->
<!-- 子组件 -->
<template>
<div>
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
<!-- 父组件 -->
<custom-card>
<template v-slot:header>
<h1>header插槽的内容</h1>
</template>
<template>
<p>默认slot的内容</p>
</template>
<template v-slot:footer>
<div>footer插槽的内容</div>
</template>
</custom-card>
3.作用域插槽
父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。
有时让插槽内容能够访问子组件中才有的数据是很有用的
<!-- SlotComp.vue -->
<!-- 子组件 -->
<div>
<slot :user="user"></slot>
</div>
<!-- 父组件 -->
<slot-comp v-slot="slotProps">{{slotProps.user}}</slot-comp>
<slot-comp v-slot="{user}">{{user}}</slot-comp>