Vue3 - Basic

lvhanghmm 2021-06-17 11:02:28
vue3 vue basic


Catalog

install

take Vue.js There are three main ways to add to a project :

  1. On the page with CDN package The form of import .

    For prototyping or learning , You can use the latest version like this :

    <script src="https://unpkg.com/[email protected]"></script>
    
  2. download JavaScript Document and Since the escrow .

    If you want to avoid using build tools , But it can not be used in the production environment CDN, Then you can download the relevant information .js File and self hosting on your server . Then you can go through <script> Tags introduced , And use CDN Is similar to .`

  3. Use npm Install it .

    In use Vue Recommended for building large applications npm install [1] .NPM Can be very good with Webpack or Rollup Module packer used together .Vue Also provided is the compilation of Single file component The kit for .

    # Latest stable version
    $ npm install [email protected]
    
  4. Use official CLI To build a project , It provides fully functional build settings for modern front-end workflow ( for example , Hot heavy load 、 Tips for saving, etc ).

In use Vue Recommended for building large applications npm install [1] .NPM Can be very good with Webpack or Rollup Module packer used together .Vue Also provided is the compilation of Single file component The kit for .

# Latest stable version
$ npm install [email protected]

Vite

Vite It's a web Develop build tools , Because of its original ES Module import mode , Can achieve lightning cold server startup .

By running the following command in the terminal , have access to Vite Fast build Vue project .

Use npm:

$ npm init @vitejs/app <project-name>
$ cd <project-name>
$ npm install
$ npm run dev

yarn:

$ yarn create @vitejs/app <project-name>
$ cd <project-name>
$ yarn
$ yarn dev

Introduce

Vue.js What is it?

Vue ( pronunciation /vjuː/, Be similar to view) Is a set for building user interfaces Progressive framework . Unlike other large frameworks ,Vue Designed to be applied layer by layer from the bottom up .Vue The core library focuses only on the view layer , Not only easy to get started , It is also easy to integrate with third-party libraries or existing projects . On the other hand , When and Modern tool chain As well as a variety of Support library When used in combination ,Vue It is also fully capable of providing drivers for complex single-page applications .

If you want to learn in depth Vue I know more about it before , We Made a video , Take you to understand its core concepts and an example project .

start

The official guide assumes that you already know about HTML、CSS and JavaScript Intermediate knowledge . If you're just starting to learn front end development , Making the framework your first step may not be the best idea —— Master the basic knowledge and come back ! Previous experience with other frameworks will help , But it's not necessary

Try Vue.js The easiest way is to use Hello World Example , You can open it in the browser's new tab , Follow the examples to learn some basic usage .

Installation tutorial More installation Vue The way . Please note that we Not recommended Novices use it directly vue-cli, Especially if you are not familiar with the basis Node.js Build the tool .

Declarative rendering

Vue.js At its core is a simple template syntax that allows data to be rendered declaratively into the DOM The system of :

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://unpkg.com/[email protected]"></script>
</head>
<body>
<div id="counter">
Counter: {{ counter }}
</div>
<script>
const Counter = {
data () {
return {
counter: 0
}
}
}
Vue.createApp(Counter).mount("#counter")
</script>
</body>
</html>

We have successfully created the first Vue application ! It looks very similar to rendering a string template , however Vue A lot of work has been done behind the scenes . Now the data and DOM It's been linked , Everything is Responsive . How can we confirm ? Please see the following example , among counter property Incrementing per second , You'll see the rendered DOM How it changed :

 const Counter = {
data () {
return {
counter: 0
}
},
mounted () {
setInterval(() => {
this.counter++
}, 1000)
}
}

Except for text interpolation , We can also bind elements like this attribute:

<div id="counter">
<span v-bind:title="message">
message: title
</span>
</div>
 const Counter = {
data () {
return {
counter: 0,
message: 'lvhanghmm ' + new Date().toLocaleString()
}
}
}

Here we come across something new . What you see v-bind attribute go by the name of Instructions . Instructions are prefixed with v-, To show that they are Vue Special offers attribute. You may have guessed that , They're going to be rendering DOM Apply special responsive behavior on . ad locum , The directive means :“ This element node's title attribute And the current active instance of message property bring into correspondence with ”.

Processing user input

In order for users to interact with Applications , We can use v-on Instruction to add an event listener , It calls the method defined in the instance :

<div id="counter">
<p>{{message}}</p>
<input type="button" value=" reverse " v-on:click="reverseMessage">
</div>
 const Counter = {
data () {
return {
counter: 0,
message: 'Hello lvhanghmm!',
}
},
methods: {
reverseMessage () {
this.message = this.message
.split('') // split Is to convert a string into an array of individual elements !
.reverse()
.join('') // join Is to convert an array to a string !
}
}
}
Vue.createApp(Counter).mount("#counter")

Notice in this method , We updated the status of the app , But no touch DOM—— be-all DOM Operations are made by Vue To deal with it , The code you write just needs to focus on the logical level .

Vue It also provides v-model Instructions , It can easily achieve two-way binding between form input and application state .

<div id="counter">
<p>{{message}}</p>
<input v-model="message">
</div>
 const Counter = {
data () {
return {
counter: 0,
message: 'Hello lvhanghmm!',
}
},
methods: {
}
}
Vue.createApp(Counter).mount("#counter")

v-bind and v-model The difference is that -v-bind Binding is a native property !v-model Binding is a custom property !

Conditions and cycles

It's also quite easy to control whether an element is displayed or not

<div id="counter">
<span v-if="seen"> Now you see me !</span>
</div>
 const Counter = {
data () {
return {
seen: true,
message: 'Hello lvhanghmm!'
}
},
methods: {
}
}
Vue.createApp(Counter).mount("#counter")

This example demonstrates that we can not only bind data to DOM Text or attribute, You can also bind to DOM Of structure . Besides ,Vue It also provides a powerful transition effect system , Can be in Vue Insert / to update / Automatically apply when removing elements Transition effects .

You can put... In the sandbox below seen from true Change to false, To check the effect :

There are many other instructions , Each has a special function . for example ,v-for Instruction can bind array data to render a list of items :

<div id="counter">
<ol>
<li v-for="todo in todos">
{{todo.book}}
</li>
</ol>
</div>
 const Counter = {
data () {
return {
// seen: true,
message: 'Hello lvhanghmm!',
todos: [
{
book: 'JavaScript Advanced programming fourth edition '
},
{
book: ' Rhinoceros Seventh Edition '
},
{
book: 'xxxxxxxxx'
}
]
}
},
methods: {
}
}
Vue.createApp(Counter).mount("#counter")

Componentized application building

Component systems are Vue Another important concept of , Because it's an abstraction , Allow us to use small 、 Independent and often reusable components build large applications . Think carefully , Almost any type of application interface can be abstracted as a component tree :

stay Vue in , A component is essentially an instance with predefined options . stay Vue It's easy to register components in : If yes App Object to create a component object , And define it in the components In the options :

 // establish Vue application
const app = Vue.createApp(Counter)
// Definition is named todo-item The new component
<ol>
<!-- Create a todo-item Component instance -->
<todo-item></todo-item>
</ol>
// mount Vue application !
app.mount("#counter")

Now? , You can put it in the template of another component :

<ol>
<!-- Create a todo-item Component instance -->
<todo-item></todo-item>
</ol>

But this will render the same text for each to-do , It doesn't look cool . We should be able to transfer data from the parent component to the child component . Let's modify the definition of a component , Make it accept a prop

 // Definition is named todo-item The new component
app.component('todo-item', {
props: ['todo'],
template: `<li>{{todo.book}}</li>`
})

Now? , We can use v-bind Instruction passes the to-do item to each component of the loop output

<div id="counter">
<ol>
<!--
Now we're doing it for everyone todo-item Provide todo object
todo Objects are variables , That is, its content can be dynamic .
We also need to provide one for each component “key”, Later again
Explain in detail .
-->
<todo-item
v-for="item in todos"
v-bind:todos="item"
v-bind:key="item.id"
></todo-item>
</ol>
</div>
 const Counter = {
data () {
return {
// seen: true,
message: 'Hello lvhanghmm!',
todos: [
{
id: 1,
book: 'JavaScript Advanced programming fourth edition '
},
{
id: 2,
book: ' Rhinoceros Seventh Edition '
},
{
id: 3,
book: 'xxxxxxxxx'
}
]
}
},
methods: {
}
}
// establish Vue application
const app = Vue.createApp(Counter)
// Definition is named todo-item The new component
app.component('todo-item', {
props: ['todos'],
template: `<li>{{todos.book}}</li>`
})
// mount Vue application !
app.mount("#counter")

Although this is only an example of deliberate design , But we've managed to split the application into two smaller units . Subunit pass prop The interface is well decoupled from the parent unit . We can now further improve <todo-item> Components , Provide more complex templates and logic , Without affecting the parent app .

In a large application , It is necessary to divide the whole application into several components , To make development easier to manage . stay Follow up tutorials We'll go into the components , But here's one ( A hypothetical ) Example , To show what an application template looks like with components :

<div id="app">
<app-nav></app-nav>
<app-view>
<app-sidebar></app-sidebar>
<app-content></app-content>
</app-view>
</div>

Relationship with custom elements

You may have noticed Vue Components are very similar to custom elements —— It is Web Component specifications Part of , This is because Vue The component syntax section of refers to the specification . for example Vue Component implementation Slot API And is attribute. however , There are still a few key differences :

  1. Web Components The specification has been completed and passed , But it's not native to all browsers . at present Safari 10.1+、Chrome 54+ and Firefox 63+ Native support Web Components. by comparison ,Vue Components don't need any polyfill, And in all supported browsers (IE11 And higher ) It's the same thing . When necessary, ,Vue Components can also be wrapped in native custom elements .

  2. Vue Components provide some important functions that pure custom elements don't have , The most prominent is cross component data flow 、 Custom event communication and build tool integration .

although Vue No custom elements are used internally , But using custom elements in applications 、 Or in the form of custom elements , There's still good interoperability .Vue CLI Support will also be given to Vue Components build into native custom elements .

application & Component instance

Create an application instance

Every Vue Applications are all through createApp Function to create a new Application example At the beginning :

const app = Vue.createApp({
/* Options */
}

The application instance is used to register in the application “ overall situation ” Component's . We will discuss it in detail in the guide later , A simple example :

 const app = Vue.createApp({})
app.component('SearchInput', SearchInput)
app.directive('focus', FocusDirective)
app.use(LocalPlugin)

Most methods exposed by the application instance will return the same instance , Allow chaining :

 Vue.createApp({})
.component('SearchInput', SearchInput)
.directive('focus', FocusDirective)
.use(LocalPlugin)

The root component

Pass to createApp For configuration The root component . When we mount When applied , This component is used as the starting point for rendering .

An application needs to be mounted to a DOM In the elements . for example , If you want to put one Vue Application mount to <div id="app"></div>, It should be introduced #app

 const rootComponent = {
/* Options */
}
const app = Vue.createApp(rootComponent)
const vm = app.mount('#app')

Different from most application methods ,mount Do not return the application itself . contrary , It returns the root component instance .

Although not completely followed MVVM Model , however Vue It's also inspired the design of . So it's often used in documents vm (ViewModel Abbreviation ) This variable name represents the component instance .

Although all the examples on this page only need a single component , But most real-world applications are organized into a nest 、 Reusable component tree . for instance , One todo The application component tree might look like this :

Root Component
└─ TodoList
├─ TodoItem
│ ├─ DeleteTodoButton
│ └─ EditTodoButton
└─ TodoListFooter
├─ ClearTodosButton
└─ TodoListStatistics

Each component will have its own component instance vm. For some components , Such as TodoItem, There can be multiple instances rendering at any time . All component instances in this application will share the same application instance .

We'll be back later Component basis Chapter specific development . But now, , You just need to understand that the root component is no different from other components , The configuration options are the same , The behavior of the corresponding component instance is the same .

Component instance property

In the previous guide , We know each other data property. stay data As defined in property Is exposed through component instances :

 const app = Vue.createApp({
data () {
return {
count: 4
}
}
})
const vm = app.mount('#app')
console.log(vm.count); // 4

There are a variety of other component options , User defined property Add to component instance , for example methods,props,computed,inject and setup. We'll talk about them in depth in a later guide . All components of a component instance property, Define... Anyway , Can be accessed in the template of the component .

Vue Some built-in components are also exposed through component instances property, Such as $attrs and $emit. these property There is one. $ Prefix , To avoid conflicts with user-defined property Name conflict .

Lifecycle hook

Each component has to go through a series of initialization processes when it is created —— for example , Data monitoring needs to be set 、 Compiling templates 、 Mount the instance to DOM And update when the data changes DOM etc. . At the same time, in this process, we will also run something called Lifecycle hook Function of , This gives users the opportunity to add their own code at different stages .

such as created Hooks can be used to execute code after an instance is created :

 const app = Vue.createApp({
data () {
return {
count: 4
}
},
created () {
// `this` Point to vm example
console.log('count is: ' + this.count)
}
})
const vm = app.mount('#app')

There are also some other hooks , Called at different stages of the instance lifecycle , Such as mountedupdated and unmounted. Life cycle hook's this The context points to the current active instance that calls it .

Don't be in the options property Or callback Arrow function , such as created: () => console.log(this.a) or vm.$watch('a', newValue => this.myMethod()). Because the arrow function does not this,this Will always look up the parent lexical scope as a variable , Until it's found , Often leads to Uncaught TypeError: Cannot read property of undefined or Uncaught TypeError: this.myMethod is not a function Or something like that .

Lifecycle diagram

Official picture :

The figure below is provided by blog users pachulia Provided Vue2 Life cycle function diagram of

Template syntax

Vue.js Based on HTML Template syntax for , Allow developers to declaratively put DOM Data bound to the underlying component instance . all Vue.js The templates are all legal HTML, So browsers and HTML Parser parsing .

At the bottom of the implementation ,Vue Compile the template into a virtual DOM Rendering function . Combined with responsive system ,Vue Be able to intelligently calculate the minimum number of components that need to be re rendered , And put DOM Minimize the number of operations .

If you are familiar with virtual DOM And prefer JavaScript The original power of , You can also use no templates , Write directly to render (render) function , Use optional JSX grammar .

interpolation

Text

The most common form of data binding is to use “Mustache” grammar ( Double brace ) Text interpolation of :

<span>Message: {{ msg }}</span>

Mustache The tag will be replaced by the corresponding component instance msg property Value . No matter when , On the bound component instance msg property It has changed , The interpolation will be updated .

By using v-once Instructions , You can also perform one-time interpolation , When data changes , The interpolation will not update . But be aware that this will affect other data bindings on this node :

<span v-once> This will not change : {{ msg }}</span>

original HTML

Double braces interpret the data as plain text , Instead of HTML Code . In order to output the real HTML, You need to use v-html Instructions

<p>Using mustaches: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
data () {
return {
count: 4,
msg: 'lvhanghmm',
rawHtml: `<h1> I am a h1 label </h1>`
}
}

This span Will be replaced by property value rawHtml, Act directly as HTML—— Will ignore parsing property Data binding in values . Be careful , You can't use v-html To compound the local template , because Vue It's not a string based template engine . conversely , For the user interface (UI), Components are more suitable as reusable and composable basic units .

Dynamically render any image on your site HTML It's very dangerous , Because it can easily lead to XSS attack . Please use... Only for trusted content HTML interpolation , Never The content provided by users is used as interpolation .

Attribute

Mustache Grammar can't be in HTML attribute Use in , However , have access to v-bind Instructions

 <p v-bind:class="cla1">Using mustaches: {{ rawHtml }}</p>
 data () {
return {
count: 4,
msg: 'lvhanghmm',
rawHtml: `<h1> I am a h1 label </h1>`,
cla1: 'lvhanghmm'
}
}

If the value of the binding is null or undefined, Then the attribute Will not be included on the rendered element .

For boor attribute ( They are worth as long as they exist true),v-bind Work a little different , In this case :

<button v-bind:disabled="isButtonDisabled"> Button </button>

If isButtonDisabled The value of is truthy[1], that disabled attribute Will be included . If the value is an empty string , It will also be included , And <button disabled=""> bring into correspondence with . For other wrong values , The attribute Will be omitted .

Use JavaScript expression

so far , In our template , We've always bound simple property Key value . But actually , For all data bindings ,Vue.js All provide complete JavaScript Expressions support .

<div id="app">
<p>{{ number + 1 }}</p>
<p>{{ ok ? "YES" : "NO" }}</p>
<p>{{ msg.split('').reverse().join('') }}</p>
<p v-bind:id="'list' + id"> I am a p label </p>
</div>
 const app = Vue.createApp({
data () {
return {
msg: 'lvhanghmm',
id: 'lvchengxin',
ok: false,
number: 5894
}
},
methods: {
setMsg: function () {
console.log(123)
}
}
})
const vm = app.mount('#app')

These expressions are used in the data scope of the current active instance as JavaScript Be resolved . One limitation is , Each binding can only contain A single expression , So the following examples are all Can't take effect .

<!-- This is the statement , It's not an expression :-->
{{ var a = 1 }}
<!-- Flow control will not work , Please use ternary expression -->
{{ if (ok) { return message } }}

Instructions

Instructions (Directives) It's with v- Special prefixes attribute. Instructions attribute The expected value of is Single JavaScript expression (v-for and v-on It's an exception , Let's talk about it later ). The duty of the order is , When the value of an expression changes , The joint and several effects of it , Act responsibly on DOM. Review the examples we saw in the introduction :

<p v-if="seen"> Now you see me </p>

here ,v-if The instruction will be based on the expression seen The value of true or false to insert / remove <p> Elements .

Parameters

Some instructions can receive a “ Parameters ”, After the instruction name, indicate with a colon . for example ,v-bind Instructions can be used to update... In response HTML attribute:

<a v-bind:href="url"> ... </a>

ad locum href Is the parameter , inform v-bind The command will change the href attribute And the expression url Value binding for .

Another example is v-on Instructions , It's used to monitor DOM event :

<a v-on:click="doSomething"> ... </a>

Here, the parameter is the name of the listening event . We'll also discuss event handling in more detail .

Dynamic parameters

It can also be used in instruction parameters JavaScript expression , The method is to use square brackets :

<!--
Be careful , There are some constraints in the way parameter expressions are written , As follows “ Constraints on dynamic parameter expressions ” As described in section .
-->
<a v-bind:[attributeName]="url"> ... </a>

there attributeName Will be treated as a JavaScript Expressions are evaluated dynamically , The resulting value will be used as the final parameter . for example , If your component instance has a data property attributeName, Its value is "href", So this binding will be equivalent to v-bind:href.

similarly , You can use dynamic parameters to bind handler functions for a dynamic event name :

<a v-on:[eventName]="doSomething"> ... </a>

In this example , When eventName The value of is "focus" when ,v-on:[eventName] Will be equivalent to v-on:focus

Modifier

Modifier (modifier) It's half a period . Specified special suffix , Used to indicate that an instruction should be bound in a special way . for example ,.prevent Modifier tell v-on The instruction calls... For the triggered event event.preventDefault()

 <from v-on:submit.prevent="onSubmit">...</from>

Next, I'm going to v-on and v-for And so on , You'll see other examples of modifiers .

abbreviation

v- Prefix as a visual cue , Used to identify... In the template Vue specific attribute. When you are using Vue.js Add dynamic behavior to existing tags (dynamic behavior) when ,v- Prefixes help a lot , However , For some frequently used instructions , You'll feel cumbersome to use . meanwhile , In building by Vue Single page application that manages all templates (SPA - single page application) when ,v- Prefixes have become less important . therefore ,Vue by v-bind and v-on These two most commonly used instructions , Provides a specific abbreviation :

v-bind abbreviation

<!-- Complete grammar -->
<a v-bind:href="url"> ... </a>
<!-- abbreviation -->
<a :href="url"> ... </a>
<!-- Short for dynamic parameters -->
<a :[key]="url"> ... </a>

v-on abbreviation

<!-- Complete grammar -->
<a v-on:click="doSomething"> ... </a>
<!-- abbreviation -->
<a @click="doSomething"> ... </a>
<!-- Short for dynamic parameters (2.6.0+) -->
<a @[event]="doSomething"> ... </a>

They may look like ordinary HTML It's a little different , but : And @ about attribute Names are legal characters , In all support Vue All browsers can be parsed correctly . and , They don't appear in the final render tag . Abbreviation syntax is completely optional , But as you learn more about what they do , You'll be glad to have them .

Start on the next page , We will use abbreviations in the example , Because this is Vue The most common usage of developers .

matters needing attention

For dynamic parameter value conventions

Dynamic parameters are expected to find a string , In case of abnormality, the value is null. This special null Values can be explicitly used to remove bindings . Any other non string value will trigger a warning .

For dynamic parameter expression conventions

Dynamic parameter expressions have some syntax constraints , Because some characters , Like spaces and quotes , Put it in HTML attribute The name is invalid . for example :

<!-- This triggers a compilation warning -->
<a v-bind:['foo' + bar]="value"> ... </a>

The alternative is to use expressions without spaces or quotation marks , Or use Compute properties Replace this complex expression .

stay DOM When using templates in ( Directly in a HTML Writing templates in the document ), You also need to avoid using uppercase characters to name keys , Because the browser will attribute All names are forced to lowercase :

<!--
stay DOM When using templates in, this code is converted to `v-bind:[someattr]`.
Unless there's one in the instance called “someattr” Of property, Otherwise, the code won't work .
-->
<a v-bind:[someAttr]="value"> ... </a>

JavaScript expression

Template expressions are placed in sandbox , Only access A white list of global variables , Such as Math and Date. You should not try to access user-defined global variables in template expressions .

Data Property And methods

Data Property

Component's data Option is a function .Vue This function is called in the process of creating new component instances . It should return an object , then Vue It's wrapped up in a responsive system , And $data Is stored in the component instance . For convenience , Any top level of the object property It is also exposed directly through component instances :

 const app = Vue.createApp({
data () {
return {
count: 4
}
}
})
const vm = app.mount('#app')
console.log(vm.$data.count); // 4
console.log(vm.count); // 4
// modify vm.count The value of will also be updated $data.count
vm.count = 5
console.log(vm.$data.count) // => 5
// vice versa
vm.$data.count = 6
console.log(vm.count) // => 6

These examples property Is added only when the instance is first created , So you need to make sure they're all there data In the object returned by the function . When necessary, , To update a property Use nullundefined Or other values of the occupancy .

Directly not included in data New in property Adding to a component instance is possible . But because of the property Responsive style without behind $data In object , therefore Vue Responsive system based on It won't automatically track it .

Vue Use $ Prefixes expose their built-in properties through component instances API. It also serves the interior property Retain _ Prefix . You should avoid using the top level at the beginning of these two characters data property name .

Method

We use it methods Option to add a method to a component instance , It should be an object that contains the required methods :

 const app = Vue.createApp({
data() {
return { count: 4 }
},
methods: {
increment() {
// `this` Point to the component instance
this.count++
}
}
})
const vm = app.mount('#app')
console.log(vm.count) // => 4
vm.increment()
console.log(vm.count) // => 5

Vue Automatically for methods binding this, So that it always points to the component instance . This will ensure that the method remains correct when used as an event listener or callback this Point to . In defining methods You should avoid using arrow functions when using , Because it will stop Vue Bind properly this Point to .

these methods And all other components of the component instance property It can also be accessed in the template of the component . In the template , They are usually used as event listeners :

<button @click="increment">Up vote</button>

In the example above , Click on <button> when , Would call increment Method .

You can also invoke the method directly from the template. . As you'll see in the next chapter , Usually change to Compute properties Will be better . however , In the case that calculating attributes is not feasible , How to use it can be useful . You can support it in the template JavaScript The method is called anywhere in the expression :?!

<span :title="toTitleDate(date)">
{{ formatDate(date) }}
</span>

If toTitleDate or formatDate Access any responsive data , Then track it as a rendering dependency , It's like using it directly in a template .

Methods called from templates should not have any side effects , Such as changing data or triggering asynchronous processes . If you want to do this , It should be changed Lifecycle hook .

Anti shake and throttling

Vue No built-in support for anti shake and throttling , But you can use Lodash Wait for the library to implement .

If a component is used only once , Can be in methods In the application of anti shake :

<script src="https://unpkg.com/[email protected]/lodash.min.js"></script>
<script>
Vue.createApp({
methods: {
// use Lodash The anti shake function of
click: _.debounce(function() {
// ... Response Click ...
}, 500)
}
}).mount('#app')
</script>

however , This approach has potential problems with reusable components , Because they all share the same anti shake function . To make component instances independent of each other , You can hook in the life cycle created Add the anti shake function in the :

app.component('save-button', {
created() {
// use Lodash The anti shake function of
this.debouncedClick = _.debounce(this.click, 500)
},
unmounted() {
// When removing components , Cancel timer
this.debouncedClick.cancel()
},
methods: {
click() {
// ... Response Click ...
}
},
template: `
<button @click="debouncedClick">
Save
</button>
`
})

Compute properties and listeners

Compute properties

The expressions in the template are very convenient , But they were designed for simple computation . Putting too much logic in a template makes it too heavy and difficult to maintain . for example , There is a nested array object :

Vue.createApp({
data() {
return {
author: {
name: 'John Doe',
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'
]
}
}
}
})

We want to author Are there any books showing different messages

<div id="computed-basics">
<p>Has published books:</p>
<span>{{ author.books.length > 0 ? 'Yes' : 'No' }}</span>
</div>

here , Templates are no longer simple and declarative . You have to look at it first , And then realize that the computation it performs depends on author.books. If you want to include this calculation multiple times in the template , The problem will get worse .

therefore , For any complex logic that contains responsive data , You should use Compute properties .

Basic examples

<div id="app">
<p>Has published books:</p>
<span>{{ publishedBookMessage }}</span>
</div>
const vm = {
data() {
return {
author: {
name: 'John Doe',
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'
]
}
}
},
computed: {
// Computed attribute getter
publishedBookMessage() {
// this perform vm example
return this.author.books.length > 0 ? 'YES' : 'NO'
}
}
}
const app = Vue.createApp(vm)
app.mount('#app')

A calculated property is declared here publishedBooksMessage.

Try changing the application data in books The value of the array , You will see publishedBooksMessage How to change it accordingly .

You can bind data to a calculated property in a template just like a normal property .Vue know vm.publishedBookMessage Depend on vm.author.books, So when vm.author.books When there is a change , All dependence vm.publishedBookMessage The binding of will also be updated . And best of all, we've created this dependency in a declarative way : Computed attribute getter Function has no side effects , It's easier to test and understand .

Compute property cache VS Method

You may have noticed that we can achieve the same effect by calling the method in the expression :

<p>{{ calculateBooksMessage() }}</p>
// In components
methods: {
calculateBooksMessage() {
return this.author.books.length > 0 ? 'Yes' : 'No'
}
}

We can define the same function as a method instead of a calculated property . The end result of the two ways is exactly the same . However , The difference is Computed properties are cached based on their reaction dependencies . Computed properties are revalued only when the related responsive dependency changes . This means that as long as author.books It hasn't changed , Multiple access publishedBookMessage The calculated property will immediately return the previous calculation result , Instead of executing the function again .

This also means that the following calculated properties will not be updated , because Date.now () Not reactive dependency :

computed: {
now() {
return Date.now()
}
}

by comparison , Whenever re rendering is triggered , Call method will always execute function again .

Why do we need caching ? Let's say we have a computing property with high performance overhead list, It needs to traverse a huge array and do a lot of calculations . Then we may have other computational properties that depend on list. If there is no cache , We will inevitably carry out many times list Of getter! If you don't want a cache , Please use method To replace .

Computed attribute Setter

The default calculation property is getter, But you can also provide a setter:

// ...
computed: {
fullName: {
// getter
get() {
return this.firstName + ' ' + this.lastName
},
// setter
set(newValue) {
const names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
// ...

Now run vm.fullName = 'John Doe' when ,setter Will be called ,vm.firstName and vm.lastName Will also be updated accordingly .

The listener

Although calculating properties is more appropriate in most cases , But sometimes you need a custom listener . That's why Vue adopt watch Options provide a more general approach , To respond to changes in data . When you need to perform asynchronous or expensive operations when data changes , This way is the most useful .

for example :

<div id="app">
<p>
Ask a yes/no question:
<input v-model="question" />
</p>
<p>{{ answer }}</p>
</div>
<!-- because AJAX The ecology of libraries and general tools is already quite rich ,Vue The core code is not duplicated -->
<!-- Provide these features to keep things simple . It also gives you the freedom to choose tools you are more familiar with . -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/axios.min.js"></script>
<script>
const vm = {
data() {
return {
question: '',
answer: 'Questions usually contain a question mark. ;-)'
}
},
watch: {
// whenever question changes, this function will
question (newQuestion, oldQuestion) {
if (newQuestion.indexOf('?') > -1) {
this.getAnswer()
}
}
},
methods: {
getAnswer () {
this.answer = 'Thinking...'
axios
.get('https://yesno.wtf/api')
.then(response => {
this.answer = response.data.answer
})
.catch(error => {
this.answer = 'Error! Could not reach the API. ' + error
})
}
}
}
const app = Vue.createApp(vm)
app.mount('#app')
</script>

In this example , Use watch Option allows us to perform asynchronous operations ( Visit one API), Limit how often we do this , And before we get the final result , Set intermediate state . These are all things that computational properties can't do .

except watch Beyond the options , You can also use imperative vm.$watch API.

Compute properties vs The listener

Vue Provides a more general way to observe and respond to data changes on current active instances : Listening properties . When you have some data that needs to change with other data , It's easy for you to abuse watch—— Especially if you've used AngularJS. However , It's usually better to use calculated properties rather than imperative watch Callback . Think about this example :

<div id="demo">{{ fullName }}</div>
 const vm = {
data() {
return {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
}
},
watch: {
firstName (val) {
this.fullName = val + ' ' + this.lastName
},
lastName(val) {
this.fullName = this.firstName + ' ' + val
}
},
}
const app = Vue.createApp(vm)
app.mount('#app')

The above code is imperative and repetitive . Compare it with the version of the calculated property :

 const vm = {
data() {
return {
firstName: 'Foo',
lastName: 'Bar',
}
},
computed: {
fullName () {
return this.firstName + " " + this.lastName
}
}
}
const app = Vue.createApp(vm)
app.mount('#app')

Much better , isn't it? ?

Class And Style binding

Operating elements class Lists and inline styles are a common requirement for data binding . Because they are all attribute, So we can use v-bind Deal with them : You just need to calculate the string result through the expression . however , String splicing is troublesome and error prone . therefore , Will be v-bind be used for class and style when ,Vue.js Made a special enhancement . The type of expression result is in addition to string , It can also be an object or an array .

binding HTML Class

Object syntax

We can pass it on :class (v-bind:class Abbreviation ) An object , To switch dynamically class:

<div :class="{ active: isActive }"></div>

The above syntax active This class Whether it exists or not will depend on the data property isActive Of truthiness.

You can pass in more fields in the object to dynamically switch multiple class. Besides ,:class Instructions can also be compared with ordinary class attribute coexistence . When there are the following templates :

You can pass in more fields in the object to dynamically switch multiple class. Besides ,:class Instructions can also be compared with ordinary class attribute coexistence . When there are the following templates :

<div id="app">
<div
class="static"
:class="{ active: isActive, lvhanghmm: isLvchengxin}"
></div>
</div>

And the following data:

data() {
return {
isActive: true,
isLvchengxin: true
}
}

The rendered result is :

<div class="static active lvhanghmm"></div>

When isActive perhaps lvhanghmm When the change ,class The list will be updated accordingly . for example , If lvhanghmm The value of is true,class The list will change to "static active lvhanghmm".

Bound data objects do not need to be defined inline in the template :

<div
class="static"
:class="classObject"
></div>
data() {
return {
classObject: {
isActive: false,
lvhanghmm: true
}
}
}

The rendered result is the same as above . We can also bind a return object here Compute properties . This is a common and powerful model :

<div
class="static"
:class="classObject"
></div>
data() {
return {
isActive: true,
error: null
}
},
computed: {
classObject () {
return {
active: this.isActive && !this.error,
lvhanghmm: this.error && this.error.type === 'fatal'
}
}
}

Array syntax

We can pass an array to :class, To apply a class list :

<div :class="[activeClass, errorClass]"></div>
data() {
return {
activeClass: 'lvhanghmm',
errorClass: 'lvchengxin'
}
}

The rendered result is :

<div class="lvhanghmm lvchengxin"></div>

If you want to switch between the class, You can use ternary expressions :

<div :class="[isActive ? activeClass : '', errorClass]"></div>
data() {
return {
activeClass: 'dapeng',
isActive: true,
errorClass: 'lvchengxin'
}
}

This will always add errorClass, But only in isActive by truthy[1] Only add activeClass.【 I changed the chestnut , Now both will be displayed !】

however , When there are multiple conditions class It's a little tedious to write like this . So you can also use object syntax in array syntax :

<div :class="[{ active: isActive }, errorClass]"></div>

Use... On components

This chapter assumes that you've learned about Vue Components Have some understanding . Of course, you can also skip here first , Come back later .

When you use it on a custom component with a single root element class attribute when , these class Will be added to the element . Existing on this element class It will not be overwritten .

for example , If you declare this component :

const app = Vue.createApp(vm)
app.component('my-component', {
template: `<p class="foo bar">Hi!</p>`
})
app.mount('#app')

Then add some... When using it class:

<my-component class="baz boo"></my-component>

HTML Will be rendered as :

<p class="foo bar baz boo">Hi</p>

For with data binding class The same applies :

<my-component :class="{ active: isActive }"></my-component>
data() {
return {
isActive: true,
}
}
<p class="foo bar active">Hi</p>

If your component has more than one root element , You need to define which parts will receive this class . have access to $attrs Component properties perform this operation :

<div id="app">
<my-component class="baz"></my-component>
</div>
const vm = {
data() {
return {
isActive: true,
}
}
}
const app = Vue.createApp(vm)
app.component('my-component', {
template: `
<p :class="$attrs.class">Hi!</p>
<span>This is a child component</span>
`
})
app.mount('#app')

You can Not prop Attribute Section to learn more about component property inheritance .

Binding inline styles

Object syntax

:style Object syntax of —— It looks very similar CSS, But it's actually a JavaScript object .CSS property The name can be humped (camelCase) Or a short horizontal line (kebab-case, Remember to put it in quotation marks ) Named after the :

<div :style="{ color: activeColor, fontSize: fontSize + 'px' }">lvhanghmm</div>
data() {
return {
activeColor: 'red',
fontSize: 30
}
}

It's usually better to bind directly to a style object , This will make the template clearer :

<div :style="styleObject">lvhanghmm</div>
data() {
return {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
}

alike , Object syntax is often used in conjunction with the computed properties of the returned object

Array syntax

<div :style="[baseStyles, overridingStyles]">lvhanghmm</div>
data() {
return {
baseStyles: {
color: 'red',
fontSize: '30px'
},
overridingStyles: {
height: '300px',
width: '300px',
backgroundColor: 'pink'
}
}
}

Automatically prefix

stay :style Need to use in ( Browser engine prefix ) vendor prefixes Of CSS property when , Such as transform,Vue Will automatically detect and add the corresponding prefix .

Multiple values

It can be for style In binding property Provides an array of multiple values , Often used to provide multiple prefixed values , for example :

<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>

This will only render the last browser supported value in the array . In this case , If the browser supports flexbox, Then it will only render display: flex.

Conditions apply colours to a drawing

v-if

v-if Instructions are used to conditionally render a piece of content . This will only return... In the expression of the instruction truthy It's rendered when it's worth .

<h1 v-if="awesome">Vue is awesome!</h1>

It can also be used. v-else Add one “else block ”:

<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no </h1>

stay template Use on element v-if Conditional rendering groups

because v-if It's an instruction , So you have to add it to an element . But if you want to switch multiple elements ? At this time, you can put a <template> Element as invisible wrap element , And use it on it v-if. The final rendering result will not contain <template> Elements .

<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>

The code above will not be displayed , because ok Variables are not defined , Its value is false

v-else

You can use v-else Order to express v-if Of “else block ”:

<div v-if="Math.random() > 0.5">
Now you see me
</div>
<div v-else>
Now you don't
</div>

v-else The elements must be followed by v-if perhaps v-else-if After the element of , Otherwise it will not be recognized .

v-else-if

v-else-if, seeing the name of a thing one thinks of its function , act as v-if Of “else-if block ”, And it can be used continuously :

<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>

And v-else The usage of is similar to ,v-else-if We must also keep up with it v-if perhaps v-else-if After the elements of .

v-show

Another option for conditionally displaying elements is v-show Instructions . The usage is about the same :

<h1 v-show="ok">Hello!</h1>

The difference is that with v-show Elements of are always rendered and remain in the DOM in .v-show Simply switching elements CSS property display.

Be careful ,v-show I won't support it <template> Elements , Nor does it support v-else.

v-if VSv-show

v-if yes “ real ” Conditional rendering , Because it will ensure that in the switching process , The event listeners and subcomponents in the condition block are properly destroyed and rebuilt .

v-if It's also The inertia of the : If the condition is false at the initial render , And do nothing —— Until the condition is true for the first time , Before the condition block is rendered .

by comparison ,v-show It's much simpler —— Whatever the initial conditions are , Elements are always rendered , And simply based on CSS Switch .

Generally speaking ,v-if There is higher switching overhead , and v-show There is a higher initial rendering overhead . therefore , If you need to switch very frequently , Then use v-show good ; If conditions rarely change at run time , Then use v-if good

v-if And v-for Use it together

Tips

Not recommended Use at the same time v-if and v-for. Please refer to Style guide For more information .

When v-if And v-for When used together ,v-if Ratio v-for Higher priority . Please refer to List rendering Guide For details .

The list of rendering

use v-for An array is mapped to a set of elements

We can use v-for The command renders a list based on an array .v-for Instruction needs to be used item in items Special syntax of form , among items It's an array of source data , and item Is the iterated array element Alias .

 <div id="app">
<ul>
<li v-for="item in items">
{{ item.message }}
</li>
</ul>
</div>
 const vm = {
data() {
return {
items: [{ message: 'Foo' }, { message: 'Bar' }]
}
}
}
const app = Vue.createApp(vm)
app.mount('#app')

result :

stay v-for In block , We can access all of the parent scope's property.v-for An optional second parameter is also supported , That is, the index of the current item .

 <div id="app">
<ul>
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
</ul>
</div>
 data() {
return {
parentMessage: 'Parent',
items: [{ message: 'Foo' }, { message: 'Bar' }]
}
}

You can also use it of replace in As a separator , Because it's closer to JavaScript Iterator syntax :

 <li v-for="(item, index) of items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>

stay v-for The object used in

You can also use it v-for To traverse an object's property.

 <div id="app">
<ul>
<li v-for="(item, index) of myObject">
{{ index }} + {{ item }}
</li>
</ul>
</div>
 const vm = {
data() {
return {
myObject: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
}
}
const app = Vue.createApp(vm)
app.mount('#app')

result :

You can also provide the second parameter as property name ( That's the key name key):

It's shown above , You can see that I use the chestnut cycle in front directly !

Now let me change it !

You can also use the third parameter as an index :

<li v-for="(value, name, index) in myObject">
{{ index }}. {{ name }}: {{ value }}
</li>

Tips

When traversing objects , Will press Object.keys() Result traversal of , But there's no guarantee it's different JavaScript The results are consistent under the engine .

Maintenance state

When Vue Updating usage v-for When rendering a list of elements , It uses by default “ in-place update ” The strategy of . If the order of data items is changed ,Vue Will not move DOM Element to match the order of data items , Instead, each element is updated in place , And make sure they render correctly at each index location .

This default mode is efficient , however Only applicable to non dependent sub component status or temporary DOM state ( for example : Form input value ) List render output for .

To give Vue A hint , So that it can track the identity of each node , To reuse and reorder existing elements , You need to provide a unique key attribute:

<div v-for="item in items" :key="item.id">
<!-- content -->
</div>

It is recommended to use as much as possible v-for Provide time key attribute, Unless traversing the output DOM It's very simple , Or deliberately rely on default behavior for performance improvement .

Because it is Vue A general mechanism for identifying nodes ,key It's not just with v-for Special relevance . We'll see later in the guide , It also has other uses .

Tips

Don't use non primitive type values such as objects or arrays as v-for Of key. Please use a value of string or numeric type .

Array update detection

Change method

Vue Wrapped the change method of the array being listened on , So they will also trigger view updates . These wrapped methods include :

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

You can turn on the console , And then for the previous example items Array tries to call the change method . such as example1.items.push({ message: 'Baz' }).

【 Don't understand, !】

Replace array

Change method , seeing the name of a thing one thinks of its function , Will change the original array that called these methods . by comparison , There are also non change methods , for example filter()concat() and slice(). They don't change the original array , and Always return a new array . When using the non change method , You can replace the old array with a new array :

example1.items = example1.items.filter(item => item.message.match(/Foo/))

You may think that this will lead to Vue Discard the existing DOM And re render the entire list . Fortunately, , This is not the case .Vue In order to make DOM Elements are reused to the maximum extent, and some intelligent heuristics are implemented , So it is very efficient to replace the original array with an array containing the same elements

Display filtering / The result after sorting

Sometimes , We want to display a filtered or sorted version of an array , Without actually changing or resetting the original data . under these circumstances , You can create a calculated property , To return the filtered or sorted array .

for example :

<li v-for="n in evenNumbers" :key="n">{{ n }}</li>
 data() {
return {
numbers: [ 1, 2, 3, 4, 5 ]
}
},
computed: {
evenNumbers() {
// Returns an even array !
return this.numbers.filter(number => number % 2 === 0)
}
}

In cases where the calculated property is not applicable ( for example , In nesting v-for In circulation ) You can use a method :

 <div id="app">
<ul v-for="numbers in sets">
<li v-for="n in even(numbers)" :key="n">{{ n }}</li>
</ul>
</div>
 const vm = {
data() {
return {
sets: [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
}
},
methods: {
even(numbers) {
return numbers.filter(number => number % 2 === 0)
}
},
}
const app = Vue.createApp(vm)
app.mount('#app')

stay v-for Range of values used in

v-for You can also accept integers . under these circumstances , It will repeat the template for the corresponding number of times .

 <div id="app">
<span v-for="n in 10" :key="n">{{ n }} </span>
</div>

stay template Use in v-for

Be similar to v-if, You can also take advantage of the v-for Of <template> To loop through a piece of content that contains multiple elements . such as :

<ul>
<template v-for="item in items" :key="item.msg">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>

v-for And v-if Use together

TIP

Pay attention to us No It is recommended to use... On the same element v-if and v-for. More details can be found in Style guide .

When they are at the same node ,v-if The priority ratio v-for Higher , It means v-if You will not have access v-for Variables in :

<!-- This will throw an error because property "todo" is not defined on instance. -->
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo.name }}
</li>

You can put v-for Move to <template> Tag to correct :

<template v-for="todo in todos" :key="todo.name">
<li v-if="!todo.isComplete">
{{ todo.name }}
</li>
</template>

Use... On components v-for

This part assumes that you already know Components Related knowledge . You can also skip it first , Come back later to check .

On custom components , You can use it just like on any normal element v-for

<my-component v-for="item in items" :key="item.id"></my-component>

However , No data is automatically passed to the component , Because components have their own independent scopes . To pass iteration data to components , We're going to use props:

<my-component
v-for="(item, index) in items"
:item="item"
:index="index"
:key="item.id"
></my-component>

Not automatically item The reason for injection into the component is , This makes the component and v-for The operation of is tightly coupled . Identifying the source of component data enables components to be reused in other situations .

Here's a simple one todo A complete example of the list :

<div id="app">
<form v-on:submit.prevent="addNewTodo">
<label for="new-todo">Add a todo</label>
<input
v-model="newTodoText"
id="new-todo"
placeholder="E.g. Feed the cat"
/>
<button>Add</button>
</form>
<ul>
<todo-item
v-for="(todo, index) in todos"
:key="todo.id"
:title="todo.title"
@remove="todos.splice(index, 1)"
>
</todo-item>
</ul>
</div>
 const vm = {
data() {
return {
newTodoText: '',
todos: [
{
id: 1,
title: 'Do the dishes'
},
{
id: 2,
title: 'Take out the trash'
},
{
id: 3,
title: 'Mow the lawn'
}
],
nextTodoId: 4
}
},
methods: {
addNewTodo() {
this.todos.push({
id: this.nextTodoId++,
title: this.newTodoText
})
this.newTodoText = ''
}
},
}
const app = Vue.createApp(vm)
app.component('todo-item', {
props: ['title'],
emit: ['remove'],
template: `
<li>
{{ title }}
<button @click="$emit('remove')">Remove</button>
</li>
`
})
app.mount('#app')

Event handling

Monitoring events

We can use v-on Instructions ( Commonly abbreviated as @ Symbol ) To listen to DOM event , And execute some actions when the event is triggered JavaScript. Usage for v-on:click="methodName" Or use a shortcut @click="methodName"

for example :

<div id="app">
<button @click="counter += 1">Add 1</button>
<p>The button above has been clicked {{ counter }} times.</p>
</div>
 const vm = {
data() {
return {
counter: 0
}
},
methods: {
},
}
const app = Vue.createApp(vm)
app.mount('#app')

Event handling method

However, many of the event processing logic will be more complex , So directly JavaScript The code is written in v-on It is not feasible in the instruction . therefore v-on You can also receive a method name that needs to be called .

for example :

<div id="app">
<!-- `greet` Is the method name defined below -->
<button @click="greet">Greet</button>
</div>
 const vm = {
data() {
return {
name: 'Vue.js'
}
},
methods: {
greet (event) {
// `methods` Inside `this` Points to the current active instance
alert('Hello ' + this.name + '!')
// `event` It's original DOM event
if (event) {
alert(event.target.tagName)
}
}
},
}
const app = Vue.createApp(vm)
app.mount('#app')

Methods in introverted processor

In addition to directly binding to a method , You can also inline JavaScript Method is called in the statement :

<div id="app">
<button @click="say('hi')">Say hi</button>
<button @click="say('what')">Say what</button>
</div>
Vue.createApp({
methods: {
say(message) {
alert(message)
}
}
}).mount('#app')

Sometimes you need to access the original... In the inline statement processor DOM event . You can use special variables $event Put it into the method :

<button @click="warn('Form cannot be submitted yet.', $event)">
Submit
</button>
// ...
methods: {
warn(message, event) {
// You can now access the native event
if (event) {
event.preventDefault()
}
alert(message)
}
}

Multi event processor

There can be multiple methods in an event handler , These methods are separated by the comma operator :

<!-- these two items. one() and two() Click the event to execute the button -->
<button @click="one($event), two($event)">
Submit
</button>
// ...
methods: {
one(event) {
// The first event handler logic ...
},
two(event) {
// The second event handler logic ...
}
}

Event modifier

Call in event handler event.preventDefault() or event.stopPropagation() It's a very common requirement . Although we can easily implement this in the method , But the better way is : Method has only pure data logic , Instead of dealing with DOM Details of the incident .

To solve this problem ,Vue.js by v-on Provides Event modifier . I mentioned before , The modifier is represented by the instruction suffix at the beginning of the dot .

  • .stop
  • .prevent
  • .capture
  • .self
  • .once
  • .passive`
<!-- Prevent click events from continuing to propagate -->
<a @click.stop="doThis"></a>
<!-- Submit event no longer reloads page -->
<form @submit.prevent="onSubmit"></form>
<!-- Modifiers can be concatenated -->
<a @click.stop.prevent="doThat"></a>
<!-- Only modifiers -->
<form @submit.prevent></form>
<!-- Use event capture mode when adding event listeners -->
<!-- That is, events triggered by internal elements are handled here first , Then it's left to the internal elements to deal with -->
<div @click.capture="doThis">...</div>
<!-- Just be there event.target Is the trigger handler for the current element itself -->
<!-- That is, events are not triggered from internal elements -->
<div @click.self="doThat">...</div>

TIP

When using modifiers , Order matters ; The corresponding code will be generated in the same order . therefore , use v-on:click.prevent.self Will block all clicks , and v-on:click.self.prevent It will only prevent clicking on the element itself .

<!-- The click event will only trigger once -->
<button type="button"@click.once="doThis">asd</button>

Unlike others that can only deal with native DOM The modifier that events work ,.once Modifiers can also be used in custom Component events On . If you haven't read the documentation about components , Don't worry about it now .

Vue It also corresponds to addEventListener Medium passive Options Provides .passive Modifier .

<!-- Default behavior for scrolling Events ( Rolling behavior ) Will trigger immediately -->
<!-- Instead of waiting `onScroll` complete -->
<!-- This includes `event.preventDefault()` The situation of -->
<div @scroll.passive="onScroll">...</div>

This .passive In particular, modifiers can improve the performance of mobile terminals .

TIP

Don't put the .passive and .prevent Use it together , because .prevent Will be ignored , At the same time, the browser may show you a warning . please remember ,.passive Will tell the browser you Don't want to Default behavior for block events .

Key modifier

When listening for keyboard events , We often need to check the detailed buttons .Vue Allow for v-on perhaps @ Add key modifiers when listening for keyboard events :

<!-- Only in `key` yes `Enter` Called when the `vm.submit()` -->
<input @keyup.enter="submit" />

You can directly KeyboardEvent.key Any valid key name exposed is converted to kebab-case As a modifier .

<input @keyup.page-down="onPageDown" />

In the example above , The handler will only $event.key be equal to 'PageDown' When called .

Key alias

Vue Aliases are provided for the most commonly used keys :

  • .enter
  • .tab
  • .delete ( Capture “ Delete ” and “ Backspace ” key )
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

System modifier keys

The following modifiers can be used to implement a listener that triggers mouse or keyboard events only when the corresponding key is pressed .

  • .ctrl
  • .alt
  • .shift
  • .meta

Tips

Be careful : stay Mac On the system keyboard ,meta Corresponding command key (⌘). stay Windows System keyboard meta Corresponding Windows Winkey (⊞). stay Sun On the operating system keyboard ,meta Corresponding to the solid gem key (◆). On other specific keyboards , Especially in MIT and Lisp The keyboard of the machine 、 And its successors , such as Knight keyboard 、space-cadet keyboard ,meta Marked as “META”. stay Symbolics On the keyboard ,meta Marked as “META” perhaps “Meta”.

.exact Modifier

.exact Modifiers allow you to control events triggered by a precise combination of system modifiers .

<!-- Even if Alt or Shift It also triggers when pressed together -->
<button @click.ctrl="onClick">A</button>
<!-- Yes and only Ctrl Triggered when pressed -->
<button @click.ctrl.exact="onCtrlClick">A</button>
<!-- No system modifier is triggered until it is pressed -->
<button @click.exact="onClick">A</button>

Mouse button modifier

  • .left
  • .right
  • .middle

These modifiers limit the handler to respond only to specific mouse buttons .

Why is it HTML Listening events in

You may notice that this way of event monitoring goes against separation of concerns (separation of concern) This long tradition of excellence . But don't worry , Because of all the Vue.js Event handling methods and expressions are strictly bound to the ViewModel On , It will not cause any maintenance difficulties . actually , Use v-on or @ There are several benefits :

  1. Glance at HTML Templates can be easily located in JavaScript The corresponding method in the code .
  2. Because you don't have to JavaScript Manually bind events in , Yours ViewModel Code can be very pure logic , and DOM Completely decoupled , Easier to test .
  3. When one ViewModel Be destroyed when the , All event handlers are automatically deleted . You don't have to worry about how to clean them up .

Form input binding

Basic usage

You can use it. v-model Instruction in form <input><textarea> And <select> Create two-way data binding on element . It automatically selects the correct method to update the element based on the control type . Even though it's magical , but v-model It's just grammar sugar in essence . It is responsible for monitoring user input events to update data , And some special treatment in some extreme situation .

Tips

v-model All form elements will be ignored valuecheckedselected attribute Always use the data of the current active instance as the data source . You should go through JavaScript In the component's data Initial value declared in option .

v-model Use different... Internally for different input elements property And throw out different events :

  • text and textarea Element usage value property and input event ;
  • checkbox and radio Use checked property and change event ;
  • select Fields will value As prop And will change As an event .

Tips

For the need to use typewriting ( Such as Chinese 、 Japanese 、 Korean, etc ) Language , You'll find that v-model It will not be updated in the process of organizing text with input method . If you also want to respond to these updates , Please use input Event listeners and value binding , Instead of using v-model.

Text (Text)

<input v-model="message" placeholder="edit me" />
<p>Message is: {{ message }}</p>

Multiline text (Textarea)

<span>Multiline message is:</span>
<p style="white-space: pre-line;">{{ message }}</p>
<br />
<textarea v-model="message" placeholder="add multiple lines"></textarea>

Interpolation doesn't work in text areas , You should use v-model Instead of .

<!-- bad -->
<textarea>{{ text }}</textarea>
<!-- good -->
<textarea v-model="text"></textarea>

Check box (CheckBox)

Single check box , Bind to Boolean :

<input type="checkbox" id="checkbox" v-model="checked" />
<label for="checkbox">{{ checked }}</label>

Multiple check boxes , Bind to the same array :

<div id="app">
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames" />
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames" />
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames" />
<label for="mike">Mike</label>
<br />
<span>Checked names: {{ checkedNames }}</span>
</div>
const vm = {
data() {
return {
checkedNames: []
}
},
methods: {
}
}
const app = Vue.createApp(vm)
app.mount('#app')

Radio buttons (Radio)

<div id="app">
<input type="radio" id="one" value="One" v-model="picked" />
<label for="one">One</label>
<br />
<input type="radio" id="two" value="Two" v-model="picked" />
<label for="two">Two</label>
<br />
<span>Picked: {{ picked }}</span>
</div>
const vm = {
data() {
return {
picked: ''
}
},
methods: {
}
}
const app = Vue.createApp(vm)
app.mount('#app')

Selection box (Select)

On single selection :

<div id="app">
<select v-model="selected">
<option disabled value="">Please select one</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>Selected: {{ selected }}</span>
</div>
const vm = {
data() {
return {
selected: ''
}
},
methods: {
}
}
const app = Vue.createApp(vm)
app.mount('#app')

Be careful

If v-model The initial value of the expression failed to match any options ,<select> The element will be rendered as “ Not selected ” state . stay iOS in , This prevents the user from choosing the first option . Because in this case ,iOS Not trigger change event . therefore , It is more recommended to provide a disable option with a null value like above .

When there are multiple choices ( Bind to an array ):

<select v-model="selected" multiple>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<br />
<span>Selected: {{ selected }}</span>

use v-for Dynamic options for rendering :

<div id="app">
<select v-model="selected">
<option v-for="option in options" :value="option.value">
{{ option.text }}
</option>
</select>
<span>Selected: {{ selected }}</span>
</div>
 const vm = {
data() {
return {
selected: 'A',
options: [
{ text: 'One', value: 'A' },
{ text: 'Two', value: 'B' },
{ text: 'Three', value: 'C' }
]
}
},
methods: {
}
}
const app = Vue.createApp(vm)
app.mount('#app')

Value binding

For radio buttons , Check box and check box options ,v-model The value of the binding is usually a static string ( The check box can also be Boolean ):

<!-- When elected ,`picked` For the string "a" -->
<input type="radio" v-model="picked" value="a" />
<!-- `toggle` by true or false -->
<input type="checkbox" v-model="toggle" />
<!-- When the first option is selected ,`selected` For the string "abc" -->
<select v-model="selected">
<option value="abc">ABC</option>
</select>

But sometimes we may want to bind the value to a dynamic instance of the current activity property On , You can use v-bind Realization , Besides , Use v-bind You can bind an input value to a non string .

Check box (Checkbox)

<input type="checkbox" v-model="toggle" true-value="yes" false-value="no" />
// when checked:
vm.toggle === 'yes'
// when unchecked:
vm.toggle === 'no'

Tips

there true-value and false-value attribute Does not affect the input control value attribute, Because browsers don't include unchecked checkboxes when submitting forms . If you want to make sure that one of these two values in the form can be submitted ,( namely “yes” or “no”), Please change the radio button .

Radio buttons (Radio)

<input type="radio" v-model="pick" v-bind:value="a" />
// When elected
vm.pick === vm.a

Selection box options (Select Options)

<select v-model="selected">
<!-- Inline object literals -->
<option :value="{ number: 123 }">123</option>
</select>
// When selected
typeof vm.selected // => 'object'
vm.selected.number // => 123

Modifier

.lazy

Above When input method organizes text ). You can add lazy Modifier , So it turns into change event _ after _ To synchronize :

<!-- stay “change” Sometimes not “input” When the update -->
<input v-model.lazy="msg" />

.number

If you want to automatically change the user's input value to a numeric type , You can give v-model add to number Modifier :

<input v-model.number="age" type="number" />

This is usually useful , Because even in type="number" when ,HTML The value of an input element always returns a string . If this value cannot be parseFloat() analysis , The original value will be returned .

.trim

If you want to automatically filter the first and last blank characters entered by users , You can give v-model add to trim Modifier :

<input v-model.trim="msg" />

Use... On components v-model

If you're not familiar with it Vue The components of , You can skip here for a while .

HTML Native input element types don't always meet the requirements . fortunately ,Vue Our component system allows you to create reusable input components with fully customized behavior . These input components can even interact with v-model Use it together !

To learn more about , See... In the components guide Custom input Components .

Foundation of organization

Basic examples

Here's one Vue Examples of components :

const vm = {
data() {
return {}
},
methods: {}
}
const app = Vue.createApp(vm)
app.component('button-counter', {
data() {
return {
count: 0
}
},
template: `
<button @click="count++">
You clicked me {{ count }} times.
</button>
`
})
app.mount('#app')

INFO

Here's a simple example , But in a typical Vue Application , We use a single file component instead of a string template . You can In this section Find out more about them .

A component is a reusable instance with a name , In this case, yes <button-counter>. We can use this component as a custom element in the root instance :

<div id="app">
<button-counter></button-counter>
</div>

Because components are reusable component instances , So they receive the same options as the root instance , for example datacomputedwatchmethods Lifecycle hooks and so on .

Reuse of components

<div id="app">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>

Notice when you click the button , Each component will maintain its own count. Because every time you use a component , There will be a new one example Be created .

Organization of components

Usually an application is organized as a nested component tree :

for example , You may have a header 、 Sidebar 、 Content area and other components , Each component also contains other links like navigation 、 Components like blogs .

To be used in templates , These components must first be registered in order to Vue Able to identify . There are two types of component registration : Global registration and Partial registration . thus , All of our components are just through the component Method globally registered :

const app = Vue.createApp({})
app.component('my-component-name', {
// ... Options ...
})

Globally registered components can be used in the template of any component in the application .

up to now , That's all you need to know about component registration , If you have read this page and mastered it , We'll recommend you to come back Component registration After reading .

adopt Prop Passing data to subcomponents

earlier , We talked about creating a blog component . The problem is that if you can't pass the title or content of a blog post to this component and the like data we want to show , There is no way to use it . This is what prop The origin of .

Prop It's some customizations that you can register on the component attribute. To pass a title to the blog component , We can use props Option to include it in the component's acceptable prop In the list :

const app = Vue.createApp(vm)
app.component('blog-post', {
props: ['title'],
template: `<h4>{{ title }}</h4>`
})
app.mount('#app')

When a value is passed to a prop attribute when , It becomes one of the component instances property. The property Can be accessed in the template , Just like any other component property equally .

By default, a component can have any number of prop, Any value can be passed to the prop.

<div id="app">
<blog-post title="My journey with Vue"></blog-post>
<blog-post title="Blogging with Vue"></blog-post>
<blog-post title="Why Vue is so fun"></blog-post>
</div>

However, in a typical application , You may be in data There is an array of blog posts :

const vm = {
data() {
return {
posts: [
{ id: 1, title: 'My journey with Vue' },
{ id: 2, title: 'Blogging with Vue' },
{ id: 3, title: 'Why Vue is so fun' }
]
}
},
methods: {}
}
const app = Vue.createApp(vm)
app.component('blog-post', {
props: ['title'],
template: `<h4>{{ title }}</h4>`
})
app.mount('#app')

And want to render a component for each blog post :

<div id="app">
<blog-post
v-for="post in posts"
:key="post.id"
:title="post.title"
>
</blog-post>
</div>

As shown above , You will find that we can use v-bind To deliver dynamically prop. You don't know exactly what to render at the beginning , It's very useful .

up to now , About prop That's about all you need to know , If you have read this page and mastered it , We'll recommend you to come back prop After reading .

Listen for subcomponent Events

We are developing <blog-post> When the component , Some of its functions may need to communicate with the parent component . For example, we may introduce an auxiliary function to enlarge the font size of blog posts , And leave the rest of the page with the default font size .

In its parent component , We can do this by adding a postFontSize data property To support this function :

It can be used to control the font size of all blog posts in the template :

data() {
return {
posts: [
{ id: 1, title: 'My journey with Vue' },
{ id: 2, title: 'Blogging with Vue' },
{ id: 3, title: 'Why Vue is so fun' }
],
postFontSize: 1
}
}

It can be used to control the font size of all blog posts in the template :

<div id="app">
<div :sytle="{ fontSize: postFontSize + 'em'}">
<blog-post
v-for="post in posts"
:key="post.id"
:title="post.title"
>
</blog-post>
</div>
</div>

Now let's add a button before the body of each blog post to enlarge the font size :

app.component('blog-post', {
props: ['title'],
template: `
<div class="blog-post">
<h4>{{ title }}</h4>
<button>
Enlarge text
</button>
</div>
`
})

The problem is that this button doesn't do anything :

<button>
Enlarge text
</button>

When you click this button , We need to tell the parent component to enlarge the text of all posts . Fortunately, the component instance provides a custom event system to solve this problem . The parent component can handle native components as well DOM Events pass through v-on or @ Listen for any events of a subcomponent instance :

<blog-post ... @enlarge-text="postFontSize += 0.1"></blog-post>

At the same time, the sub components can call the built-in $emit Method And pass in the event name to trigger an event :

<button @click="$emit('enlargeText')">
Enlarge text
</button>

Thanks a lot @enlarge-text="postFontSize += 0.1" Monitor , The parent component can receive events and update them postFontSize value .

I failed anyway !

My code !:

<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="Vue3.js"></script>
</head>
<body>
<div id="app">
<div :sytle="{ fontSize: postFontSize + 'em' }">
<blog-post
v-for="post in posts"
:key="post.id"
:title="post.title"
v-on:enlarge-text="postFontSize += 0.1"
>
</blog-post>
</div>
</div>
<script>
const vm = {
data() {
return {
posts: [
{id: 1, title: 'My journey with Vue'},
{id: 2, title: 'Blogging with Vue'},
{id: 3, title: 'Why Vue is so fun'}
],
postFontSize: 1
}
},
methods: {}
}
const app = Vue.createApp(vm)
app.component('blog-post', {
props: ['title'],
template: `
<div class="blog-post">
<h4>{{ title }}</h4>
<button @click="$emit('enlargeText')">
Enlarge text
</button>
</div>
`
})
app.mount('#app')
</script>
</body>
</html>

Successful results on the document !

We can use the component's emits Option lists the events that have been thrown :

app.component('blog-post', {
props: ['title'],
emits: ['enlargeText']
})

This will allow us to examine all events thrown by the component , You can also choose Verify them .

Use the event to throw a value ( It's just carrying parameters !)

Sometimes it's very useful to throw a specific value with an event . For example, we might want to <blog-post> Component determines how much of its text to enlarge . You can use $emit The second parameter to provide this value :

<button @click="$emit('enlargeText', 0.1)">
Enlarge text
</button>

Then when the parent component listens for this event , We can go through $event Access to the value being thrown :

<blog-post ... @enlarge-text="postFontSize += $event"></blog-post>

perhaps , If this event handler is a method :

<blog-post ... @enlarge-text="onEnlargeText"></blog-post>

Then this value will be passed into this method as the first parameter :

methods: {
onEnlargeText(enlargeAmount) {
this.postFontSize += enlargeAmount
}
}

Use... On components v-model

Custom events can also be used to create support v-model The custom input component of . remember :

<input v-model="searchText" />

Equivalent to :

<input :value="searchText" @input="searchText = $event.target.value" />

When used on components ,v-model That's what happens :

<custom-input
:model-value="searchText"
@update:model-value="searchText = $event"
></custom-input>

WARNING

Please note that , What we use here is model-value, Because we're using DOM In the template kebab-case. You can analysis DOM Precautions for formwork Section to find out about kebab cased and camelCased Property

To make it work , In this component <input> must :

  • Put it value attribute Bind to a name modelValue Of prop On
  • In its input When the event is triggered , Pass the new value through the custom update:modelValue Event throw

It's like this after writing the code

app.component('custom-input', {
props: ['modelValue'],
emits: ['update:modelValue'],
template: `
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
>
`
})

Now? v-model It should work perfectly on this component :

<custom-input v-model="searchText"></custom-input>

In this component v-model Another way to do this is to use computed property To define the function of getter and setter.get Method should return modelValue property,set Method should trigger the corresponding event .

app.component('custom-input', {
props: ['modelValue'],
emits: ['update:modelValue'],
template: `
<input v-model="value">
`,
computed: {
value: {
get() {
return this.modelValue
},
set(value) {
this.$emit('update:modelValue', value)
}
}
}
})

Now you just need to know about custom component events , But once you've read this page and feel good about it , We suggest you read about it later Custom events

版权声明
本文为[lvhanghmm]所创,转载请带上原文链接,感谢
https://qdmana.com/2021/05/20210528111338075u.html

  1. HTML + CSS + JavaScript to achieve cool Fireworks (cloud like particle text 3D opening)
  2. HTML + CSS + JavaScript realizes 520 advertising love tree (including music), which is necessary for programmers to express themselves
  3. Solve the problem of Web front-end deployment server (it can be deployed online without a server)
  4. HTML + CSS + JS make wedding countdown web page template (520 / Tanabata Valentine's Day / programmer advertisement)
  5. What else can driverless minibus do besides "Park connection"?
  6. Cloud native leads the era of all cloud development
  7. NRM mirror source management tool
  8. Bring it to you, flex Jiugong
  9. Lolstyle UI component development practice (II) -- button group component
  10. Deconstruction assignment in ES6
  11. Luo 2 peerless Tang clan was officially launched. The official gave a key point, and the broadcast time was implied
  12. 20初识前端HTML(1)
  13. 当新零售遇上 Serverless
  14. 20 initial knowledge of front-end HTML (1)
  15. When new retail meets serverless
  16. [golang] - go into go language lesson 5 type conversion
  17. [golang] - go into go language lesson 6 conditional expression
  18. HTML5(八)——SVG 之 path 详解
  19. HTML5 (8) -- detailed explanation of SVG path
  20. 需要开通VIP以后页面内容才能复制怎么办?控制台禁用javascript即可
  21. Web前端|CSS入门教程(超详细的CSS使用讲解,适合前端初学者)
  22. 实践积累 —— 用Vue3简单写一个单行横向滚动组件
  23. Serverless 全能选手,再下一城
  24. What if you need to open a VIP to copy the page content? Just disable JavaScript on the console
  25. Web front end | CSS introductory tutorial (super detailed CSS explanation, suitable for front-end beginners)
  26. Practice accumulation - write a single line horizontal scroll component simply with vue3
  27. Dili Reba is thin again. She looks elegant and high in a strapless hollow skirt, and her "palm waist" is beautiful to a new height
  28. Serverless all-round player, next city
  29. The difference between MySQL semi synchronous replication and lossless semi synchronous replication
  30. Vue表单设计器的终极解决方案
  31. The ultimate solution for Vue form designer
  32. Nginx从理论到实践超详细笔记
  33. Yu Shuxin's red backless swimsuit is split to the waist and tail, with a concave convex figure and excessive color matching, and his face is white to dazzling
  34. Nginx ultra detailed notes from theory to practice
  35. 【动画消消乐|CSS】086.炫酷水波浪Loading过渡动画
  36. typecho全站启用https
  37. CCTV has another popular employee. The off-site interpretation is very professional, and the appearance ability is no less than that of Wang Bingbing
  38. [animation Xiaole | CSS] 086. Cool water wave loading transition animation
  39. Enable HTTPS in Typecho
  40. 50天用JavaScript完成50个web项目,我学到了什么?
  41. 根据JavaScript中原生的XMLHttpRequest实现jQuery的Ajax
  42. What have I learned from completing 50 web projects with JavaScript in 50 days?
  43. "My neighbor doesn't grow up" has hit the whole network. There are countless horse music circles, and actor Zhou Xiaochuan has successfully made a circle
  44. 根据JavaScript中原生的XMLHttpRequest实现jQuery的Ajax
  45. Implement the Ajax of jQuery according to the native XMLHttpRequest in JavaScript
  46. Implement the Ajax of jQuery according to the native XMLHttpRequest in JavaScript
  47. 30 + women still wear less T-shirts and jeans. If they wear them like stars, they will lose weight
  48. 数栈技术分享前端篇:TS,看你哪里逃~
  49. Several stack technology sharing front end: TS, see where you escape~
  50. 舍弃Kong和Nginx,Apache APISIX 在趣链科技 BaaS 平台的落地实践
  51. Abandon the landing practice of Kong and nginx, Apache apisik on the baas platform of fun chain technology
  52. 浪迹天涯king教你用elementui做复杂的表格,去处理报表数据(合并表头,合并表体行和列)
  53. 前端HTML两万字图文大总结,快来看看你会多少!【️熬夜整理&建议收藏️】
  54. Wandering around the world king teaches you to use elementui to make complex tables and process report data (merge header, merge table body rows and columns)
  55. 路由刷新数据丢失 - vuex数据读取的问题
  56. Front end HTML 20000 word graphic summary, come and see how much you can【 Stay up late to sort out & suggestions]
  57. Route refresh data loss - vuex data reading problem
  58. Systemctl系统启动Nginx服务脚本
  59. Systemctl system startup nginx service script
  60. sleepless