Implement a component
A component is actually a vue file. A simple example () is as follows:
<script setup></script> <template> <div class="header"></div> </template> <style scoped lang="less"> .header { position: absolute; width: 100%; height: 80px; background: linear-gradient( 180deg, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100% ); } </style>
Register to use
Based on script setup, components can be automatically registered and only import can be used, as follows:
<script setup> import Header from "./"; </script> <template> <div class="container"> <Header></Header> </div> </template> <style scoped lang="less"> .container { width: 100%; height: 100%; } </style>
data
You can pass data to components through Prop, and first define it in the component, as follows:
<script setup> const props = defineProps({ title: String, userInfo: Object }); function doSomething(){ if(){ ... } } </script> <template> <div class="header">{{}}</div> </template> <style scoped lang="less"> ... </style>
Here a title attribute is defined, which is a string; a userInfo attribute is an object, which can be passed in the component.to use these properties.
So how to pass data to these properties? Just bind the data directly through v-bind, as follows:
<script setup> import Header from "./"; let userInfo; let title; </script> <template> <div class="container"> <Header :title="title" :userInfo="userInfo"></Header> </div> </template> <style scoped lang="less"> ... </style>
Here is the abbreviation of v-bind. v-bind binding is an expression after the double quotes, so if the type is:
- Value:
:count="3"
- Boolean value:
:isVip="true"
- Array:
:array="[1,2,3]"
- Object:
:info="{name:'name',isVip:true}"
I won't list the others one by one.
Props is supported as follows:
- String
- Number
- Boolean
- Array
- Object
- Date
- Function
- Symbol。
Props supports type checking and also supports default values, as follows:
props: { // Basic type checking (`null` and `undefined` values will pass any type verification) propA: Number, // Multiple possible types propB: [String, Number], // Required string propC: { type: String, required: true }, // Number with default value propD: { type: Number, default: 100 }, // Object with default value propE: { type: Object, // The default value of an object or array must be returned from a factory function default() { return { message: 'hello' } } }, // Function with default values propG: { type: Function, // Unlike the default values of an object or array, this is not a factory function - this is a function used as the default values default() { return 'Default function' } } }
Props are a one-way data stream, which prevents child components from accidentally changing the state of the parent component. Whenever the parent component changes, all the child components' Props will be refreshed to the latest value. Therefore, the properties of Props cannot be changed in the child component, otherwise it will be warned in the console.
Non-Prop Attribute
for exampleclass
、style
andid
etc attribute, by default, it is added to the root node of the component, such as:
<script setup> ... </script> <template> <div class="header" > <input ...> </div> </template> <style scoped lang="less"> ... </style>
When we use this component, add an attribute to it, such as:
<Header ></Header>
The actual rendering result is:
<div class="header" > <input ...> </div>
Disable Attribute inheritance
If you do not want to add to the root node, you can set itinheritAttrs: false
。
<script setup>
Can't declare inheritAttrs, so we need to add normal<script>
, use it at the same timev-bind="$attrs"
To bind nodes that inherit Attribute, such as
<script> export default { inheritAttrs: false }; </script> <script setup> ... </script> <template> <div class="header" > <input ... v-bind="$attrs"> </div> </template> <style scoped lang="less"> ... </style>
In this way, the Attribute added to the component will be directly added to the input element. The actual rendering result is:
<div class="header"> <input ... > </div>
Multiple nodes
If the component has multiple nodes, it must be explicitly setv-bind="$attrs"
, otherwise warning.
event
The data is delivered clearly, so how do you respond to some custom events of the component? Define events through emits, as follows:
<script setup> const emit = defineEmits(["onSelected"]); function selectItem(item){ emit("onSelected", item); } </script> <template> <div class="header" > ... </div> </template> <style scoped lang="less"> ... </style>
Here is a defined onSelected event, which will be executed when the selectItem function is triggered in the component.
Note: If there are no parameters, thenemit("onSelected")
If there are multiple parameters,emit("onSelected", param1, param2, ...)
In the parent component, events are bound through v-on, as follows:
<script setup> import Header from "./"; function headerSelected(item){ } </script> <template> <div class="container"> <Header @onSelected="headerSelected"></Header> </div> </template> <style scoped lang="less"> ... </style>
This is also the abbreviation of v-on, so the event is bound. Events can also be verified, so I won’t go into details here.
v-model
v-model is a two-way data binding, and by default, v-model on the component uses modelValue as prop and update:modelValue as events. For example, there is a title attribute:
<my-component v-model:title="bookTitle"></my-component>
Then in the child component you can do this:
<script setup> const props = defineProps({ title: String }); const emit = defineEmits(["update:title"]); const setTitle = (newTitle) => { emit("update:title", newTitle); } </script> <template> <div class="header" > ... </div> </template> <style scoped lang="less"> ... </style>
This way, the subcomponent can passupdate:title
To synchronize title data.
Slot
What if some areas in a child component are uncertain and need the parent component to implement it? This requires slot slot. The slot is very simple to use, as follows:
<script setup> ... </script> <template> <div class="header" > <slot>default</slot> </div> </template> <style scoped lang="less"> ... </style>
Here a slot is defined and a default content is specified, in the parent component:
<script setup> import Header from "./"; </script> <template> <div class="container"> <Header>newtitle</Header> </div> </template> <style scoped lang="less"> ... </style>
In this way the slot is replaced by the string "newtitle" if there is nothing here<Header></Header>
Then the default content is displayed, that is, "default".
The slot is not only a string, but can be html or other components, such as:
<Header> <button>submit</botton> </Header>
Of course, the default content can also be html.
Named slots
There can be multiple slots in a component, such as the left and right columns, so named slots are needed to distinguish them, as follows:
<script setup> ... </script> <template> <div class="header" > <div name="leftbar" > <slot>left</slot> </div> <div name="rightbar" > <slot>right</slot> </div> </div> </template> <style scoped lang="less"> ... </style>
When using it, you need to use the v-slot command, and it must be<template>
element, because v-slot can only be added in<template>
Above, as follows:
<script setup> import Header from "./"; </script> <template> <div class="container"> <Header> <template v-slot:leftbar > <button>left</button> </template> <template v-slot:rightbar > <button>right</button> </template> </Header> </div> </template> <style scoped lang="less"> ... </style>
The slot name can also be dynamic<template v-slot:[dynamicSlotName] >
. v-slot can also be abbreviated as "#", such as<template #leftbar >
。
Scope
The following code:
<div v-for="item in list" > <slot></slot> </div>
At this time, when we use components, there is no item in the slot, as follows
<my-component > <img :src=""></img> </my-component>
Codes like the above will report an error because the item can only be accessed in the component, while the slots are provided on the parent component and have different scopes.
Of course we can add an attribute binding to the slot, i.e.Slot prop,as follows:
<div v-for="item in list" > <slot :item="item"></slot> </div>
Slots can add multiple attributes.
Then use the value in the parentv-slot
To define the name of the slot prop we provide, such as:
<my-component > <template v-slot:default="slotProps"> <img :src=""></img> </template> </my-component>
This way there will be no errors. If there is only one slot,v-slot
You can directly add components, such as:
<my-component v-slot="slotProps"> <img :src=""></img> </my-component>
The template element is not needed; however, if there are multiple slots (named) it must be added to the template element.
Provide / Inject
The above knows that the parent component uses Props to pass data to the child component, but if the component level is very deep, it needs to pass data to an underlying child component. If you use Props, you need to pass it layer by layer. You can use Provide / Inject at this time. For example: Passed in the parent componentprovide(key, value)
To set the data
<script setup> const userid = "123"; provide("userid", userid); </script> ...
Then pass in the subcomponentinject(key, defaultValue)
To get data
<script setup> const userid = inject("userid", defaultId); </script> ...
Of course, the above is one-time data. If a response is required, use ref or reactive in the parent component, such as:
<script setup> const userid = ref("123"); provide("userid", userid); </script> ...
Get DOM object
In the component, we can set the id to the element and get its DOM object through the id. But in the case where there are multiple components on the page, it will be problematic to get the DOM object in this way because the id is not unique.
We can also useref
attribute Specifies a reference ID for a child component or HTML element. like:
<script setup> import Header from "./"; const headerRef = ref(); </script> <template> <div class="container"> <Header ref="headerRef"> ... </Header> </div> </template> <style scoped lang="less"> ... </style>
The ref attribute of the header above is "headerRef", so the variable name is also consistent, that is,const headerRef = ref();
,soIt is its DOM object, which can be executed
getElementsByTagName
etc.
This means that there are multiple components on the page, but because of the scope, each headerRef does not interfere with each other.
List
What if it is in a list? for example:
<template> <div class="container"> <item ref="itemRef" v-for="item in list"> ... </item> </div> </template>
This wayconst itemRef = ref();
Which one do you get? Actually, that's itIt becomes a list.
[0]
It's the first oneitem
The object of the component.
Element position restricted
Some HTML elements are<ul>
、<ol>
、<table>
and<select>
, there are strict restrictions on its internal limits. Some elements such as<li>
、<tr>
and<option>
, can only appear inside certain specific elements.
This causes us to have some problems using these constrained elements. For example:
<table> <my-component></my-component> </table>
Custom components<my-component>
It will be promoted to the outside as invalid content, resulting in rendering errors. You need to use it at this timeis
attribute, such as:
<table> <tr is="vue:my-component"></tr> </table>
Notice:is
The value of must bevue:
Only at the beginning can it be interpreted as a Vue component. This is to avoid confusion with native custom elements.
Calling child component method
The above event chapter talks about the event of the parent component responding to the child component, that is, the method of the child component calling the parent component. So how does the parent component call the child component's method?
Expose
First of all, the method of subcomponents needs to be exposed, as follows:
<script setup> defineExpose({ onEvent }); function onEvent(event) { (`header: ${event}`); } </script> <template> <div class="header" > ... </div> </template> <style scoped lang="less"> ... </style>
Then add a ref attribute to the child component in the parent component, and then use the ref() function to obtain the object execution method, as follows:
<script setup> import Header from "./"; const headerRef = ref(); function headerEvent(event){ (event); } </script> <template> <div class="container"> <Header ref="headerRef"> ... </Header> </div> </template> <style scoped lang="less"> ... </style>
This way it can passExposed methods are executed.
If there are multiple subcomponents and all have the ref attribute set, you can define multiple variables, as follows:
const headerRef = ref(); const footerRef = ref();
EventBus
The simpler method is to use EventBus to complete communication between components, and it is also very simple to use. Please refer to the official documentation./package/events
We can simply encapsulate it for use, as follows:
import EventEmitter from "events"; const eventEmitter = new EventEmitter(); export const WsEvent = { emit: data => { ("wsevent", data); }, on: callback => { ("wsevent", callback); } };
The above is a detailed description of the component component in Vue3. For more information about Vue3 component, please follow my other related articles!