一.组件间传值
1.eventbus
// bus.js
import Vue from 'vue'
export default new Vue({})
// component-a.js
import bus from './bus.js'
export default {
created () {
bus.$on('event-name', (preload) => {
// ...
})
}
}
// component-b.js
import bus from './bus.js'
export default {
created () {
bus.$emit('event-name', preload)
}
}
- 优点
- 解决了多层组件之间繁琐的事件传播。
- 使用原理十分简单,代码量少。
- 缺点
- 由于是都使用一个Vue实例,所以容易出现重复触发的情景,例如:
- 多人开发时,A、B两个人定义了同一个事件名。
- 两个页面都定义了同一个事件名,并且没有用$off销毁(常出现在路由切换时)。
- 在for出来的组件里注册。
- 由于是都使用一个Vue实例,所以容易出现重复触发的情景,例如:
2.props和$emit/$on
-
优点
- 使用最为简单,也是父子组件传递最常见的方法。
- Vue为给props提供了类型检查支持。
- $emit不会修改到别的组件的同名事件,因为他只能触发父级的事件,这里和event-bus不同
-
缺点
- 单一组件层级一深需要逐层传递,会有很多不必要的代码量。
- 不能解决了多组件依赖统同一状态的问题。
<template>
<div>
父组件:
<input type="text" v-model="name">
<br>
<br>
<!-- 引入子组件 -->
<child :inputName="name"></child>
</div>
</template>
<script>
import child from './child'
export default {
components: {
child
},
data () {
return {
name: ''
}
}
}
</script>
<template>
<div>
子组件:
<span>{{inputName}}</span>
</div>
</template>
<script>
export default {
// 接受父组件的值
props: {
inputName: String,
required: true
}
}
</script>
3.slot传值
- 优点
- 可以在父组件里自定义插入到子组件里的内容,虽然其他属性也可以,但是我觉得slot更倾向于自定义的条件是来自于父容器中。
- 复用性好,适合做组件开发。
- 缺点
- 和props一样不支持跨层级传递。
<swiper class="swiper" :options="swiperOption" id="cateCard">
<swiper-slide v-for="(category, index) in categories" :key="index">
<slot name="items" :category="category.newsList"></slot>
</swiper-slide>
<div class="swiper-pagination" slot="pagination"></div>
</swiper>
<m-list-card icon="caidan" title="新闻资讯" :categories="newsCates">
<template #items="{ category }">
<div
class="swiper-centent mt-3 d-flex"
v-for="(item, index) in category"
:key="index"
>
<sapn>[{{ item.categories }}]</sapn>
<sapn class="mx-2">|</sapn>
<sapn class="flex-grow-1">{{ item.title }}</sapn>
<sapn>{{ item.date }}</sapn>
</div>
</template>
</m-list-card>
4.ref
也是父子间传值
// Child.vue
<script setup>
// 方法一 不适用于Vue3.2版本,该版本 useContext()已废弃
import { useContext } from "vue"
const ctx = useContext()
// 对外暴露属性方法等都可以
ctx.expose({
childName: "这是子组件的属性",
someMethod(){
console.log("这是子组件的方法")
}
})
// 方法二 适用于Vue3.2版本, 不需要引入
// import { defineExpose } from "vue"
defineExpose({
childName: "这是子组件的属性",
someMethod(){
console.log("这是子组件的方法")
}
})
</script>
// Parent.vue 注意 ref="comp"
<template>
<child ref="comp"></child>
<button @click="handlerClick">按钮</button>
</template>
<script setup>
import child from "./child.vue"
import { ref } from "vue"
const comp = ref(null)
const handlerClick = () => {
console.log(comp.value.childName) // 获取子组件对外暴露的属性
comp.value.someMethod() // 调用子组件对外暴露的方法
}
</script>
5.vueX
- 优点
- 解决了多层组件之间繁琐的事件传播。
- 解决了多组件依赖统同一状态的问题。
- 单向数据流
- 为Vue量身定做,学习成本不高
- 缺点
- 不能做数据持久化,刷新页面就要重制,要做数据持久化可以考虑使用localstorage。
- 增加额外的代码体积,简单的业务场景不建议使用。
// store/index.js
import { createStore } from "vuex"
export default createStore({
state:{ count: 1 },
getters:{
getCount: state => state.count
},
mutations:{
add(state){
state.count++
}
}
})
// main.js
import { createApp } from "vue"
import App from "./App.vue"
import store from "./store"
createApp(App).use(store).mount("#app")
// Page.vue
// 方法一 直接使用
<template>
<div>{{ $store.state.count }}</div>
<button @click="$store.commit('add')">按钮</button>
</template>
// 方法二 获取
<script setup>
import { useStore, computed } from "vuex"
const store = useStore()
console.log(store.state.count) // 1
const count = computed(()=>store.state.count) // 响应式,会随着vuex数据改变而改变
console.log(count) // 1
</script>