Vue3中关于组件之间的事件传递和数据共享

事件传递

  1. 子组件向父组件传递事件

    首先在父组件中定义一个用于接收事件的方法handleContentPage:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    <!-- 这是父组件 -->
    <template>
    <div id="parent">
    <!-- 接收子组件的消息 -->
    <Navbar @update-content-page="handleContentPage"/>
    </div>
    </template>


    <script>
    import Navbar from "@admin/views/Navbar.vue";

    export default {
    components: {
    Navbar,
    },
    methods:{
    handleContentPage(page){
    console.log("收到子组件传递过来的消息")
    }
    }
    };
    </script>

    然后在子组件中借助$emit来调用父组件的函数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    <!-- 这是子组件 -->
    <template>
    <div class="navbar">
    <!-- 导航栏 -->
    <nav>
    <ul>
    <li @click="navigateTo('Dashboard')">仪表板</li>
    <li @click="navigateTo('Users')">用户</li>
    <li @click="navigateTo('Settings')">设置</li>
    </ul>
    </nav>
    </div>
    </template>
    <script>

    export default {
    methods: {
    navigateTo(page) {
    console.log("点击了菜单栏");
    //向父组件发送数据
    this.$emit('update-content-page', page);
    }
    },
    };
    </script>

    注意: $emit闯入的第一个参数 update-content-page 需要和父组件中使用@进行一一对应

  2. 父组件向子组件传递事件

    首先在子组件中定义一个供父组件调用的方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <!-- 这是子组件 -->
    <template>
    <div class="content">
    </div>
    </template>
    <script>

    export default {
    methods: {
    //定义一个方法供父组件调用
    updatePage(page) {
    console.log("收到来自父组件的数据"+page);
    }
    },

    }
    }
    </script>

    然后在父组件中通过对象引用的方式调取子组件的方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    <!-- 这是父组件 -->
    <template>
    <div id="parent">
    <button @click="handleContentPage">一键转换</button>

    <!-- 使用 ref 建立子组件的实例引用 方便调子组件方法 -->
    <Content ref="contentRef"/>
    </div>
    </template>
    <script>

    import Content from "@admin/views/Content.vue";

    export default {
    components: {
    Content,
    },
    methods:{
    handleContentPage(page){
    //调取子组件的函数
    this.$refs.contentRef.updatePage(page)
    }
    }
    };
    </script>
  3. 两个不相关的组件进行事件传递

    Vue 3中,可以使用事件总线Event Bus来进行两个不相关的组件之间优雅地通信。

    首先在一个单独的JavaScript模块中创建事件总线:

    1
    2
    import { createApp } from 'vue'
    export const eventBus = createApp({})

    然后在需要发布事件的组件中导入事件总线并发送事件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    import { eventBus } from './event-bus'

    export default {
    methods: {
    sendMessage() {
    eventBus.emit('message-sent', this.message)
    }
    }
    }

    最后,在接收事件的组件中也导入事件总线并监听事件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    import { eventBus } from './event-bus'

    export default {
    created() {
    eventBus.on('message-sent', message => {
    console.log(`Received message: ${message}`)
    })
    }
    }

数据传递

Vue中如果需要进行父子间数据的传递, 可以使用provide/inject来实现

在祖先组件中使用provide来提供数据:

1
2
3
4
5
6
7
8
import { provide } from 'vue'

export default {
setup() {
const name = 'John Doe';
provide('name', name);
}
}

在后代组件中使用inject来获取数据:

1
2
3
4
5
6
7
8
import { inject } from 'vue'

export default {
setup() {
const name = inject('name');
console.log(name); // Output: John Doe
}
}

这样,后代组件就可以通过inject方法访问提供的数据了。

全局数据共享

如果我们需要在所有组件中共享数据, 比如用户的信息 缓存数据等等,

Vue3中,介绍两种方案

第一种 使用一个全局的provide/inject

具体步骤如下:

  1. 在根组件中提供要共享的数据
1
2
3
4
5
6
7
8
9
10
11
12
import { createApp, reactive } from 'vue';

const app = createApp({
setup() {
const sharedState = reactive({ count: 0 });
return {
sharedState,
};
},
});

app.mount('#app');
  1. 在需要使用该数据的子组件中注入它
1
2
3
4
5
6
7
8
9
10
import { inject } from 'vue';

export default {
setup() {
const sharedState = inject('sharedState');
return {
sharedState,
};
},
};
  1. 在子组件中就可以直接使用这个共享的状态了,比如在模板中显示它的值或者修改它的值
1
2
3
4
5
6
<template>
<div>
{{ sharedState.count }}
<button @click="sharedState.count++">增加</button>
</div>
</template>

这样就可以实现一个简单的全局数据共享了。需要注意的是,provide/inject API并不是响应式的,如果需要响应式地共享数据,可以使用reactive或者ref等Vue3提供的响应式API来实现。

使用Vuex

Vue 3 中,可以使用 Vuex 4来实现全局数据共享。

首先需要安装Vuex

1
npm install vuex@next

然后在 main.js 中创建一个 store 实例:

1
2
3
4
5
6
7
import { createApp } from 'vue'
import App from './App.vue'
import store from './store'

const app = createApp(App)
app.use(store)
app.mount('#app')

接着在 src 目录下创建一个 store.js 文件,用于定义 store:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import { createStore } from 'vuex'

const store = createStore({
state() {
return {
count: 0
}
},
mutations: {
increment(state) {
state.count++
}
},
actions: {
increment(context) {
context.commit('increment')
}
},
getters: {
doubleCount(state) {
return state.count * 2
}
}
})

export default store

这里的state 定义了初始状态,mutations 定义了修改状态的方法,actions 定义了异步操作,getters定义了从状态中派生出来的值。

在组件中使用store 的数据和方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<template>
<div>
<p>Count: {{ count }}</p>
<p>Double Count: {{ doubleCount }}</p>
<button @click="increment">Increment</button>
</div>
</template>

<script>
import { computed } from 'vue'
import { useStore } from 'vuex'

export default {
setup() {
const store = useStore()
const count = computed(() => store.state.count)
const doubleCount = computed(() => store.getters.doubleCount)

const increment = () => {
store.dispatch('increment')
}

return {
count,
doubleCount,
increment
}
}
}
</script>

在组件中使用 useStore 获取store 实例,在 setup函数中使用computed函数将 store 中的数据和方法转化为响应式的值,然后在模板中使用即可。

以上是一个简单的示例,具体使用还可以根据实际需求进行修改和扩展。

本文为作者原创转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

0%