props
$emit $on(vue3废弃)
$children(vue3废弃) $parent
$attrs $listeners(vue3废弃)
ref
$root
eventbus
vuex
父组件通过自定义属性给子组件传值,子组件用props接收;
通过组件标签进行方法的传递,子组件$emit触发方法
<template>
<div id="app">
<div>父组件:{{message}}</div>
<ChildrenComponet :message="message" @changeMsgFn="message=$event"/>
</div>
</template>
<script>
import ChildrenComponet from './components/ChildrenComponet.vue'
export default {
name: 'App',
data(){
return{
message:'默认数据'
}
},
components: {
ChildrenComponet
},
methods:{
changeMessage(msg){
this.message = 'Bye';
}
}
}
</script>
子组件
<template>
<div>
子组件:{{message}}
<button @click="handleClick">按钮</button>
</div>
</template>
<script>
export default {
props:['message'],
methods:{
handleClick(){
this.$emit('changeMsgFn','Bye')
}
}
}
</script>
通过 $ parent来获取父组件的实例,从而获取父组件的属性和方法
通过this.$ children得到的是一个子组件实例的数组
<template>
<div id="app">
<div>父组件:{{message}}</div>
<ChildrenComponet :message="message"/>
<button @click="changeChildrenNumber">改变子number</button>
</div>
</template>
<script>
import ChildrenComponet from './components/ChildrenComponet.vue'
export default {
name: 'App',
data(){
return{
message:'默认数据'
}
},
components: {
ChildrenComponet
},
methods:{
changeChildrenNumber(){
this.$children[0].number = 50
}
}
}
</script>
子组件
<template>
<div>
子组件:{{number}}
<button @click="handleClick">按钮</button>
</div>
</template>
<script>
export default {
data(){
return {
number:'初始number'
}
},
props:['message'],
methods:{
handleClick(){
this.$parent[0].message = '测试$parent,我是子组件'
}
}
}
</script>
父组件:
<template>
<div id="app">
<ChildrenComponet/>
</div>
</template>
<script>
import ChildrenComponet from './components/ChildrenComponet.vue'
export default {
name: 'App',
provide:{
message:"hello"
},
components: {
ChildrenComponet
},
}
</script>
子组件
<template>
<div>
子组件:{{message}}
</div>
</template>
<script>
export default {
inject:['message'],
}
</script>
父组件
<template>
<div id="app">
------父组件------
<div>姓名:{{ name }}</div>
<div>年龄:{{ age }}</div>
<ChildrenComponet :name="name" :age="age" @changeName="changeName"/>
</div>
</template>
<script>
import ChildrenComponet from './components/ChildrenComponet.vue'
export default {
name: 'App',
data(){
return{
name:'小米',
age: 33,
}
},
components: {
ChildrenComponet
},
methods:{
changeName(){
this.name = '小夏'
}
}
}
</script>
子组件
<template>
<div>
------子组件------
姓名:{{$attrs.name}}
年龄:{{$attrs.age}}
<button @click="$listeners.changeName">按钮</button>
<GrandChild v-bind="$attrs" />
</div>
</template>
<script>
import GrandChild from './GrandChild.vue'
export default {
components:{
GrandChild
},
}
</script>
孙组件
<template>
<div>
------孙组件------
姓名:{{$attrs.name}}
年龄:{{$attrs.age}}
</div>
</template>
通过ref得到子组件的实例,进而得到子组件的方法和属性
------父组件------
<ChildrenComponet ref="childComp"/>
...
this.$refs.childComp.changeAge()
------子组件------
changeAge(){
this.age = 50
}
//eventBus原理就是利用和emit 并实例化一个全局 vue 实现数据共享
//main.js
Vue.prototype.$bus=new Vue()
//传值组件
this.$bus.$emit('eventTarget','值')
//接收组件
this.$bus.$on('eventTarget',value=> console.log(value))
下载npm install pubsub-js --save
兄弟组件:
childone.vue
...
<button @click="pubsubBrotherMsg">send brother msg by pubsub</button>
...
//script
import PubSub from 'pubsub-js'
methods: {
pubsubBrotherMsg (){
PubSub.subscribe('pubsubMsg',this.commonMsg)
},
}
childtwo.vue
...
import PubSub from 'pubsub-js'
data(){
return {
pubsubMsg:''
}
},
mounted() {
/*msg:回调函数第一个参数,必须传*/
PubSub.subscribe('pubsubMsg',(msg,data) => {
this.pubsubMsg = data
} )
}
...
除此之外,还有mixin,localStorage,sessionStorage等都可以实现。
不可以修改,
组件化开发过程中有个单项数据流原则,不在子组件中修改父组件是个常识问题。
所有的 prop 都使得其父子之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父组件的状态,从而导致你的应用的数据流向难以理解。另外,每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器控制台中发出警告
实际开发过程中有两个场景会想要修改一个属性:
1.这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用。在这种情况下,最好定义一个本地的 data,并将这个 prop 用作其初始值:
const props = defineProps(['initialCounter'])
const counter = ref(props.initialCounter)
2.这个 prop 以一种原始的值传入且需要进行转换。在这种情况下,最好使用这个 prop 的值来定义一个计算属性:
const props = defineProps(['size'])
// prop变化,计算属性自动更新
const normalizedSize = computed(() => props.size.trim().toLowerCase())
3.实践中如果确实想要改变父组件属性应该emit一个事件让父组件去做这个变更。注意虽然我们不能直接修改一个传入的对象或者数组类型的prop,但是我们还是能够直接改内嵌的对象或属性。
< keep-alive > 包裹动态组件时,会被缓存不活动的组件实例,而不是销毁它们。
< keep-alive > 是个抽象组件,它自身不会渲染一个DOM元素,也不会出现在组件的父组件链中。
逻辑扩展: mixins、extends、composition api;
内容扩展: slots;
常见的组件扩展方法有:mixins,slots,extends等
混入mixins是分发 Vue组件中可复用功能的非常灵活的方式。混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项。
插槽slots主要用于vue组件中的内容分发,也可以用于组件扩展。
如果要精确分发到不同位置可以使用具名插槽,如果要使用子组件中的数据可以使用作用域插槽。
混入的数据和方法不能明确判断来源且可能和当前组件内变量产生命名冲突,vue3中引入的composition api,可以很好解决这些问题,利用独立出来的响应式模块可以很方便的编写独立逻辑并提供响应式的数据,然后在setup选项中组合使用,增强代码的可读性和维护性。