destroyed
Called after the Vue instance is destroyed. After the invocation, everything indicated by the Vue instance is unbound and all event listeners are removed.
What are components?
If a component is a reusable Vue instance with a name, such as Shanshan-cMP, we can use this component as a custom element in a root instance created with new Vue:
<div id="app">
<shanshan-cmp></shanshan-cmp>
</div>
Copy the code
const vm = new Vue({
el: '#app'
})
Copy the code
Because components are reusable Vue instances, they receive the same options as new Vue, such as Data, computed, Watch, Methods, and lifecycle hooks. The only exceptions are root instance-specific options like EL.
The component registration
Global components
Vue.component
Components created with Vue.com Ponent components are registered globally. That is, they can be used in the template of any newly created Vue root instance (New Vue) after registration.
Parameters:
- {string}
- {Function | Object} [definition]
Usage: Register or get global components. The registration also automatically sets the name of the component with the given ID.
Example:
<div id="app">
<button-counter></button-counter>
</div>
Copy the code
Vue.component('button-counter', {
data () {
return {
count: 0,}},template: ` < button @ click = "count + +" > you rang I {{count}} < / button > `
})
const vm = new Vue({
el: '#app',})Copy the code
Local components
Define the components to use in the Components option. For each attribute in the Components object, its attribute name is the name of the custom element, and its attribute value is the component’s option object.
Example:
<div id="#app">
<button-counter></button-counter>
</div>
Copy the code
const buttonCounter = {
data () {
return {
count: 0}},template: ` < button @ click = "count + +" > you rang I {{count}} < / button > `,}const vm = new Vue({
el: '#app'.components: {
'button-counter': buttonCounter
}
})
Copy the code
Component name
When registering a component, we always need to give it a name. The name you give to a component may depend on what you intend to do with it, so naming is semantic.
Component name case
There are two ways to define component names:
Use kebab-case (horizontal dash delimited name)
Vue.component('my-component', {/ * * * /});
Copy the code
When defining a component using kebab-case, you must use kebab-case when referencing the custom element, for example:
Use PascalCase (big hump name)
Vue.component('MyComponent', {/ * * * /});
Copy the code
When defining a component using PascalCase, you can use either nomenclature when referencing the custom element.
and
are both acceptable. Note, however, that only kebab-case is valid when used directly in the DOM (that is, a string template or a single-file component).
Also: We strongly recommend following the W3C specification for custom component names (all lowercase and must contain a hyphen). This will help you avoid conflicts with current and future HTML elements.
Component reuse
Components can be reused any number of times:
<div id="#app">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
Copy the code
Self-closing assembly
Components that have no content in single-file components, string templates, and JSX should be self-closing — but never in DOM templates.
Self-closing components indicate that they not only have no content, but intentionally have no content. The difference is like a blank page in a book compared to a blank page labeled “this page is intentionally blank.” And without the extra closing tag, your code is much cleaner.
Unfortunately, HTML does not support self-closing custom elements — only official “empty” elements. So the above strategy only applies where Vue’s template compiler can reach before entering the DOM, and then producing HTML that conforms to the DOM specification.
Component’s data option
When we define a component, its data does not directly provide an object like this:
data: {
count: 0
}
Copy the code
Instead, a component’s data option must be a function, so each instance can maintain a separate copy of the returned object:
data () {
return {
count: 0}}Copy the code
If Vue does not have this rule, clicking a button may affect all other instances as follows:
Single root element
Each component must have only one root element, and when the template element is greater than 1, the template’s contents can be wrapped in a parent element.
Component _Prop
Register custom features
By default, a component simply writes its structure, style, and behavior, using data that should be passed to the component from the outside.
How is it delivered? Register the prop that needs to be received, passing the data to the component as a custom feature.
Such as:
<div id="app">
<video-item
title="Sheep village Shake"
poster="https://developer.duyiedu.com/bz/video/955bac93ccb7f240d25a79b2ff6a9fdbda9537bc.jpg@320w_200h.webp"
play="638000"
rank="1207"
></video-item>
</div>
Copy the code
Vue.component('video-item', {
props: ['title'.'poster'.'play'.'rank'],})Copy the code
In the template above, you can see that we can access this value in the component instance just as we can access the value in data:
<div id="app">
<video-item
title="Sheep village Shake"
poster="https://developer.duyiedu.com/bz/video/955bac93ccb7f240d25a79b2ff6a9fdbda9537bc.jpg@320w_200h.webp"
play="638000"
rank="1207"
></video-item>
</div>
Copy the code
Vue.component('video-item', {
props: ['title'.'poster'.'play'.'rank'].template: `<div>{{ title }}</div>`
})
Copy the code
Prop case
Feature names in HTML are case insensitive, so browsers interpret all uppercase characters as lowercase characters. Therefore, when a prop passed is named with a dash, the props inside the component should be named with the hump. Such as:
<div id="app">
<! -- kebab-case in HTML -->
<video-item sub-title="hello!"></video-item>
</div>
Copy the code
Vue.component('video-item', {
// In JavaScript it is camelCase
props: ['subTitle'].template: '<h3>{{ postTitle }}</h3>'
})
Copy the code
Note that this limitation does not exist if you are using a string template.
Pass static or dynamic Prop
Like this, we already know that we can pass a static value to prop:
<video-item title="Sheep village Shake"></video-item>
Copy the code
If you want to pass a dynamic value, you can use the V-bind directive to do so, for example:
<video-item :title="title"></video-item>
Copy the code
Pass all attributes of an object
If you want to pass in all the properties of an object as prop, you can use V-bind with no arguments. For example, for a given object person:
person: {
name: 'shanshan'.age: 18
}
Copy the code
Pass all attributes:
<my-component v-bind="person"></my-component>
Copy the code
This code is equivalent to:
<my-component
:name="person.name"
:age="person.age"
></my-component>
Copy the code
Component _Prop validation
We can specify validation requirements for a prop of a component, for example you can ask what type a prop is. Vue alerts the browser console if a requirement is not being met, which can be very helpful when developing a component that will be used by others.
To customize the validation of prop, you can provide an object with validation requirements for the values in props instead of an array of strings. Such as:
Vue.component('my-component', {
props: {
title: String.likes: Number.isPublished: Boolean.commentIds: Array.author: Object.callback: Function.contactsPromise: Promise}})Copy the code
In the above code, basic type checking is performed on prop. The type value can be one of the following native constructors: String, Number, Boolean, Array, Object, Date, Function, Symbol, any custom constructor, or an Array of the above. Note that null and undefined will pass any type validation. In addition to basic type checking, we can configure advanced options for additional validation of Prop, such as type checking, custom validation, and setting defaults. Such as:
Vue.component('my-component', {
props: {
title: {
type: String.// Check whether prop is of the given type
default: 'Chinese fir is the most beautiful'.// Specify a default value for the prop. The default value for the object or array must be returned from a factory function, such as: default () {return {a: 1, b: 10}},
required: true.// Define whether prop is mandatory
validator (prop) { If the prop function returns a falsy value, the validation fails
return prop.length < 140; }}}})Copy the code
For better teamwork, the definition of prop in the submitted code should be as detailed as possible, or at least specify its type.
Component _ One-way data flow
All prop forms a one-way downlink binding between their parent prop: updates to the parent prop flow down to the child, but not the other way around. This prevents accidental changes in the state of the parent component from the child, which can make the data flow of your application difficult to understand.
There are two common situations when trying to change a prop:
- This prop is used to pass an initial value; The child component then wants to use it as a local prop data, and this value will be changed in subsequent operations. In this case, it is best to define a local data property and use this prop as its initial value:
props: ['initialCounter'].data: function () {
return {
counter: this.initialCounter
}
}
Copy the code
- This prop is passed in as a raw value and needs to be converted. In this case, it is best to use the value of this prop to define a calculated property:
props: ['size'].computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
Copy the code
Component_non-prop features
A non-prop feature is a feature that is not registered by a component. When a component receives a non-prop feature, that feature is added to the root element of the component.
Replace/merge existing features
Imagine the template for < my-cMP > looks like this:
<input type="date" class="b">
Copy the code
To customize a theme for our date picker plug-in, we might need to add a special class name like this:
<my-cmp
class="my-cmp"
></my-cmp>
Copy the code
In this case, we define two different class values:
- My-cmp, which is set up in the component’s template
- B, this is passed in from the component’s parent
For most features, the value provided externally to the component replaces the value set internally by the component. So if you pass type=”text” it will replace type=”date” and break it! Fortunately, the class and style features are a little smarter, as the values on both sides are merged to get the final value: my-cmp B.
Disable feature inheritance
If you don’t want the root element of a component to inherit features, you can set inheritAttrs: false in the component options. Such as:
Vue.component('my-cmp', {
inheritAttrs: false.// ...
})
Copy the code
In this case, it is appropriate to use the instance’s $attrs attribute, which is an object with the key name of the passed attribute and the key value of the passed attribute.
{
required: true.placeholder: 'Enter your username'
}
Copy the code
Using inheritAttrs: false and $attrs, we can manually determine which element these attributes will be assigned to. Such as:
Vue.component('base-input', {
inheritAttrs: false.props: ['label'.'value'].template: ` `,})Copy the code
Note that the inheritAttrs: false option does not affect the style and class bindings.
Component_ Listens for component events
First, let’s write a blog component such as:
Vue.component('blog-post', {
props: {
post: {
type: Object,}},template: ` < div class = "blog post -" > < h3 > {{post. The title}} < / h3 > < button > amplification size < / button > < div > {{post. The content}} < / div > < / div > `,})Copy the code
<div id="app">
<div :style="{fontSize: postFontSize + 'em'}">
<blog-post
v-for="post in posts"
:key="post.id"
:post="post"
>
</blog-post>
</div>
</div>
Copy the code
const vm = new Vue({
el: '#app'.data: {
posts: [{title: 'heading 1'.content: 'Body content'.id: 0}, {title: 'title 2'.content: 'Body content'.id: 1}, {title: 'title'.content: 'Body content'.id: 2],},postFontSize: 1}})Copy the code
As you can see in each blog component, there is a button to enlarge the size of the font on the page. That is, when clicking this button, we tell the parent component to change the postFontSize data to enlarge the text of all the blog posts. What should you do in such a situation?
The Vue instance provides a custom event to solve this problem. The parent component can listen for any event of the child component instance through the V-ON directive, as if it were a native DOM element, such as:
<div id="app">
<div :style="{fontSize: postFontSize + 'em'}">
<blog-post
.
@enlarge-text="PostFontSize + = 0.1"
>
</blog-post>
</div>
</div>
Copy the code
So how can we monitor such a strange event? This requires actively firing a custom event within the component.
How to trigger? An event is emitted by calling the $emit method and passing in the event name, such as:
Vue.component('blog-post', {
props: {... },template: `
<div class="blog-post">
...
<button @click="$emit('enlarge-text')">放大字号</button>
...
</div>
`,})Copy the code
The parent component can then receive the event and update the value of the data pageFontSize.
Throw a value using an event
In some cases, we might want to let the
component decide how much larger its text should be. This is the second argument you can use to provide this value, such as:
Vue.component('blog-post', {
props: {... },template: `
... < button @ click = "$emit (' enlarge - text, 0.2)" > amplification size < / button >...
`,})Copy the code
When the parent component listens for this event, the value thrown can be accessed via $event:
<div id="app">
<div :style="{fontSize: postFontSize + 'em'}">
<blog-post
.
@enlarge-text="postFontSize += $event"
>
</blog-post>
</div>
</div>
Copy the code
Alternatively, write the event handler as a method:
<div id="app">
<div :style="{fontSize: postFontSize + 'em'}">
<blog-post
.
@enlarge-text="onEnlargeText"
>
</blog-post>
</div>
</div>
Copy the code
This value will be passed to the method as the first argument:
methods: {
onEnlargeText: function (enlargeAmount) {
this.postFontSize += enlargeAmount
}
}
Copy the code
The event name
Unlike components and Prop, event names do not have any automated capitalization conversion. Instead, the name of the event that fires needs to match exactly all the names that are listening for that event. If an event with the camelCase name is triggered:
this.$emit('myEvent')
Copy the code
Listening on the kabab-case version of this name has no effect.
<! -- No effect -->
<my-component v-on:my-event="doSomething"></my-component>
Copy the code
Unlike components and prop, event names are not treated as JS variable names or property names, so there is no reason to use camelCase or PascalCase.
The V-ON event listener is automatically converted to all lowercase in the DOM template, so @myevent will become @myevent, making it impossible to listen on myEvent.
Therefore, it is recommended to always use the event name of kebab-case.
Bind native events to components
When a component listens for events, we listen for custom events that are automatically triggered by the component, but in some cases we may want to listen for a native event directly on the root element of a component. This is a. Native modifier that can be used with the V-ON instruction, such as:
<base-input @focus.native="onFocus" @blur.native="onBlur"></base-input>
Copy the code
Vue.component('base-input', {
template: ` `
})
Copy the code
This is useful in some cases, but not a good idea when trying to listen for an element like , such as a
component that might have been refactored, such as:
<label>Name:<input type="text">
</label>
Copy the code
As you can see, the root element of the component is actually an element, and the parent. Native listener will silently fail. It does not generate any errors, but the onFocus handler will not be called as expected.
To solve this problem, Vue provides a $Listeners property, which is an object that contains all listeners working on the component. Such as:
{
focus: function (event) { / *... * / }
blur: function (event) { / *... * /}},Copy the code
With the $Listeners attribute, we can use v-on=”$Listeners “to direct all listeners to specific child elements of the component, such as:
Vue.component('base-input', {
template: Name:
})
Copy the code
Use v-Models on components
V-model directives can also be used on components due to custom events.
Using the V-mode directive on an input element binds the value feature and listens for input events:
<input v-model="searchText" />
Copy the code
Is equivalent to:
<input
:value="searchText"
@input="searchText = $event.target.value"
>
Copy the code
When applying the V-model directive to a component:
<base-input v-model="searchText" />
Copy the code
Is equivalent to:
<base-input
:value="searchText"
@input="searchText = $event"
/>
Copy the code
As with the input element, using the V-model directive on the component binds the value property and listens for the input event.
So, in order for the V-Model directive to work properly, the in this component must:
- Bind its value feature to a prop called Value
- Throws the new value through a custom input event when its input event is raised
Such as:
Vue.component('base-input', {
props: ['value'].template: ` `
})
Copy the code
Once this is done, the V-Model is ready to work on this component.
As we learned above, a V-Model on a component makes use of a prop named Value and an event named input by default, but input controls like checkboxes, checkboxes, and so on May use the value feature for different purposes. In such cases, we can use the Model option to avoid collisions:
Vue.component('base-checkbox', {
model: {
prop: 'checked'.event: 'change'
},
props: {
checked: Boolean
},
template: ` `
})
Copy the code
Using components:
<base-checkbox v-model="lovingVue"></base-checkbox>
Copy the code
The value of lovingVue here will be passed to the prop named Checked. The lovingVue property is updated when a change event is fired with a new value.
The sync modifier
In addition to using the V-model directive for bidirectional binding of components to external data, we can also use the modifier.sync of the V-bind directive.
So how do you do that? Recall that the v-model directive is not used to implement bidirectional data binding for components:
<base-input :value="searchText" @input="searchText = $event"></base-input>
Copy the code
Vue.component('base-input', {
props: ['value'].template: ` `
})
Copy the code
Then, we can also try to change the name of the listening event, such as:
<base-input :value="searchText" @update:value="searchText = $event"></base-input>
Copy the code
Vue.component('base-input', {
props: ['value'].template: ` `
})
Copy the code
This also allows for bidirectional data binding, so what does it have to do with the.sync modifier? At this point, we modify the code:
<base-input :value.sync="searchText"></base-input>
Copy the code
Vue.component('base-input', {
props: ['value'].template: ` `
})
Copy the code
So, the.sync modifier is essentially a syntactic sugar, used on components:
<base-input :value.sync="searchText"></base-input>
Copy the code
Is equivalent to:
<base-input
:value="searchText"
@update:value="searchText = $event"
/>
Copy the code
We can also use the sync modifier with v-bind when setting multiple prop objects simultaneously:
<base-input v-bind.sync="obj"></base-input>
Copy the code
Note:
- The V-bind directive, with the.sync modifier, can only provide the name of the property you want to bind,Can’tUsed with expressions such as:
:title.sync="1+1"
, this operation is invalid - will
v-bind.sync
Used on a literal object, as inv-bind.sync="{ title: 'haha' }"
, will not work because there are many edge cases to consider when parsing a complex expression like this.
v-model VS .sync
To be clear, the.sync syntax was already supported in Vue 1.x, but.sync could change the state of the parent component entirely in the child component, making the entire state change difficult to trace, so this feature was removed in 2.0. Then, with Vue2.3,.sync came back, but now, sync is completely a syntactic sugar. It is implemented in the same way as V-Model, and it is not easy to break the existing data model, so it is safer and more convenient to use.
- Both are used to implement two-way data transfer, implemented by syntax sugar, and finally passed
prop
+The event
To get the job done. - Vue 1.x’s.sync and V-model are two completely different things. After Vue 2.3, it can be understood as a single feature with slightly different usage scenarios
- When a component exposes only one controlled state to the outside world, and all conform to uniform standards, we will use the V-Model to deal with it. .sync is more flexible and can be used whenever two-way data transfer is required.
Component_slot
As with HTML elements, we often need to pass content to a component like this:
<my-cmp>
Something bad happened.
</my-cmp>
Copy the code
If there is a need, we can do it through slots.
Content of the slot
With slots, we can compose components like this:
<my-cmp>What is written in the component tag structure</my-cmp>
Copy the code
Component templates can be written as:
<div>
<slot></slot>
</div>
Copy the code
When the component is rendered,
element, anything between the component’s start tag and end tag is discarded.
Compile scope
When using data in slots:
<my-cmp>This is the data used in the slot: {{user}}</my-cmp>
Copy the code
This slot has access to the same instance attributes as the rest of the template, the same “scope,” but not to the scope of < my-cMP >. Remember: everything in the parent template is compiled in the parent scope; Everything in a subtemplate is compiled in a subscope.
Backup the content
We can set the default slot, which will be rendered when no content is provided, for example, in the < my-cMP > component:
Vue.compopnent('my-cmp', {
template: ` `
})
Copy the code
We want the
Vue.compopnent('my-cmp', {
template: ` `
})
Copy the code
When using a component that does not provide slots, backup content will be rendered. If slots are provided, backup content will be replaced.
A named slot
Sometimes we need multiple slots, such as the < my-CMP > component:
Vue.compopnent('my-cmp', {
template: ` <div class="container"> <header> <! --> </header> <main> <! </main> <footer> <! -- footer --> </footer> </div>
})
Copy the code
At this point, you can use a special feature on the
element: name. Use this feature to define additional slots:
Vue.compopnent('my-cmp', {
template: `
`
})
Copy the code
A
exit without a name carries the implied name “default”. When feeding content to a named slot, we can use the V-slot directive on a
element and supply its name as an argument to the v-slot:
<my-cmp>
<template v-slot:header>
<h1>The head</h1>
</template>
<p>content</p>
<p>content</p>
<template v-slot:footer>
<p>At the bottom of the</p>
</template>
</my-cmp>
Copy the code
Now everything in the
element is passed into the appropriate slot. Anything that is not wrapped in
with v-slot is treated as the content of the default slot. For clarity, the template can also be written as follows:
<my-cmp>
<template v-slot:header>
<h1>The head</h1>
</template>
<template v-slot:default>
<p>content</p>
<p>content</p>
</template>
<template v-slot:footer>
<p>At the bottom of the</p>
</template>
</my-cmp>
Copy the code
Note: V-slot can only be added in<template>
With one exception.
Scope slot
To enable slot content to access the child component’s data, we can bind the child component’s data as a feature of the
element:
Vue.component('my-cmp', {
data () {
return {
user: {
name: 'very'.age: 18,}}},template: `
`,})Copy the code
Features bound to
elements are called slot prop. So in the parent scope, we can give v-slot a value to define the name of the slot prop we provide:
<div id="app">
<my-cmp>
<template v-slot:default="slotProps">
{{ slotProps.user.name }}
</template>
</my-cmp>
</div>
Copy the code
Exclusive default slot abbreviation syntax
A component’s label can be used as a template for a slot when only the default slot is supplied. In this case, v-slot can be used directly on the component:
<my-cmp v-slot:default="slotProps">
{{ slotProps.user.name }}
</my-cmp>
Copy the code
It could also be simpler:
<my-cmp v-slot="slotProps">
{{ slotProps.user.name }}
</my-cmp>
Copy the code
Note: The default slot abbreviation syntax should not be mixed with named slots, as it would result in undefined scope.
<! -- invalid, will result in warning -->
<my-cmp v-slot="slotProps">
{{ slotProps.user.name }}
<template v-slot:other="otherSlotProps">SlotProps is not legal here</template>
</my-cmp>
Copy the code
Whenever multiple slots are present, you need to use the full
based syntax for all of them.
Deconstructing slot Prop
We can use deconstruction to pass in a specific slot prop, as in:
<my-cmp v-slot="{ user }">
{{ user.name }}
</my-cmp>
Copy the code
This makes the template more concise, especially if you provide multiple prop for slots. There are other possibilities, such as prop renaming:
<my-cmp v-slot="{ user: person }">
{{ person.name }}
</my-cmp>
Copy the code
And custom backup content, effective when slot prop is undefined:
<my-cmp v-slot="{ user = { name: 'Guest' } }">
{{ user.name }}
</my-cmp>
Copy the code
Dynamic slot name
Vue server new
<my-cmp>
<template v-slot:[dynamicSlotName] >.</template>
</my-cmp>
Copy the code
An abbreviation for named slot
Vue server new
Like V-ON and V-bind, v-slot has an abbreviation. Replace v-slot: with #.
<my-cmp>
<template #header>
<h1>The head</h1>
</template>
<template #default>
<p>content</p>
<p>content</p>
</template>
<template #footer>
<p>At the bottom of the</p>
</template>
</my-cmp>
Copy the code
Of course, like other instructions, this abbreviation is only available if it has arguments.
Obsolete grammar
A named slot with the slot feature
Deprecated since 2.6.0
<my-cmp>
<template slot="header">
<h1>The head</h1>
</template>
<template>
<p>content</p>
<p>content</p>
</template>
<template slot="footer">
<p>At the bottom of the</p>
</template>
</my-cmp>
Copy the code
Scope slot with slot-scope feature
Deprecated since 2.6.0
<my-cmp>
<template slot="default" slot-scope="slotProps">
{{ slotProps.user.name }}
</template>
</my-cmp>
Copy the code
Component_dynamic Component
The basic use
When we are in a multi-tab interface, it is very useful to dynamically switch between different components.
<div id="app">
<button
v-for="page in pages"
@click="pageCmp = page.cmp"
:key="page.id"
>{{ page.name }}</button>
<component :is="pageCmp"></component>
</div>
Copy the code
Vue.component('base-post', {
data () {
return {
postCmp: ' '.posts: [{title: "Heading 1".content: { template: Content of ` < div > 1 < / div > `}, id: 11},
{ title: "Heading 2".content: { template: Content of ` < div > 2 < / div > `}, id: 12},
{ title: "Title".content: { template: Content of ` < div > 3 < / div > `}, id: 13},
],
}
},
mounted () {
this.postCmp = this.posts[0].content;
},
template: `
`
})
Vue.component('base-more', {
template: '
More
})
const vm = new Vue({
el: '#app'.data: {
pages: [{name: 'blog'.cmp: 'base-post'.id: 0},
{ name: 'more'.cmp: 'base-more'.id: 1}].pageCmp: 'base-post'}})Copy the code
By the above method, we can realize the switch between components, to be able to notice is that every time a switch label, will create a new component instance, to create the dynamic component in more cases are very useful, but in this case, we will be more hope what label component instance can be created for the first time in their cache down. To solve this problem, we can wrap the dynamic component with a
element. Such as:
<! -- Deactivated components will be cached! -->
<keep-alive>
<component v-bind:is="pageCmp"></component>
</keep-alive>
Copy the code
Note:
requires that the component being switched to have its own name, either through the component’s name option or through local/global registration.
keep-alive
when wrapping dynamic components, inactive component instances are cached rather than destroyed.
is an abstract component: it does not render a DOM element on its own and does not appear in the parent component chain. When a component is switched within
, its activated and deactivated lifecycle hook functions are executed accordingly.
activated & deactivated
Activated: activated when the keep-alive component is activated. Deactivated: Activated when the keep-alive component is disabled.
Component _ Handles boundary cases
The next steps are all related to handling boundary cases, special cases that require minor adjustments to the Vue’s rules. It is important to note that these features have disadvantages or dangerous scenarios.
Access elements & components
In most cases, it’s best not to touch inside another component instance or manually manipulate DOM elements. But there are situations where it’s appropriate to do these things.
Accessing the root instance
Within each child component, the root instance can be accessed through $root.
// Vue root instance
new Vue({
data: {
foo: 1
},
computed: {
bar () { / *... * /}},methods: {
baz () { / *... * /}}})Copy the code
All child components can access or use this instance as a global store.
// Get the data for the root component
this.$root.foo
// Write data to the root component
this.$root.foo = 2
// Access the computed properties of the root component
this.$root.bar
// Call the root component's method
this.$root.baz()
Copy the code
It’s handy to use in demos or in small applications with a few components. But using it in large applications can be complicated. So again, we’ll use Vuex (which we’ll learn later) to manage the state of our applications.
Access the parent component instance
In the child component, the parent component instance can be accessed through $parent. This is an alternative to passing data to child components as prop.
Such as:
<cmp-parent>
<cmp-a></cmp-a>
</cmp-parent>
Copy the code
If cmp-parent needs to share a property, all of its children need to access the share property, in which case Cmp-a can access the share through this.$parent-share.
However, components built through this pattern are still prone to internal problems. For example, we nested a child component cMP-b in cMP-A, as in:
<cmp-parent>
<cmp-a>
<cmp-b></cmp-b>
</cmp-a>
</cmp-parent>
Copy the code
If there is no share in cMP-b, check whether there is share in cMP-B. If there is no share in CMP-B, check whether there is share in cMP-B.
var share = this.$parent.share || this.$parent.$parent.share;
Copy the code
This quickly gets out of hand: touching the parent component makes the application harder to debug and understand, especially when changing the parent data, and after a while it’s hard to figure out where the change originated.
Dependency injection can be used to solve these situations.
Dependency injection
In the example above, the $parent attribute doesn’t scale well to deeper nested components. This is where dependency injection comes in, using two new instance options: provide and Inject.
The provide option allows us to specify the data/methods we want to provide to future generations of components, for example:
Vue.component('cmp-parent', {
provide () {
return {
share: this.share,
}
},
data () {
return {
share: 'share',}},template: `<div>cmp-parent</div>`
})
Copy the code
Then in any descendant component, we can use the Inject option to accept properties that specify what we want to add to the instance.
Vue.component('cmp-a', {
inject: ['share'].template: `<div>cmp-a</div>`
})
Copy the code
In contrast to $parent, this usage allows us to access share in any descendant component without exposing the entire CMP-parent instance. This allows us to better continue developing the component without worrying that we might change/remove some of the dependencies of the child component. And the interfaces between these components are always clearly defined, just like props.
In fact, you can think of dependency injection as part of a “prop that works on a large scale,” except for:
- The ancestor component does not need to know which descendant components use the properties it provides
- Descendant components don’t need to know where the injected property came from
However, di has a downside. It couples the components in your application to their current organization, making refactoring more difficult. The supplied properties are also non-reactive. This is for design reasons, as it is not good enough to use them to create a centralized scale of data as it is to use $root to do so. If the attribute you want to share is specific to your application rather than generic, or if you want to update the data provided in the ancestor component, this means you may need to switch to a true state management scheme like Vuex.
Access child component instances or child elements
In spite of prop and events, there may be times when we need to access a child component directly in JS. In this case, we can use the ref feature to give the child an ID reference:
<my-cmp ref="cmp"></my-cmp>
Copy the code
This allows the
instance to be accessed via this.$refs.cmp. Ref can also access specified DOM elements, such as:
<input ref="input" />
Copy the code
So, we can query the DOM element by calling this.$refs.input.
When ref and V-for are used together, the resulting reference will be an array containing these subcomponents of the corresponding data source.
Note: $refs only take effect after the component is rendered, and they are not reactive. You should avoid accessing $refs in templates or calculated properties.
Programmatic event listeners
In addition to V-ON and $EMIT, the Vue instance provides other methods in its event interface. We can:
- Listen for an event with $on(eventName, eventHandler)
- Listen for one event at a time with $once(eventName, eventHandler)
- Stop listening for an event with $off(eventName, eventHandler)
These methods are not typically used, but they can be useful when you need to manually listen for events on a component instance.
For example, sometimes we integrate third-party libraries with components:
Vue.component('my-cmp', {
// Attach the date picker to an input box once
// It will be mounted to the DOM.
mounted () {
// Pikaday is a library of third-party date pickers
this.picker = new Pikaday({
field: this.$refs.input,
format: 'YYYY-MM-DD',}}),// Before the component is destroyed,
// Also destroy the date picker.
beforeDestroy () {
this.picked.destroy();
},
template: ` < div > < input type = "text" ref = "input" / > < button @ click = "$destroy ()" > destroying components < / button > < / div > `,})Copy the code
There are two potential problems with the above approach:
- It needs to store the picker in the component instance, preferably accessible only by lifecycle hooks if possible. This is not a serious problem, but it can be considered clutter.
- Our build code is separate from our cleanup code, which makes it harder to programmatically clean up everything we build.
So, we can solve these two problems with programmatic listeners:
Vue.component('my-cmp', {
mounted () {
var picker = new Pikaday({
field: this.$refs.input,
format: 'YYYY-MM-DD',})this.$once('hook:beforeDestroy'.() = >{ picker.destroy(); })},template: ` < div > < input type = "text" ref = "input" / > < button @ click = "$destroy ()" > destroying components < / button > < / div > `
})
Copy the code
Using this strategy, we can also make multiple input field elements use different pikaday:
Vue.component('my-cmp', {
mounted () {
this.datePicker('inputA');
this.datePicker('inputB');
},
methods: {
datePicker (refName) {
var picker = new Pikaday({
field: this.$refs[refName],
format: 'YYYY-MM-DD',})this.$once('hook:beforeDestroy'.() = >{ picker.destroy(); })}},template:
`
})
Copy the code
Note, though, that if you find yourself having to do a lot of setup and cleanup in a single component, the best approach is usually to create more modular components. In this case, we recommend creating a reusable
component.
A circular reference
Recursive components
Components can call themselves in their own templates, but they can only do this with the name option:
name: 'my-cmp'
Copy the code
However, when a component is registered globally with Vue.com Ponent, the global ID is automatically set to the component’s name option.
Vue.component('my-cmp', { / * * * /});
Copy the code
A recursive component can lead to an infinite loop with the slightest error:
name: 'my-cmp'.template: `<div><my-cmp /></div>`
Copy the code
A component like the one above will cause a “Max Stack Size exceeded” error, so make sure the recursive call is conditional (for example, using a V-if that will eventually get false).
Circular references between components
Sometimes, when building components, there are descendants/ancestors of each other:
Vue.component('cmp-a', {
template: `
`
})
Copy the code
Vue.component('cmp-b', {
template: `
`
})
Copy the code
At this point, we are using a globally registered component and there is no paradox, but there would be if we were using a local component.
Error: Failed to mount Component: template or render function not defined
The modular system finds that it needs A, but first A depends on B, but B depends on A, but A depends on B, and so on. It becomes a loop, not knowing how to fully resolve one component without going through the other. To solve this problem, we need to give the module system A point: “A needs B anyway, but we don’t need to parse B first.”
beforeCreate () {
this.$options.components.CmpB = require('./tree-folder-contents.vue').default;
}
Copy the code
Or, when registering components locally, you can use webpack’s asynchronous import:
components: {
CmpB: () = > import('./tree-folder-contents.vue')}Copy the code
Alternatives to template definitions
Inline template
When using a component, write the special feature inline-template to treat the contents directly as templates instead of being distributed (slots).
<my-cmp inline-template>
<div>
<p>These are compiled as the component's own template.</p>
<p>Not parent's transclusion content.</p>
</div>
</my-cmp>
Copy the code
However, inline-template makes the scope of the template more difficult to understand. As a best practice, use the template option within the component or a
element in the.vue file to define the template in preference.
X-Template
Another way to define a template is to give it a text/x-template type in a
<script
type="text/x-template"
id="hello-world-template"
></script>
Copy the code
Vue.component('hello-world', {
template: '#hello-world-template'
})
Copy the code
These can be used for very large demos or very small applications, but avoid them otherwise because they separate the template from the rest of the component’s definition.
Control update
Forced to update
When you change some data and the page is not re-rendered, you can call $forceUpdate to do a forced update.
$forceUpdate $forceUpdate $forceUpdate $forceUpdate $forceUpdate $forceUpdate $forceUpdate $forceUpdate $forceUpdate
Create low-overhead static components with V-once
Rendering normal HTML elements is very fast in Vue, but sometimes you may have a component that contains a lot of static content. In this case, you can add the V-once feature to the root element to ensure that the content is evaluated only once and then cached, like this:
Vue.component('terms-of-service', {
template: `
Terms of Service
... a lot of static content ...
`
})
Copy the code
Try not to overuse this pattern. It’s handy in rare cases when you need to render a lot of static content, and it’s not necessary unless you’re very careful about rendering slowly — plus it can cause a lot of confusion later on. For example, assuming another developer is unfamiliar with V-once or missed it in the template, they might spend hours trying to figure out why the template isn’t updating properly.
Component_Communication
prop
When a parent component passes data to a child component, it can pass it through a feature.
This is recommended for parent -> child communication.
$emit
When a child component passes data to its parent, it fires an event that throws data.
This is recommended for child -> parent communication.
v-model
.sync
$attrs
When an ancestor component passes data to a descendant component, it can use $attrs pass.
Demo or small projects can use $attrs for data transfer, medium and large projects are not recommended, data flow can become difficult to understand.
The real purpose of $attrs is to write base components that give some DOM elements non-prop features.
$listeners
You can execute the ancestor component’s functions in descendant components to implement data passing.
$Listeners can be used for demos or small projects, but are not recommended for medium and large projects and may make data streams difficult to understand.
The real purpose of $Listeners is to point all event listeners to a specific child of the component.
$root
The data of the root instance can be accessed in the child component.
This is handy for demos or very small applications with a few components. Medium and large projects are not applicable. Can make the application difficult to debug and understand.
$parent
The parent instance’s data can be accessed in the child component.
This is handy for demos or very small applications with a few components. Medium and large projects are not applicable. Can make the application difficult to debug and understand.
$children
The child instance’s data can be accessed in the parent component.
This is handy for demos or very small applications with a few components. Medium and large projects are not applicable. Can make the application difficult to debug and understand.
ref
The child instance’s data can be accessed in the parent component.
$refs only take effect after the component is rendered, and they are not reactive and are suitable for demo or small projects.
provide & inject
Ancestor components provide data and descendant components inject as needed.
It can couple the blocking methods of components together and make component refactoring difficult and maintenance difficult. Not recommended for medium to large projects, suitable for writing small components.
eventBus
Vue.prototype.$bus = new Vue();
Copy the code
Vue.component('cmp-a', {
data () {
return {
a: 'a'}},methods: {
onClick () {
this.$bus.$on('click'.this.a)
}
},
template: ` < div > < button @ click = "onClick" > click < / button > < / div > `,})Copy the code
Vue.component('cmp-a', {
mounted () {
this.$bus.$on('click'.data= > {
console.log(data); })},template: `
b
`,})Copy the code
You can use this approach when non-parent components communicate, but only for small projects. When used in medium and large projects, the code will be chaotic and difficult to maintain.
Vuex
State management, medium and large projects are strongly recommended to use this method, learn later ~
Mixed with
basis
Mixins provide a very flexible way to distribute reusable functionality in Vue components. A mixin object can contain any component option. When a component uses mixin, all mixin options are “blended” into the component’s own options.
var minxin = {
created () {
this.hello();
},
methods: {
hello () {
console.log('Hello, I'm a function mixed in');
},
}
}
Vue.component('my-cmp', {
mixins: [mixin],
template: `
xx
`
})
Copy the code
Option to merge
When components and mixins have options with the same name, those options are “merged” in the appropriate way.
Merge data with component data in preference:
var mixin = {
data () {
return {
msg: 'hello',}}}new Vue({
mixins: [mixin],
data: {
msg: 'goodbye',},created: function () {
console.log(this.msg)
})
Copy the code
Merge hook functions that merge into an array. Call the hooks embedded in the object first, then call the component’s own hooks.
var mixin = {
created () {
console.log('Mixin object hook')}}new Vue({
el: '#app'.mixins: [mixin],
created () {
console.log('Component hook')}})Copy the code
Options that merge values into objects, such as methods, components, and so on, will be merged into the same object. When two object key names conflict, the component object’s key-value pair is taken.
With global
Mixin can also be registered globally. Use with extreme care! Once global mixin is used, it affects every subsequent Vue instance created. When used appropriately, this can be used to inject processing logic for custom options.
// Inject a handler for the custom option 'myOption'.
Vue.mixin({
created () {
var myOption = this.$options.myOption
if (myOption) {
console.log(myOption)
}
}
})
new Vue({
myOption: 'hello! '
})
Copy the code
Use global mixin with caution, as it affects each individually created Vue instance (including third-party components). In most cases, this should only apply to custom options.
Custom instruction
Introduction to the
We can write our own custom instructions to manipulate DOM elements for code reuse purposes. Note that in Vue, the main form of code reuse and abstraction is components. However, there are cases where you still need to perform low-level operations on normal DOM elements, and custom directives are used.
Global registration directive:
Vue.directive('focus', {/ * * * /})
Copy the code
Local registration instruction
const vm = new Vue({
el: '#app'.directives: {
focus: {/ * * * /}}})Copy the code
Use:
<input v-focus></input>
Copy the code
For example, write an autofocus input box:
Vue.directive('focus', {
// executes when the bound element is inserted into the DOM
inserted: function (el) { el.focus(); }})Copy the code
At this point, auto-focus can be achieved using the V-focus directive on the input element.
Hook function
The custom directive object provides optional hook functions for use.
bind
Only called once, the first time a directive is bound to an element. This is where you can perform one-time initialization Settings.
inserted
Called when the bound element is inserted into the parent (the parent is guaranteed to exist, but not necessarily inserted into the document).
update
Called when the component’s VNode is updated, but may occur before its child VNodes are updated.
componentUpdated
Called after the VNode of the component where the directive resides and its child VNodes are all updated.
unbind
Called only once, when the directive is unbound from the element (the bound Dom element is removed by Vue).
Hook function arguments
- El: The element bound by the directive that can be used to manipulate the DOM directly.
- Binding: Object containing the following properties:
- Name: indicates the command name, excluding the V – prefix.
- Value: specifies the binding value of the directive. For example, v-my-directive=”1 + 1″, the binding value is 2.
- OldValue: The previous value of the directive binding, available only in the UPDATE and componentUpdated hooks. Available regardless of whether the value changes.
- Expression: command expression in the form of a string. For example, if v-my-directive=”1 + 1″, the expression is “1 + 1”.
- Arg: Optional parameter passed to the instruction. For example, v-my-directive:foo, the parameter is “foo”.
- Modifiers: An object that contains modifiers. For example, in v-my-directive.foo.bar, the modifier object is {foo: true, bar: true}.
- Vnode: virtual node generated by Vue compilation.
- OldVnode: Last virtual node, available only in update and componentUpdated hooks.
practice
Simulation of v – show
// Bind to false, display to none, true, display to ""
Vue.directive('myshow', {
bind (el, binding, vnode, oldVnode) {
var display = binding.value ? ' ' : 'none';
el.style.display = display;
},
update (el, binding, vnode, oldVnode) {
var display = binding.value ? ' ' : 'none'; el.style.display = display; }})Copy the code
Simulation of v – model
// 1. Set value to the element based on the bound data
// 2. Change the value of the data when the input event is triggered
// 3. Synchronize the input value after changing the data
Vue.directive('mymodel', {
bind (el, binding, vnode) {
const vm = vnode.context;
const { value, expression } = binding;
el.value = value;
el.oninput = function (e) {
const inputVal = el.value;
vm[expression] = inputVal;
}
},
update (el, binding) {
const{ value } = binding; el.value = value; }})Copy the code
Write a V-slice
Vue.directive('slice', {
bind (el, binding, vnode) {
const vm = vnode.context;
let { value, expression, arg, modifiers } = binding;
if(modifiers.number) {
value = value.replace(/[^0-9]/g.' ');
}
el.value = value.slice(0, arg);
vm[expression] = value.slice(0, arg);
el.oninput = function (e) {
let inputVal = el.value;
if(modifiers.number) {
inputVal = inputVal.replace(/[^0-9]/g.' ');
}
el.value = inputVal.slice(0, arg);
vm[expression] = inputVal.slice(0, arg);
}
},
update (el, binding, vnode) {
const vm = vnode.context;
let { value, arg, expression, modifiers } = binding;
if(modifiers.number) {
value = value.replace(/[^0-9]/g.' ');
}
el.value = value.slice(0, arg);
vm[expression] = value.slice(0, arg); }})Copy the code
Dynamic instruction parameter
The parameters of an instruction can be dynamic. For example, v-directive:[arguments]=”value, the argument argument can be updated based on component instance data.
Rewrite the v – slice
Vue.directive('slice', {
bind (el, binding, vnode) {
const vm = vnode.context;
let { value, expression, arg, modifiers } = binding;
if(modifiers.number) {
value = value.replace(/[^0-9]/g.' ');
}
el.value = value.slice(0, arg);
vm[expression] = value.slice(0, arg);
el.oninput = function (e) {
let inputVal = el.value;
if(modifiers.number) {
inputVal = inputVal.replace(/[^0-9]/g.' ');
}
el.value = inputVal.slice(0, arg);
vm[expression] = inputVal.slice(0, arg);
}
},
update (el, binding, vnode) {
const vm = vnode.context;
let { value, arg, expression, modifiers } = binding;
if(modifiers.number) {
value = value.replace(/[^0-9]/g.' ');
}
el.value = value.slice(0, arg);
vm[expression] = value.slice(0, arg);
el.oninput = function (e) {
let inputVal = el.value;
if(modifiers.number) {
inputVal = inputVal.replace(/[^0-9]/g.' ');
}
el.value = inputVal.slice(0, arg);
vm[expression] = inputVal.slice(0, arg); }}})Copy the code
Function shorthand
When you want to trigger the same behavior in bind and update, regardless of the other hooks, you can write it as a function:
Vue.directive('myshow'.(el, binding) = > {
const { value } = binding;
const display = value ? ' ' : 'none';
el.style.display = display;
})
Copy the code
Vue.directive('slice'.(el, binding, vnode) = > {
const vm = vnode.context;
let { value, expression, arg, modifiers } = binding;
if(modifiers.number) {
value = value.replace(/[^0-9]/g.' ');
}
el.value = value.slice(0, arg);
vm[expression] = value.slice(0, arg);
el.oninput = function (e) {
let inputVal = el.value;
if(modifiers.number) {
inputVal = inputVal.replace(/[^0-9]/g.' ');
}
el.value = inputVal.slice(0, arg);
vm[expression] = inputVal.slice(0, arg); }})Copy the code
Object literals
If a custom directive requires multiple values, you can pass in a JS object literal. The instruction function can accept all valid JS expressions.
<div v-demo="{ color: 'white', text: 'hello!' }"></div>
Copy the code
Vue.directive('demo'.function (el, binding) {
console.log(binding.value.color) // => "white"
console.log(binding.value.text) // => "hello!"
})
Copy the code
The filter
Custom filters for some common text formatting.
Filters are available in two places: double curly brace interpolation and v-bind expressions, which are added to the end of JS expressions and are represented by the “pipe” symbol:
<! -- In double braces -->
{{ message | filter }}
<!-- 在 v-bind 中 -->
<div v-bind:id="id | filter"></div>
Copy the code
Defining filters
Global filters:
Vue.filter('filter'.value= > {})
Copy the code
Local filter:
filter () {
return xxx;
}
Copy the code
parameter
When the filter form for MSG | filter, filter filter receives a parameter, parameters for MSG.
When the filter form for MSG | filter (‘ a ‘), the filter filter receives two parameters, parameters for MSG, ‘a’
Filter series
{{ msg | filterA | filterB }}
Copy the code
In this example, the filterA argument is MSG and the filterB argument is filterA.
practice
Uppercase
{{ content | capitalize }}
Copy the code
Vue.filter('capitalize'.value= > {
if(! value) {return };
return value.charAt(0).toUpperCase() + value.slice(1);
})
Copy the code
Put a comma between the numbers
{{ money | toMoney }}
Copy the code
Vue.filter('toMoney'.value= > {
if(! value) {return };
return value.toLocaleString();
});
Copy the code
Number add text “ten thousand”
{{ likes | addWord }}
Copy the code
Vue.filter('addWord'.value= > {
if(! value) {return };
if(value > 10000) {
return ( value / 10000).toFixed(1) + '万';
}
return value;
});
Copy the code
Erection of scaffolding
Install @ vue/cli
The node version must be >8.9. 8.11.0 + is recommended.
About older versions: If you have installed an older version of VUE-CLI (1.x or 2.x) globally before this, you need to uninstall it first. Run: NPM uninstall vue-cli -g or YARN Global Remove VUe-cli.
Installation:
npm install -g @vue/cli
# OR
yarn global add @vue/cli
Copy the code
After installation, the vue commands can be accessed from the command line.
Check whether the version is correct:
vue --version
Copy the code
Rapid prototyping
Installation:
npm install -g @vue/cli-service-global
# OR
yarn global add @vue/cli-service-global
Copy the code
Install the vscode plug-in
Name: Vetur. Use to highlight. Vue file code
Exercise _ Tree components
Data:
data: [
{
label: "Level 1".children: [{label: "The secondary 1-1".children: [{label: "Triple the 1-1-1"}}]}, {label: "Level 2".children: [{label: "Secondary 2-1".children: [{label: "Triple the 2-1-1"}]}, {label: "Secondary 2-2".children: [{label: "Triple the 2-2-1"}}]}, {label: "Level 3".children: [{label: "Secondary 3-1".children: [{label: "Triple the 3-1-1"}]}, {label: "Secondary 3-2".children: [{label: "Triple the 3-2-1"}]}]Copy the code
Use scaffolding to build projects
Pull 2.x template (old version)
npm install -g @vue/cli-init
# `vue init`The operation effect will follow`[email protected]`Same vue init webpack my-projectCopy the code
Rendering function
basis
When we need the programming power of JavaScript, we can take advantage of rendering functions. Renderers are closer to the compiler than templates.
For example, we want to generate some headings:
<h1>Hello world!</h1>
Copy the code
If we follow the previous pattern, there will be a lot of redundancy in the template. If you use render functions at this point, the code will be much cleaner to write.
props: {
level: {
type: Number.required: true}},render: function (createElement) {
return createElement(
'h' + this.level, // Label name
this.$slots.default // Array of child nodes)},Copy the code
Nodes, trees, and virtual DOM
Before diving into rendering functions, let’s take a look at how browsers work. For example, the following HTML:
<div>
<h1>My title</h1>
Some text content
<! --TODO: Add tagline -->
</div>
Copy the code
When the browser reads the code, it creates oneThe DOM node treeTo keep track of everything, just as you would draw a family tree to track the progress of family members. The DOM node tree corresponding to the above HTML is shown in the figure below:
Each element is a node. Each paragraph of text is also a node. Even comments are nodes. A node is a part of a page. Like a family tree, each node can have child nodes.
Updating all of these nodes efficiently is difficult, but fortunately we don’t need to do this manually. Just tell Vue what HTML you want on the page, for example in a template:
<h1>{{ blogTitle }}</h1>
Copy the code
Or in a render function:
render: function (createElement) {
return createElement('h1'.this.blogTitle)
}
Copy the code
In both cases, Vue automatically keeps the page updated even if the blogTitle changes.
Virtual DOM
Vue tracks how it changes the real DOM by creating a virtual DOM. Such as:
return createElement('h1'.this.blogTitle);
Copy the code
What does createElement return? It does not return an actual DOM element. A more accurate name might be createNodeDescription, because it contains information that tells the Vue what nodes need to be rendered on the page, including descriptions of their children. We describe such a node as a “virtual node”, often abbreviated to “VNode”. “Virtual DOM” is the name we use for the entire VNode tree built from the Vue component tree.
CreateElement method parameter
CreateElement accepts the following parameters:
CreateElement (tag name (required), data object (optional) that corresponds to attributes in the template, child virtual node (optional));Copy the code
Deep data object
{
// The same API as' v-bind:class 'accepts a string, object, or array of strings and objects
class: {
foo: true.bar: false
},
// The same API as' v-bind:style 'accepts a string, object, or array of objects
style: {
color: 'red'.fontSize: '14px',},// Plain HTML attribute
attrs: {
id: 'foo',},/ / component prop
props: {
myProp: 'bar',},/ / DOM attributes
domProps: {
innerHTML: 'baz',},// Event listeners, modifiers such as "V-on :keyup.enter" are not supported
on: {
click: this.onClick
},
// Used only by components to listen for native events, not events that are emitted by components using VM. $emit.
nativeOn: {
click: this.nativeClickHandler
},
// Custom instruction. Note that 'oldValue' in 'binding' cannot be assigned because Vue has automatically synchronized for you.
directives: [{name: 'my-custom-directive'.value: '2'.expression: '1 + 1'.arg: 'foo'.modifiers: {
bar: true}}].// Other special top-level attributes
key: 'myKey'.ref: 'myRef'.// If the same ref name is applied to multiple elements in the render function, '$refs.myRef' becomes an array.
refInFor: true
/ / scope slot, format is: {name: props = > VNode | Array < VNode >}
// If the component is a child of another component, specify a name for the slot
slot: 'name-of-slot'.scopedSlots: {
default: props= > createElement('span', props.text)
},
}
Copy the code
Use JavaScript instead of template functionality
V – if and v – for
Vue’s rendering functions do not provide proprietary alternatives to what can easily be done in native JavaScript. For example, v-if and v-for are used in templates:
<ul v-if="items.length">
<li v-for="item in items">{{ item }}</li>
</ul>
<p v-else>No items found.</p>
Copy the code
These can be overridden in the render function using JavaScript’s if/else and map:
props: ['items'],
render (createElement) {
if(items.length) {
return createElement('ul'.this.items.map(item= > createElement('li', item)))
} else {
return createElement('p'.'No items found'); }}Copy the code
v-model
There is no direct correspondence to the V-Model in the rendering function — you have to implement the logic yourself:
<input v-model="value" />
Copy the code
data () {
return {
value: 'ceshi',
}
},
render (createElement) {
const self = this;
return createElement('input', {
attrs: {
value: self.value
},
on: { input (e) { self.value = e.target.value; }}}); },Copy the code
Event & key modifier
For.passive,.capture, and.once event modifiers, Vue provides prefixes that can be used with on:
The modifier | The prefix |
---|---|
.passive | & |
.capture | ! |
.once | ~ |
. The capture. Once or. Once the capture | ~! |
Such as:
on: {
'! click': this.doThisInCapturingMode,
'~keyup': this.doThisOnce,
'~! mouseover': this.doThisOnceInCapturingMode
}
Copy the code
For all other modifiers, private prefixes are not required, because you can use event methods in event handlers:
The modifier | Handle equivalent operations in functions |
---|---|
.stop | event.stopPropagation() |
.prevent | event.preventDefault() |
.self | if (event.target ! == event.currentTarget) return |
Key:.Enter,.13 | if (event.keyCode ! == 13) return For other key modifiers, change 13 to another key code |
Modifier keys:.ctrl,.alt,.shift,.meta | if (! CtrlKey) return (Change ctrlKey to altKey, shiftKey, or metaKey respectively) |
slot
You can access the contents of static slots via this.$slots, where each slot is an array of vNodes:
<div>
<slot></slot>
</div>
Copy the code
render: function (createElement) {
return createElement('div'.this.$slots.default)
}
Copy the code
You can also access the scope slots via this.$scopedSlots. Each scope slot is a function that returns a number of VNodes:
<div>
<slot :text="message"></slot>
</div>
Copy the code
data() {
return {
msg: 'hello world',}},render: function (createElement) {
return createElement('div'[this.$scopedSlots.default({
text: this.msg
})
])
}
Copy the code
To pass a scope slot to a child component using a render function, you can use the scopedSlots field in the VNode data object:
<div>
<base-slot v-slot="slotProps">
{{ slotProps.text }}
</base-slot>
</div>
Copy the code
render: function (createElement) {
return createElement('div', [
createElement('base-slot', {
// Pass 'scopedSlots' in the data object
/ / format for {name: props = > VNode | Array < VNode >}
scopedSlots: {
default: function (props) {
return createElement('span', props.text)
}
}
})
])
}
Copy the code
JSX
Use JSX syntax in Vue. This brings us back to a more template-like syntax.
render () {
return (
<h1>This is a headline</h1>)}Copy the code
The interpolation
<div>{ this.value }</div>
Copy the code
instruction
In JSX, some instructions don’t exist, so we can handle them differently.
v-text
<div domPropsTextContent="<p>i am a p</p>"></div>
Copy the code
v-html
<div domPropsInnerHTML="<p>i am a p</p>"></div>
Copy the code
v-show
JSX supports the V-show command:
<div v-show={this.show}></div>
Copy the code
v-if
<! -- v-if -->
{true && <div>div</div>}
{true ? <div>div</div> : <span>span</span>}
Copy the code
v-for
{ [1, 2, 3].map(item => (<div key={item}>{ item }</div>))}
Copy the code
v-on
<button onClick={this.handleClick}>Click on the event</button>
<button on-click={this.handleClick}>Click on the event</button>
<! -- @click.native -->
<cmp-button nativeOnClick={this.handleClick}>Native click events</cmp-button>
<! -- Pass parameters -->
<button onClick={e= >This.handleclick (this.id)}> Pass parameters when the click event is triggered</button>
Copy the code
v-bind
<input value={this.value} />
Copy the code
In JSX you can specify a style class directly using class=”xx”. Inline styles can be written as style=” XXX “.
<div class="a b" style="font-size: 12px;">Content</div>
<div class={{a: true.b: false}} >Content</div>
<div style={{color: 'red', fontSize: '14px'}} >Content</div>
Copy the code
v-model
There are plug-ins that support v-Model, so you can use them directly:
<input type="text" v-model={this.value} />
Copy the code
v-slot
<my-cmp>The default slot<div slot="a">Named Slot A</div>
</my-cmp>
Copy the code
v-pre
v-cloak
v-once
The above three instructions are not commonly used and have no alternative
Ref
<div ref="xxx">xxx</div>
Copy the code
When iterating over an element or component, as in:
[1.2.3].map(item= > <div ref="xx" key={ item} >{ item }</div>)
Copy the code
$refs.xxx does not fetch the expected array value, so refInFor property is set to true:
[1.2.3].map(item= > <div ref="xx" refInFor={true} key={item}>{ item }</div>)
Copy the code
Custom instruction
render () {
/ / 1
return (
<input v-splice={{value: this.value.modifiers: {number: true}}} / >
)
/ / 2
const directives = [
{
name: 'splice'.value: this.value,
modifiers: {number: true}}];return (
<div {.{ directives} }></div>)}Copy the code
The filter
<! -- Normal use of filters -->
<div>{{ msg | capitalize }}</div>
<! Use filters in JSX -->
<div>{ this.$options.filters('capitalize')(this.msg)}</div>
Copy the code
slot
Template writing:
<! -- Inside component -->
<div class="demo">
<slot name="header"></slot>
<slot></slot>
</div>
<! -- When used -->
<my-cmp>
default
<template v-slot:header>header</template>
</my-cmp>
Copy the code
JSX writing:
<! -- Inside component -->
<div class="demo">
{ this.$slots.header }
{ this.$slots.default }
</div>
<! -- When used -->
<my-cmp>
default
<template slot="header">header</template>
</my-cmp>
Copy the code
Scope slot: template
<! -- Inside component -->
<div class="demo">
<slot :text="'HelloWorld'"></slot>
</div>
<! -- When used -->
<my-cmp v-slot="slotProps">
{{ slotProps.text }}
</my-cmp>
Copy the code
JSX writing:
<! -- Inside component -->
<div class="demo">
{
this.$scopedSlots.default({
text: 'HelloWorld',
})
}
</div>
<! -- When used -->
<div id="app">
<base-demo {.{
scopedSlots: {
default: props= > props.text
},
}}></base-demo>
</div>
Copy the code
Functional component
We can mark a component as functional when it doesn’t need state (that is, reactive data), doesn’t need any lifecycle scenarios, and just accepts props to display the component.
functional: true.Copy the code
Because functional components are just functions, the rendering overhead is much lower.
Prior to 2.3.0, if a functional component wanted to receive a prop, the props option was required. In versions 2.3.0 and above, you can omit the props option, and attributes on all components are automatically resolved implicitly to prop.
To compensate for the lack of instances, the Render function provides a second argument, context, as the context. Context contains the following fields:
- Props: Objects that provide all prop
- Slots: a function that returns an object containing all slots (non-scoped)
- ScopedSlots: (2.6.0+) An object that exposes the incoming scope slots. Normal slots are also exposed as functions.
- Data: The entire data object passed to the component as the second parameter to createElement
- Parent: reference to the parent component
- An object containing all event listeners registered by the parent component for the current component. This is an alias for data.on.
- Injections: (2.3.0+) If the Inject option is used, then the object contains attributes that should be injected.
- Children: An array of VNode children, containing all non-scoped and non-named slots.
slots() VS children
Example 1:
<base-level :level="1" @click="handleClick">
<template v-slot:header>
<div>I am a head</div>
</template>
<div>div</div>
<p>p</p>
<template>template</template>
</base-level>
Copy the code
The result of slots() is:
{
default: [<div>div</div>.<p>p</p>, template],
header: [<div>I am a head</div>]}Copy the code
The results of children are:
[<div>div</div>, <p>p</p>, template]
Copy the code
Example 2:
<base-level :level="1" @click="handleClick">
<template v-slot:header>
<div>I am a head</div>
</template>
<template v-slot:default>
<div>div</div>
</template>
<p>p</p>
<template>template</template>
</base-level>
Copy the code
The result of slots() is:
{
default: [<div>div</div>].header: [<div>I am a head</div>]}Copy the code
The results of children are:
[<div>div</div>, <p>p</p>, template]
Copy the code
Template-based functional components
In version 2.5.0 and above, if you use single-file components, template-based functional components can be declared as follows:
<template functional>
</template>
Copy the code
Transitions _ single element transitions
Vue provides a variety of different application transitions when inserting, updating, or removing the DOM.
Single element/component transitions
Vue provides a wrapper component for Transition, and you can add an entry/exit transition to any element or component in the following cases
- Conditional Rendering (using V-if)
- Conditional presentation (using V-show)
- Dynamic components
- Component root node
The class name of the transition
There are six class switches in the entry/exit transition.
- V – enter:
Define the beginning state of the transition. It takes effect before the element is inserted and is removed the next frame after the element is inserted.
- V – enter – active:
Defines the state in which the transition takes effect. Applied throughout the transition phase, before the element is inserted and removed after the transition/animation is complete. This class can be used to define the process time, delay, and curve functions that enter the transition.
- v-enter-to:
Define the end state of the transition (2.1.8+). The next frame takes effect after the element is inserted (the V-enter is removed at the same time) and removed after the transition/animation is complete.
- V – leave:
Define the beginning state of the exit transition. Immediately after the exit transition is triggered, the next frame is removed.
- V – leave – active:
Defines the state when the exit transition takes effect. Applies throughout the exit transition phase, takes effect immediately when the exit transition is triggered, and removes after the transition/animation is complete. This class can be used to define exit transition process time, delay and curve functions.
- v-leave-to:
Define the end state of the exit transition (2.1.8+). The next frame takes effect after the exit transition is triggered (and the V-leave is deleted at the same time), and is removed after the transition/animation is complete.
Here is:
The class name prefix
- Transition has no name feature
The class name is prefixed with v-.
- Transition has a name property
If name is fade, the class name prefix is fade-.
CSS animations
CSS animations are used in the same way as CSS, except that the v-Enter class name is not deleted immediately after the DOM is inserted, but when the AnimationEnd event is triggered.
Custom transition class name
We can customize the transition class name using the following attributes:
- enter-class
- enter-active-class
- Enter – to – class (2.1.8 +)
- leave-class
- leave-active-class
- Leave – to – class (2.1.8 +)
They take precedence over normal class names, which is useful when used in conjunction with Vue’s transition system and other third-party CSS animation libraries such as animation.css.
The Animate. CSS website address: daneden. Making. IO/Animate. CSS… NPM install animate. CSS –save
Use both transitions and animations
You can use the type attribute to declare the type that you want Vue to listen to. The type value can be animation or Transition.
When type is not set, both transitions and animationed take longer to end by default.
Explicit transition time
In some cases, Vue can automatically figure out when the transition effect is complete to process the DOM.
Sometimes, however, we set up a series of transition effects, such as nested elements that have transition effects that last longer than the parent element. At this point we can set the Duration property to customize an explicit transition duration in milliseconds:
<transition :duration="1000">.</transition>
Copy the code
You can also customize the duration of entry and removal:
<transition :duration="{ enter: 500, leave: 800 }">.</transition>
Copy the code
Transition from initial rendering
You can use appear Attribute to set the transition of the node in the initial rendering.
As with the in/out transition, you can also customize the CSS class name. Such as:
appear-class="appear-enter"
appear-active-class="appear-enter-active"
appear-to-class="appear-enter-to"
Copy the code
JavaScript hooks
JavaScript hooks can be declared in properties:
<transition
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter"
@enter-cancelled="enterCancelled"
@before-leave="beforeLeave"
@leave="leave"
@after-leave="afterLeave"
@leave-cancelled="leaveCancelled"
>
<! -... -->
</transition>
Copy the code
- Before the animation enters, you can set the start style of the element before the animation begins
- Enter animation in which you can write animation
- After the after-Enter animation is complete
- Enter-cancelled Cancels animation
Vue skips CSS detection by adding V-bind: CSS =”false” for elements that use JavaScript transitions only. This also avoids the impact of CSS during the transition.
The Transition component with the appear feature set also has custom JavaScript hooks:
<transition
appear
v-on:before-appear="customBeforeAppearHook"
v-on:appear="customAppearHook"
v-on:after-appear="customAfterAppearHook"
v-on:appear-cancelled="customAppearCancelledHook"
>
<! -... -->
</transition>
Copy the code
Combined with the Velocity. Js
NPM install velocity-animate
Transitions _ multielement transitions
When the label name of the element displayed in the switch is the same, you need to set a different key value for each element; otherwise, Vue will only replace the contents inside the same label for efficiency.
<transition>
<div v-if="show" key="world">hello world</div>
<div v-else key="shanshan">hello shanshan</div>
</transition>
Copy the code
In some scenarios, v-if and V-else can be replaced by setting different states for the key of the same element. Such as:
<transition>
<div :key="keyName">hello {{ key Name}}</div>
</transition>
Copy the code
keyName: 'world'.Copy the code
Transition mode
Vue provides a mode feature, which can apply different modes to multiple elements. The value of mode can be:
- In-out: The new element transitions first, and then the current element transitions away.
- Out-in: The current element transitions first, and then the new element transitions in.
Multicomponent transition
We can use dynamic component switching to show different components.
Transitions _ list transitions
When we want to add transition dynamic effects to a list, we can use the
Features of this component:
- Instead, it will be rendered as a real element: the default is one
<span>
. You can also use tag attributes for other elements. - Transition mode is not available because we no longer switch unique elements between each other.
- The inner element always needs to provide a unique value for the key attribute.
- CSS transitioning classes will be applied to internal elements, not the group/container itself.
Sort transitions for lists
The
Note: When removing a list element, you need to remove the element from the document flow. Otherwise, the element to overflow will remain in the document flow during the remove transition, affecting the move effect of subsequent elements.
Internal implementation: Vue uses a simple animation queue called FLIP that uses transforms to smooth the transition of elements from their previous positions into new ones.
Note that elements using FLIP transitions cannot be set to display: inline. Alternatively, it can be set to display: inline-block or placed in Flex.
Staggered transitions of lists
If you want to apply rich transitions to elements in a list, you can use JavaScript hooks.
Transition _ multiplexing transition
Transitions can be reused through Vue’s component system. To create a reusable transition component, all you need to do is place or as the root component, and then drop any child components into it.
Note: When using functional component reuse transitions, do not set CSS scopes.
Component_asynchronous Component
In the project, some components will not be loaded when entering the first screen for the first time, but will be loaded when certain operations are performed. Therefore, we can set the component to be loaded asynchronously at this time, and when it is used and loaded again, so as to improve the performance of the first screen.
Usage:
components: {
AsyncCmp: () = > import (url);
}
Copy the code
To combine multiple components that need to be loaded simultaneously into a single file:
components: {
AsyncCmp1: () = > import(/* webpackChunkName: "async" */ 'url'),
AsyncCmp2: () = > import(/* webpackChunkName: "async" */ 'url'),}Copy the code
For files loaded asynchronously, el=”prefech” will be set on the link tag. The browser will download the corresponding resources in idle time, and can directly obtain the resources from the cache. The corresponding el=”preload” will download the corresponding resource in time.
VueRouter_ basis
What is routing?
Routing displays different content or pages based on different URLS. In the early days, the back end reloaded the page according to the URL directly, that is, the back end controlled the route. Later the page is more and more complex, the server pressure is more and more, with the advent of Ajax (asynchronous refresh technology), the realization of the page can refresh data without overload, so that the front end can also control url self-management, front-end routing from this.
When to use front-end routing?
Front-end routing is more used in single-page applications, namely SPA(Single Page Web Application). In single-page applications, the results of most pages remain unchanged, but only the use of part of the content is changed.
Install the routing
NPM install vue-router.
Use the routing
JavaScript
- The introduction of the routing
import VueRouter from 'vue-router';
Copy the code
- Use the routing
Vue.use(VueRouter);
Copy the code
- Defining routing Components
// You can import from other files
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
Copy the code
- Define the routing
// Each route should map one component
const routes = [
{ path: '/foo'.component: Foo },
{ path: '/bar'.component: Bar }
]
Copy the code
- Create a Router instance and then pass it
routes
configuration
const router = new VueRouter({
routes
})
Copy the code
- Create and mount the root instance
const app = new Vue({
router
}).$mount('#app')
Copy the code
html
<div id="app">
<h1>Hello App!</h1>
<p>
<! -- Use the router-link component to navigate.
<! -- Specifies the link by passing in the 'to' attribute.
<! -- <router-link> will be rendered as a '<a>' tag by default.
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/bar">Go to Bar</router-link>
</p>
<! -- Route exit -->
<! -- Routing matching components will be rendered here -->
<router-view></router-view>
</div>
Copy the code