In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-22 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/01 Report--
This article focuses on "how to communicate between Vue3 components". Interested friends may wish to have a look at it. The method introduced in this paper is simple, fast and practical. Now let the editor take you to learn how to communicate between Vue3 components.
This article explains the basic use of various communication methods of Vue 3.2 components, and uses a single file component.
As we all know, a very important knowledge point in Vue.js is component communication. Whether it is business class development or component library development, there are their own communication methods.
This article is suitable for:
Readers with Vue 3 basics.
Readers who intend to develop a component library.
The knowledge points that will be covered in this article:
Props
Emits
Expose / ref
Non-Props
V-model
Slot slot
Provide / inject
Bus bus
GetCurrentInstance
Vuex
Pinia
Mitt.js
I will write a simple demo for all the knowledge points listed above. The purpose of this article is to let you know that these methods can be used, so we will not dig into every knowledge point.
Readers are advised to type the code once after this article, and then dig deep into each knowledge point according to the links given in this article.
The collection is your own!
Props
The parent component passes the value to the child component (abbreviated as: parent to child)
Props document
Https://v3.cn.vuejs.org/guide/component-props.html
Parent component
/ / Parent.vue import Child from'. / components/Child.vue' / / Import subcomponent let message = 'Thunder Monkey'
Sub-component
/ / Child.vue {{msg}} const props = defineProps ({msg: {type: String, default:''}}) console.log (props.msg) / / you need to use props.xxx in js. Props is not required for use in html
You must use defineProps API to declare props in, which has complete inference and is directly available in.
Please see the documentation for more details.
Https://v3.cn.vuejs.org/api/sfc-script-setup.html#defineprops-%E5%92%8C-defineemits
In, defineProps does not need to be introduced separately.
Props can actually do a lot of things, such as: setting the default value default, type verification type, required required, custom verification function validator, and so on.
You can go to the official website to have a look, this is the knowledge point that must be mastered!
Props document
Https://v3.cn.vuejs.org/guide/component-props.html
Emits
The child component notifies the parent component to trigger an event and can pass a value to the parent component. (abbreviated as: the son passes from the father)
Emits document
Https://v3.cn.vuejs.org/guide/migration/emits-option.html
Parent component
/ / Parent.vue parent component: {{message}} import {ref} from 'vue'import Child from'. / components/Child.vue'let message = ref ('Thunder Monkey') / / change the value of message. Data is the function changeMessage (data) {message.value = data} passed from the child component.
Sub-component
/ / Child.vue child component: the child component's button / / registers a custom event name and tells the parent component what event to trigger when it is passed up. Const emit = defineEmits (['changeMsg']) function handleClick () {/ / Parameter 1: event name / / Parameter 2: value passed to the parent component emit (' changeMsg', 'Shark Pepper')}
As with props, you must use defineEmits API to declare emits in, which has complete inference and is directly available in.
Please see the documentation for more details.
Https://v3.cn.vuejs.org/api/sfc-script-setup.html#defineprops-%E5%92%8C-defineemits
In, defineEmits does not need to be introduced separately.
Expose / ref
Subcomponents can expose their own methods and data through expose.
The parent component gets the child component through ref and calls its methods or accesses data.
Expose document
Https://v3.cn.vuejs.org/api/options-data.html#expose
Speak with examples
Parent component
/ / Parent.vue parent component: get the message data of the child component: {{msg}} the method of calling the child component import {ref, onMounted} from 'vue'import Child from'. / components/Child.vue'const com = ref (null) / / bind the child component const msg = ref ('') onMounted (() = > {/ / after loading is complete) through the template ref Assign the message of the subcomponent to msg msg.value = com.value.message}) function callChildFn () {/ / call the changeMessage method com.value.changeMessage ('garlic son of a bitch') / / re-assign the message of the subcomponent to msg msg.value = com.value.message}
Sub-component
/ Child.vue subcomponent: {{message}} import {ref} from 'vue'const message = ref (' cockroach bully') function changeMessage (data) {message.value = data} use defineExpose to expose specified data and method defineExpose ({message, changeMessage})
In, defineExpose does not need to be introduced separately.
Expose document
Https://v3.cn.vuejs.org/api/options-data.html#expose
DefineExpose document
Https://v3.cn.vuejs.org/api/sfc-script-setup.html#defineexpose
Non-Props
The so-called Non-Props is a non-Prop Attribute.
It means that in subcomponents, instead of using attribute defined by prop or emits, it can be accessed through $attrs.
The common ones are class, style and id.
Or give an example to make a straight point of view.
The case of a single root element
Parent component
/ / Parent.vue import {ref} from 'vue'import Child from'. / components/Child.vue'
Sub-component
/ / Child.vue sub-component: open the console to have a look
Open the console and you can see that the attribute is attached to the HTML element.
The case of multiple elements
In Vue3, however, components no longer dictate that there is only one root element. If the subcomponent is multiple elements, the above example does not work.
/ / Child.vue subcomponents: open the console to see the subcomponents: open the console to have a look
At this point, you can use $attrs to bind.
/ / Child.vue bind only the specified value is fully bound
V-model
V-model is a grammatical sugar of Vue. There are more ways to play in Vue3.
The case of a single value
V-model on the component uses modelValue as the prop and update:modelValue as the event.
V-model parameter document
Https://v3.cn.vuejs.org/guide/component-custom-events.html#v-model-%E5%8F%82%E6%95%B0
Parent component
/ / Parent.vue import {ref} from 'vue'import Child from'. / components/Child.vue'const message = ref (Thunder Monkey)
Sub-component
/ / Child.vue {{modelValue}} import {ref} from 'vue'// receives const props = defineProps ([' modelValue' / / receives the value passed in by the parent component using v-model Must be received with the name modelValue]) const emit = defineEmits (['update:modelValue']) / / the parent component must be notified with the name update:modelValue to modify the value function handleClick () {/ / Parameter 1: notify the parent component to modify the method name / / Parameter 2: the value to be modified emit (' update:modelValue', 'spray Hippo')}
You can write it that way, too. It's easier.
Sub-component
/ / Child.vue {{modelValue}} import {ref} from 'vue'// receives const props = defineProps ([' modelValue' / / receives the value passed in by the parent component using v-model and must be received with the name modelValue]) multiple v-model bindings
Multiple v-model binding documents
Https://v3.cn.vuejs.org/guide/component-custom-events.html#%E5%A4%9A%E4%B8%AA-v-model-%E7%BB%91%E5%AE%9A
Parent component
/ / Parent.vue import {ref} from 'vue'import Child from'. / components/Child.vue'const message1 = ref (Thunder Monkey) const message2 = ref ('cockroach bully')
Sub-component
/ / Child.vue modify msg1 {{msg1}} modify msg2 {{msg2}} import {ref} from 'vue'// receive const props = defineProps ({msg1: String, msg2: String}) const emit = defineEmits ([' update:msg1', 'update:msg2']) function changeMsg1 () {emit (' update:msg1', 'Shark Pepper')} function changeMsg2 () {emit ('update:msg2',' scorpion Lailai')}
V-model modifier
V-model can still pass. The way to pass in the modifier.
V-model modifier document
Https://v3.cn.vuejs.org/guide/component-custom-events.html#%E5%A4%84%E7%90%86-v-model-%E4%BF%AE%E9%A5%B0%E7%AC%A6
Parent component
/ / Parent.vue import {ref} from 'vue'import Child from'. / components/Child.vue'const message = ref ('hello')
Sub-component
/ Child.vue {{modelValue}} import {ref, onMounted} from 'vue'const props = defineProps ([' modelValue', 'modelModifiers']) const emit = defineEmits ([' update:modelValue']) onMounted (() = > {/ / determine whether there is a uppercase modifier or not, if so, execute the toUpperCase () method if (props.modelModifiers.uppercase) {emit ('update:modelValue', props.modelValue.toUpperCase ()}))
Slot slot
Slots can be understood as passing a piece of HTML to a subcomponent. The subcomponent uses the element as an exit to host the distribution.
Slot documentation
Https://v3.cn.vuejs.org/guide/component-slots.html
This article intends to talk about three kinds of slots that are commonly used every day: default slots, named slots, and scope slots.
Default slot
The basic use of the slot is very simple, and the HTML content passed in by the parent component will be rendered simply by using the tag in the child component.
Default slot document
Https://v3.cn.vuejs.org/guide/component-slots.html#%E6%8F%92%E6%A7%BD%E5%86%85%E5%AE%B9
Parent component
/ / Parent.vue Thunder Monkey
Sub-component
/ / Child.vue named slot
Named slots are classified on the basis of the default slots, which can be understood as sitting on the right seat.
Named slot document
Https://v3.cn.vuejs.org/guide/component-slots.html#%E5%85%B7%E5%90%8D%E6%8F%92%E6%A7%BD
Parent component
/ / Parent.vue Thunder Monkey Shark Pepper
Sub-component
/ / Child.vue
The parent component needs to use a tag and use the v-solt: + name on the tag.
The subcomponent needs to be received with a name= name in the tag.
This is the reserved seat.
Finally, it should be noted that the typesetting order of the slot content is based on the typesetting in the sub-components.
This is the case in the above example, where you can carefully observe the incoming order of the subcomponents and the typesetting order of the subcomponents.
Scope slot
If you have used Table in UI frameworks such as Element-Plus, you should have a good understanding of what scope slots are.
Scope slot document
Https://v3.cn.vuejs.org/guide/component-slots.html#%E4%BD%9C%E7%94%A8%E5%9F%9F%E6%8F%92%E6%A7%BD
Parent component
/ / Parent.vue name: {{scope.name}} occupation: {{scope.occupation}} import {ref} from 'vue'import Child from'. / components/Child.vue'const list = ref ([{name: 'Thunder Monkey', occupation: 'Thunder'}, {name: 'Shark Pepper', occupation: 'swimming'}, {name: 'cockroach bully', occupation: 'sweeping'},])
Sub-component
/ / Child.vue const props = defineProps ({list: {type: Array, default: () = > []}})
I don't write styles, so I use hr elements to make it look clear visually. I'm just lazy.
Provide / inject
When it comes to passing values in multiple layers, using props and emit can be clumsy. Provide and inject can be used at this point.
Provide is used in the parent component and can be passed down.
Inject is used in child (descendant) components and can be taken online.
No matter how deep the component hierarchy is, the parent component can act as a dependent provider for all its child components.
Provide / inject documents
Https://v3.cn.vuejs.org/guide/component-provide-inject.html
Parent component
/ / Parent.vue import {ref, provide, readonly} from 'vue'import Child from'. / components/Child.vue'const name = ref ('Tiger downhill') const msg = ref ('Thunder Monkey') / / use readonly to make it impossible for sub-components to be modified directly. You need to call the provide upload method to modify provide ('name', readonly (name)) provide (' msg', msg) provide ('changeName', (value) = > {name.value = value}))
Sub-component
/ / Child.vue msg: {{msg}} name: {{name}} modify import {inject} from 'vue'const name = inject (' name', 'hello') / / to see if there is a value. If there is no value, the default value is applicable (here the default value is hello) const msg = inject (' msg') const changeName = inject ('changeName') function handleClick () {/ / this is not appropriate, because unidirectional data flow is recommended in vue This line of code does not take effect when the parent uses readonly. It will not take effect until it is not used. / / name.value = 'Thunder Monkey' / / correct way changeName ('Tiger body shakes') / / because msg has not been readonly, you can directly modify the value msg.value = 'World'}
Provide can be used with readonly. For more information, please see the examples and notes above.
In fact, provide and inject are mainly used to pass values in deep relationships. The above example only has two layers of father and son, just to illustrate that I am lazy.
Bus bus
There is a method of passing values by bus in Vue2, and we can also simulate it ourselves in Vue3.
This approach is actually a bit like Vuex or Pinia, creating a separate tool to specifically control the data.
But compared with Vuex or Pinia, the method we wrote ourselves does not have good features such as data tracking.
Principle
We create a Bus.js file that controls the data and registers the events.
There is a Bus class in Bus.js
EventList is a must and is used to store a list of events.
In constructor, except for eventList, all the other data are custom data, and public data exists here.
The $on method is used to register events.
The $emit method can call events in $on.
The $off method can log out events in eventList.
Then you need to use the components of the bus, all of which are imported into Bus.js, and you can work together to manipulate a piece of data.
Bus.js
Import {ref} from 'vue'class Bus {constructor () {/ / collect subscription information, dispatch center this.eventList = {}, / / event list This is required / / the following are custom values this.msg = ref ('this is a bus information')} / / subscribe to $on (name, fn) {this.eventList [name] = this.eventList [name] | | [] this.eventList [name] .push (fn)} / / publish $emit (name) Data) {if (this.eventList [name]) {this.eventList [name] .forEach ((fn) = > {fn (data)}) }} / / Unsubscribe $off (name) {if (this.eventList [name]) {delete this.eventList [name]}} export default new Bus ()
Parent component
/ / Parent.vue parent component: message: {{message}} msg: {{msg}} import {ref} from 'vue'import Bus from'. / Bus.js'import Child from'. / components/Child.vue'const msg = ref (Bus.msg) const message = ref ('hello') / / write Bus.$on with monitoring (' changeMsg', data = > {message.value = data})
Sub-component
/ / Child.vue subcomponent: triggers Bus.$emit to modify msg import Bus from'.. / Bus.js'function handleBusEmit () {Bus.$emit ('changeMsg',' Thunder Monkey')} function changeBusMsg () {/ / console.log (Bus.msg) Bus.msg.value = 'modify the value of the bus in the subcomponent'}
This method is actually quite useful, but just look at it may be a little confused, please be sure to knock on the code to practice.
GetCurrentInstance
Getcurrentinstance is a method provided by vue that supports access to internal component instances.
GetCurrentInstance is only exposed to high-level usage scenarios, typically in libraries. Strongly opposes the use of getCurrentInstance in the application code. Don't use it as an alternative to getting this in combinatorial API.
To put it bluntly, this method is suitable for the development of component libraries, but not for daily business development.
GetCurrentInstance can only be called in setup or lifecycle hooks.
Getcurrentinstance document
Https://v3.cn.vuejs.org/api/composition-api.html#getcurrentinstance
In, I simulated ways like $parent and $children.
Parent component
/ / Parent.vue the value of parent component message: {{message}} get child component import {ref, getCurrentInstance OnMounted} from 'vue'import Child from'. / components/Child.vue'const message = ref ('Thunder Monkey') let instance = nullonMounted (() = > {instance = getCurrentInstance ()}) / / Sub-component list let childrenList = [] / / registered component function registrationCom (com) {childrenList.push (com)} function handleClick () {if (childrenList.length > 0) {childrenList.forEach (item = > {console.log ('component instance:' Item) console.log ('component name (name):', item.type.name) console.log ('value of component input box:', item.devtoolsRawSetupState.inputValue) console.log ('- -'})}}
Sub-component
/ / Child.vue-- Child component: get the value of the parent component
Export default {name: 'ccccc'} import {getCurrentInstance, onMounted, nextTick, ref} from' vue'const inputValue = ref ('') let instance = nullonMounted (() = > {instance = getCurrentInstance () nextTick (() = > {instance.parent.devtoolsRawSetupState.registrationCom (instance)}) function handleClick () {let msg = instance.parent.devtoolsRawSetupState.message msg.value ='ha'}
You can copy the code into your project and try it, and you'd better knock it again.
Vuex
Vuex mainly solves the problem of cross-component communication.
In Vue3, the Vuex v4.x version is required.
Installation
Use npm or Yarn to install into the project.
Npm install vuex@next-- save# or yarn add vuex@next-- save uses
After the installation is successful, create the store directory under the src directory, and then create the index.js file under store.
/ / store/index.jsimport {createStore} from 'vuex'export default createStore ({state: {}, getters: {}, mutations: {}, actions: {}, modules: {}})
Enter the above under store/index.js.
State: data warehouse, used to store data.
Getters: getting data is a bit like the use of computed (in my opinion).
Mutations: all the ways to change state data are written in mutations.
Actions: asynchronous and asynchronous methods are all written here, but in the end, you need to modify the data of state through mutations.
Modules: subcontract. If the project is relatively large, the business can be split into separate modules, and then divided into file management and storage.
And then introduce it into src/main.js
Import {createApp} from 'vue'import App from'. / App.vue'import store from'. / store'const app = createApp (App) app .use (store) .mount ('# app') State
Store/index.js
/ / store/index.jsimport {createStore} from 'vuex'export default createStore ({state: {msg:' Thunder Monkey'}})
module
/ / xxx.vueimport {useStore} from 'vuex'const store = useStore () console.log (store.state.msg) / / Thunder Monkey Getter
I think the Getter method is a bit like computed.
For example, if we need to filter the data or assemble the data when we return, we can use the Getter method.
Store/index.js
/ / store/index.jsimport {createStore} from 'vuex'export default createStore ({state: {msg:' Thunder Monkey'}, getters: {getMsg (state) {return state.msg + 'World!' })
module
/ / xxx.vueimport {useStore} from 'vuex'const store = useStore () console.log (store.getters.getMsg) / / Thunder Monkey World! Mutation
Mutation is the only way to modify State data so that Vuex can track the flow of data.
You can call it through commit in the component.
Store/index.js
/ / store/index.jsimport {createStore} from 'vuex'export default createStore ({state: {msg:' Thunder Monkey'}, mutations: {changeMsg (state, data) {state.msg = data})
module
/ / xxx.vueimport {useStore} from 'vuex'const store = useStore () store.commit (' changeMsg', 'garlic bastards') console.log (store.state.msg) / / garlic bastards Action
I am used to writing asynchronous things in the Action method, and then using the dispatch method call in the component.
Store/index.js
/ store/index.jsimport {createStore} from 'vuex'export default createStore ({state: {msg:' Thunder Monkey'}, mutations: {changeMsg (state, data) {state.msg = data}}, actions: {fetchMsg (context) {/ / simulate ajax request setTimeout (() = > {context.commit ('changeMsg',' Shark Pepper')}, 1000)}})
module
/ / xxx.vueimport {useStore} from 'vuex'const store = useStore () store.dispatch (' fetchMsg') Module
Module is the legendary subcontract. This requires you to split the data from different modules into js files.
Let me give you an example. The catalogue is as follows.
Store |-index.js |-modules/ |-user.js |-goods.js
Export of index.js (main file)
Modules/user.js user related module
Modules/goods.js commodity module
Index.js
Import {createStore} from 'vuex'import user from'. / modules/user'import goods from'. / modules/goods'export default createStore ({state: {}, getters: {}, mutations: {}, actions: {}, modules: {user, goods}})
User.js
Const user = {state: {}, getters: {}, mutations: {}, actions: {}} export default user
Goods.js
Const goods = {state: {}, getters: {}, mutations: {}, actions: {}} export default goods
Then put the corresponding data and methods into each module.
Invoking methods and accessing data in a build are similar to the previous usage.
These are the basic uses of Vuex. In addition, Vuex has a variety of grammar candy, you can consult the official documents (https://vuex.vuejs.org/zh/)
Pinia
Pinia is a hot tool recently, and it is also used to deal with cross-component communication. It is very likely to become Vuex 5.
Pinia document
Https://pinia.vuejs.org/
From the point of view of using Pinia for a while, Pinia has the following advantages over Vuex:
Call time code and simplicity.
More friendly to TS.
Merges Mutation and Action of Vuex. Natural support for asynchronism.
Natural subcontracting.
In addition, the Pinia website says it is suitable for Vue2 and Vue3. But I haven't tried to use it in Vue2. I don't bother to try.
Pinia simplifies the state management module and can handle most daily tasks with only these three things.
State: the warehouse where data is stored
Getters: get and filter data (a bit like computed)
Actions: a way to store "modify state"
Let me give you a simple example.
Install npm install pinia# or yarn add pinia registration
Create a store directory under the src directory, and then create index.js and user.js in store
The directory structure is as follows
Store |-index.js |-user.js
Index.js
Import {createPinia} from 'pinia'const store = createPinia () export default store
User.js
There are two common ways to write, just choose one of them.
Import {defineStore} from 'pinia'// 1export const useUserStore = defineStore ({id:' user', / / id required And unique state: () = > {return {name: 'Thunder Monkey'}}, getters: {fullName: (state) = > {return'my name is'+ state.name}}, actions: {updateName (name) {this.name = name}}) / / 2export const useUserStore = defineStore ('user') {state: () = > {return {name: 'Thunder Monkey'}, getters: {fullName: (state) = > {return'my name is'+ state.name}}, actions: {updateName (name) {this.name = name})
Then introduce store/index.js into src/main.js
Src/main.js
Import {createApp} from 'vue'import App from'. / App.vue'import store from'. / store'const app = createApp (App) app .use (store) .mount ('# app') is used in components
module
/ / xxx.vue name: {{name}} full name: {{fullName}} modify import {computed} from 'vue'import {storeToRefs} from' pinia'import {useUserStore} from'@ / store/user'const userStore = useUserStore () / const name = computed (() = > userStore.name) / / suggest const {name FullName} = storeToRefs (userStore) function handleClick () {/ / it is not recommended to change / / name.value = 'scorpion Lailai' / / the recommended way to write it! UserStore.updateName ('Li Si')} two long sentences
In fact, the usage of Pinia is similar to that of Vuex. The default is the logic of subcontracting. I support pineapple (Pinia) in this respect.
Pinia also provides a variety of syntax sugars, so it is highly recommended to read the official documentation (https://pinia.vuejs.org/).
Mitt.js
The bus Bus method we used earlier is actually a bit similar to mitt.js, but mitt.js provides more methods.
For example:
On: adding event
Emit: execution event
Off: remove event
Clear: clear all events
Mitt.js is not dedicated to Vue services, but Vue can use mitt.js to communicate across components.
Install npm i mitt for use
Let me simulate the way the bus Bus works.
I created three files in the sibling directory to use as the simulation.
Parent.vueChild.vueBus.js
Bus.js
/ / Bus.jsimport mitt from 'mitt'export default mitt ()
Parent.vue
/ / Parent.vue Mitt import Child from'. / Child.vue'import Bus from'. / Bus.js'Bus.on ('sayHello', () = > console.log (Thunder Monkey'))
Child.vue
/ / Child.vue Child: say hello to import Bus from'. / Bus.js'function handleClick () {Bus.emit ('sayHello')}
At this point, click the button on Child.vue, and the method defined in Parent.vue will be executed on the console.
The use of mitt.js is actually very simple, it is recommended to follow the official example to tap the code, a few minutes to get started.
At this point, I believe you have a deeper understanding of "how to communicate between Vue3 components". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.