Если что-то не так или чего-то не хватает, пожалуйста, поправьте меня. Ваши лайки и комментарии - самая большая мотивация для меня двигаться вперед. Спасибо.
12 способов взаимодействия компонентов Vue2.x будут описаны позже, давайте сначала перейдем к Vue3.
Олли!
Метод связи компонента Vue3
- props
- $emit
- expose / ref
- $attrs
- v-model
- provide / inject
- Vuex
- mitt
Метод записи использования связи Vue3
1. props
Существует два способа передачи данных дочерним компонентам с использованием реквизита:
Способ 1, смешанное написание
// Parent.vue 传送
<child :msg1="msg1" :msg2="msg2"></child>
<script>
import child from "./child.vue"
import { ref, reactive } from "vue"
export default {
data(){
return {
msg1:"这是传级子组件的信息1"
}
},
setup(){
// 创建一个响应式数据
// 写法一 适用于基础类型 ref 还有其他用处,下面章节有介绍
const msg2 = ref("这是传级子组件的信息2")
// 写法二 适用于复杂类型,如数组、对象
const msg2 = reactive(["这是传级子组件的信息2"])
return {
msg2
}
}
}
</script>
// Child.vue 接收
<script>
export default {
props: ["msg1", "msg2"],// 如果这行不写,下面就接收不到
setup(props) {
console.log(props) // { msg1:"这是传给子组件的信息1", msg2:"这是传给子组件的信息2" }
},
}
</script>
Метод 2, чистое написание Vue3 (синтаксический сахар)
// Parent.vue 传送
<child :msg2="msg2"></child>
<script setup>
import child from "./child.vue"
import { ref, reactive } from "vue"
const msg2 = ref("这是传给子组件的信息2")
// 或者复杂类型
const msg2 = reactive(["这是传级子组件的信息2"])
</script>
// Child.vue 接收
<script setup>
// 不需要引入 直接使用
// import { defineProps } from "vue"
const props = defineProps({
// 写法一
msg2: String
// 写法二
msg2:{
type:String,
default:""
}
})
console.log(props) // { msg2:"这是传级子组件的信息2" }
</script>
Уведомление:
Если родительский компонент написан смешанным образом, а дочерний компонент написан на чистом Vue3, он не может получить свойства данных в родительском компоненте, а может получить только свойства, переданные в функции настройки родительского компонента.
Если родительский компонент написан на чистом Vue3, а дочерний компонент написан на смешанном, то можно получить свойства в data и setup функции через пропсы, но если дочерний компонент получает в setup, то он может только получить свойства в функции настройки в родительском компоненте.атрибут не в данных
Чиновник также сказал, что, поскольку используется 3, не пишите 2, поэтому смешанное написание не рекомендуется. В следующих примерах используется только чистый метод записи Vue3, а смешанный метод записи не используется.
2. $emit
// Child.vue 派发
<template>
// 写法一
<button @click="emit('myClick')">按钮</buttom>
// 写法二
<button @click="handleClick">按钮</buttom>
</template>
<script setup>
// 方法一 适用于Vue3.2版本 不需要引入
// import { defineEmits } from "vue"
// 对应写法一
const emit = defineEmits(["myClick","myClick2"])
// 对应写法二
const handleClick = ()=>{
emit("myClick", "这是发送给父组件的信息")
}
// 方法二 不适用于 Vue3.2版本,该版本 useContext()已废弃
import { useContext } from "vue"
const { emit } = useContext()
const handleClick = ()=>{
emit("myClick", "这是发送给父组件的信息")
}
</script>
// Parent.vue 响应
<template>
<child @myClick="onMyClick"></child>
</template>
<script setup>
import child from "./child.vue"
const onMyClick = (msg) => {
console.log(msg) // 这是父组件收到的信息
}
</script>
3. expose / 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>
4. attrs
attrs
: содержит нереквизиты, кроме класса и стиля в родительской областисбор имущества
// Parent.vue 传送
<child :msg1="msg1" :msg2="msg2" title="3333"></child>
<script setup>
import child from "./child.vue"
import { ref, reactive } from "vue"
const msg1 = ref("1111")
const msg2 = ref("2222")
</script>
// Child.vue 接收
<script setup>
import { defineProps, useContext, useAttrs } from "vue"
// 3.2版本不需要引入 defineProps,直接用
const props = defineProps({
msg1: String
})
// 方法一 不适用于 Vue3.2版本,该版本 useContext()已废弃
const ctx = useContext()
// 如果没有用 props 接收 msg1 的话就是 { msg1: "1111", msg2:"2222", title: "3333" }
console.log(ctx.attrs) // { msg2:"2222", title: "3333" }
// 方法二 适用于 Vue3.2版本
const attrs = useAttrs()
console.log(attrs) // { msg2:"2222", title: "3333" }
</script>
5. v-model
Может поддерживать двустороннюю привязку нескольких данных
// Parent.vue
<child v-model:key="key" v-model:value="value"></child>
<script setup>
import child from "./child.vue"
import { ref, reactive } from "vue"
const key = ref("1111")
const value = ref("2222")
</script>
// Child.vue
<template>
<button @click="handlerClick">按钮</button>
</template>
<script setup>
// 方法一 不适用于 Vue3.2版本,该版本 useContext()已废弃
import { useContext } from "vue"
const { emit } = useContext()
// 方法二 适用于 Vue3.2版本,不需要引入
// import { defineEmits } from "vue"
const emit = defineEmits(["key","value"])
// 用法
const handlerClick = () => {
emit("update:key", "新的key")
emit("update:value", "新的value")
}
</script>
6. provide / inject
обеспечить/внедрить для внедрения зависимостей
provide
: позволяет нам указать данные, которые мы хотим предоставить дочерним компонентам или
inject
: Получите данные, которые вы хотите добавить к этому компоненту, в любом компоненте-потомке, независимо от того, насколько глубоко вложен компонент, его можно использовать напрямую.
// Parent.vue
<script setup>
import { provide } from "vue"
provide("name", "沐华")
</script>
// Child.vue
<script setup>
import { inject } from "vue"
const name = inject("name")
console.log(name) // 沐华
</script>
7. Vuex
// 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>
8. mitt
В Vue3 нет межкомпонентной связи EventBus, но теперь есть альтернативное решение mitt.js, принцип по-прежнему EventBus
Установить первымnpm i mitt -S
Затем инкапсулируйте его, как вы это делали до инкапсуляции шины.
mitt.js
import mitt from 'mitt'
const mitt = mitt()
export default mitt
Тогда использование связи между двумя компонентами
// 组件 A
<script setup>
import mitt from './mitt'
const handleClick = () => {
mitt.emit('handleChange')
}
</script>
// 组件 B
<script setup>
import mitt from './mitt'
import { onUnmounted } from 'vue'
const someMethed = () => { ... }
mitt.on('handleChange',someMethed)
onUnmounted(()=>{
mitt.off('handleChange',someMethed)
})
</script>
Метод связи компонента Vue2.x
Существует 12 типов взаимодействия компонентов Vue2.x.
- props
- $emit / v-on
- .sync
- v-model
- ref
- $children / $parent
- $attrs / $listeners
- provide / inject
- EventBus
- Vuex
- $root
- slot
Связь между родительскими и дочерними компонентами может использоваться:
- props
- $emit / v-on
- $attrs / $listeners
- ref
- .sync
- v-model
- $children / $parent
Связь компонентов родственного компонента может использоваться:
- EventBus
- Vuex
- $parent
Взаимодействие между компонентами может быть выполнено с использованием:
- provide/inject
- EventBus
- Vuex
- $attrs / $listeners
- $root
Метод записи использования связи Vue2.x
Ниже приведен список методов записи для каждого метода связи компонентов.
1. props
Родительский компонент передает данные дочернему компоненту, это должно быть наиболее распространенным способом
После того, как дочерний компонент получит данные,не может быть изменено напрямуюДанные родительского компонента. Будет сообщено об ошибке, поэтому при повторном рендеринге родительского компонента данные будут перезаписаны. Если вы хотите изменить подкомпонент, рекомендуется использовать вычисляемый
// Parent.vue 传送
<template>
<child :msg="msg"></child>
</template>
// Child.vue 接收
export default {
// 写法一 用数组接收
props:['msg'],
// 写法二 用对象接收,可以限定接收的数据类型、设置默认值、验证等
props:{
msg:{
type:String,
default:'这是默认数据'
}
},
mounted(){
console.log(this.msg)
},
}
2. .sync
Это может помочь нам реализовать двустороннюю привязку данных, передаваемых от родительского компонента к дочернему, поэтому после того, как дочерний компонент получит данныеможно напрямую модифицировать, и одновременно изменит данные родительского компонента
// Parent.vue
<template>
<child :page.sync="page"></child>
</template>
<script>
export default {
data(){
return {
page:1
}
}
}
// Child.vue
export default {
props:["page"],
computed(){
// 当我们在子组件里修改 currentPage 时,父组件的 page 也会随之改变
currentPage {
get(){
return this.page
},
set(newVal){
this.$emit("update:page", newVal)
}
}
}
}
</script>
3. v-model
Подобно .sync, данные, передаваемые из родительского компонента в дочерний, могут быть двусторонними, а дочерний компонент может изменять данные родительского компонента через $emit.
// Parent.vue
<template>
<child v-model="value"></child>
</template>
<script>
export default {
data(){
return {
value:1
}
}
}
// Child.vue
<template>
<input :value="value" @input="handlerChange">
</template>
export default {
props:["value"],
// 可以修改事件名,默认为 input
model:{
event:"updateValue"
},
methods:{
handlerChange(e){
this.$emit("input", e.target.value)
// 如果有上面的重命名就是这样
this.$emit("updateValue", e.target.value)
}
}
}
</script>
4. ref
ref Если это обычный элемент DOM, ссылка указывает на элемент DOM;
Если на дочернем компоненте ссылка указывает на экземпляр дочернего компонента, то родительский компонент может активно получать свойства дочернего компонента или вызывать метод дочернего компонента через ref
// Child.vue
export default {
data(){
return {
name:"沐华"
}
},
methods:{
someMethod(msg){
console.log(msg)
}
}
}
// Parent.vue
<template>
<child ref="child"></child>
</template>
<script>
export default {
mounted(){
const child = this.$refs.child
console.log(child.name) // 沐华
child.someMethod("调用了子组件的方法")
}
}
</script>
5. $emit / v-on
Дочерний компонент отправляет данные родительскому компоненту, отправляя события, или инициирует такие операции, как обновление родительского компонента.
// Child.vue 派发
export default {
data(){
return { msg: "这是发给父组件的信息" }
},
methods: {
handleClick(){
this.$emit("sendMsg",this.msg)
}
},
}
// Parent.vue 响应
<template>
<child v-on:sendMsg="getChildMsg"></child>
// 或 简写
<child @sendMsg="getChildMsg"></child>
</template>
export default {
methods:{
getChildMsg(msg){
console.log(msg) // 这是父组件接收到的消息
}
}
}
6. $attrs / $listeners
Когда несколько вложенных компонентов передают данные, это можно использовать, если передаются только данные без промежуточной обработки, например, когда родительские компоненты передают данные дочерним компонентам.
$attrs
: содержит нереквизиты, кроме класса и стиля в родительской областисбор имущества. Получите весь набор квалифицированных атрибутов в родительской области через this.$attrs, а затем продолжите передавать его другим компонентам внутри дочернего компонента, вы можете передать v-bind="$attrs"
$listeners
: содержит прослушиватели, кроме .native в родительской области.коллекция событий. Если вы хотите продолжить передачу другим компонентам внутри подкомпонента, вы можете передать v-on="$linteners"
использование такое же
// Parent.vue
<template>
<child :name="name" title="1111" ></child>
</template
export default{
data(){
return {
name:"沐华"
}
}
}
// Child.vue
<template>
// 继续传给孙子组件
<sun-child v-bind="$attrs"></sun-child>
</template>
export default{
props:["name"], // 这里可以接收,也可以不接收
mounted(){
// 如果props接收了name 就是 { title:1111 },否则就是{ name:"沐华", title:1111 }
console.log(this.$attrs)
}
}
7. $children / $parent
$children
: получить массив объектов VueComponent, содержащий все дочерние компоненты (за исключением внучатых компонентов), вы можете напрямую получить все данные и методы в дочерних компонентах и т. д.
$parent
: получить объект VueComponent родительского узла, который также содержит все данные и методы родительского узла и т. д.
// Parent.vue
export default{
mounted(){
this.$children[0].someMethod() // 调用第一个子组件的方法
this.$children[0].name // 获取第一个子组件中的属性
}
}
// Child.vue
export default{
mounted(){
this.$parent.someMethod() // 调用父组件的方法
this.$parent.name // 获取父组件中的属性
}
}
8. provide / inject
Provide/inject — это внедрение зависимостей, его не рекомендуется использовать непосредственно в коде приложения, но он обычно используется в некоторых плагинах или библиотеках компонентов, поэтому я думаю, что это бесполезно, это довольно полезно
provide
: позволяет нам указать данные или методы, которые мы хотим предоставить компонентам-потомкам
inject
: Получите данные или методы, которые вы хотите добавить к этому компоненту, в любом компоненте-потомке, независимо от того, насколько глубоко вложен компонент, его можно использовать напрямую.
Следует отметить, что данные, переданные с помощью Provide и Inject, не реагируют, то есть после получения данных с помощью Inject данные в обеспечении изменяются, а данные в компонентах-потомках не изменятся, если только входящие не будут изменены. контролируемый объект
Поэтому рекомендуется передавать некоторые константы или методы
// 父组件
export default{
// 方法一 不能获取 methods 中的方法
provide:{
name:"沐华",
age: this.data中的属性
},
// 方法二 不能获取 data 中的属性
provide(){
return {
name:"沐华",
someMethod:this.someMethod // methods 中的方法
}
},
methods:{
someMethod(){
console.log("这是注入的方法")
}
}
}
// 后代组件
export default{
inject:["name","someMethod"],
mounted(){
console.log(this.name)
this.someMethod()
}
}
9. EventBus
EventBus — это центральная шина событий, которую могут использовать родительско-дочерние компоненты, одноуровневые компоненты, межуровневые компоненты и т. д. для выполнения коммуникационных операций.
Есть три способа определить
// 方法一
// 抽离成一个单独的 js 文件 Bus.js ,然后在需要的地方引入
// Bus.js
import Vue from "vue"
export default new Vue()
// 方法二 直接挂载到全局
// main.js
import Vue from "vue"
Vue.prototype.$bus = new Vue()
// 方法三 注入到 Vue 根对象上
// main.js
import Vue from "vue"
new Vue({
el:"#app",
data:{
Bus: new Vue()
}
})
Использование заключается в следующем, взяв метод 1 в качестве примера, чтобы ввести по запросу
// 在需要向外部发送自定义事件的组件内
<template>
<button @click="handlerClick">按钮</button>
</template>
import Bus from "./Bus.js"
export default{
methods:{
handlerClick(){
// 自定义事件名 sendMsg
Bus.$emit("sendMsg", "这是要向外部发送的数据")
}
}
}
// 在需要接收外部事件的组件内
import Bus from "./Bus.js"
export default{
mounted(){
// 监听事件的触发
Bus.$on("sendMsg", data => {
console.log("这是接收到的数据:", data)
})
},
beforeDestroy(){
// 取消监听
Bus.$off("sendMsg")
}
}
10. Vuex
Vuex — это менеджер состояний, который централизованно хранит и управляет состоянием всех компонентов. Этот фрагмент контента слишком длинный, если вы не знакомы с основами, вы можете прочитать этоVuex, а затем примерно используется следующим образом
Например, создайте файловую структуру, подобную этой
Содержимое index.js следующее
import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
import actions from './actions'
import mutations from './mutations'
import state from './state'
import user from './modules/user'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
user
},
getters,
actions,
mutations,
state
})
export default store
Затем импортируйте его в main.js
import Vue from "vue"
import store from "./store"
new Vue({
el:"#app",
store,
render: h => h(App)
})
Затем в требуемом компоненте
import { mapGetters, mapMutations } from "vuex"
export default{
computed:{
// 方式一 然后通过 this.属性名就可以用了
...mapGetters(["引入getters.js里属性1","属性2"])
// 方式二
...mapGetters("user", ["user模块里的属性1","属性2"])
},
methods:{
// 方式一 然后通过 this.属性名就可以用了
...mapMutations(["引入mutations.js里的方法1","方法2"])
// 方式二
...mapMutations("user",["引入user模块里的方法1","方法2"])
}
}
// 或者也可以这样获取
this.$store.state.xxx
this.$store.state.user.xxx
11. $root
$root
Вы можете получить данные и методы в App.vue
12. slot
Это передать данные дочернего компонента родительскому компоненту через слот, а затем вставить его обратно
// Child.vue
<template>
<div>
<slot :user="user"></slot>
</div>
</template>
export default{
data(){
return {
user:{ name:"沐华" }
}
}
}
// Parent.vue
<template>
<div>
<child v-slot="slotProps">
{{ slotProps.user.name }}
</child>
</div>
</template>
Эпилог
Писать нелегко, ваши лайки и комментарии — самая большая мотивация для меня двигаться вперед.