diff --git a/src/.vuepress/config.js b/src/.vuepress/config.js index 8825a5f2e7..d60977473d 100644 --- a/src/.vuepress/config.js +++ b/src/.vuepress/config.js @@ -12,6 +12,7 @@ const sidebar = { '/guide/introduction', '/guide/instance', '/guide/template-syntax', + '/guide/data-methods', '/guide/computed', '/guide/class-and-style', '/guide/conditional', diff --git a/src/guide/data-methods.md b/src/guide/data-methods.md new file mode 100644 index 0000000000..69c6a14c80 --- /dev/null +++ b/src/guide/data-methods.md @@ -0,0 +1,125 @@ +# Data Properties and Methods + +## Data Properties + +The `data` option for a component is a function. Vue calls this function as part of creating a new component instance. It should return an object, which Vue will then wrap in its reactivity system and store on the component instance as `$data`. For convenience, any top-level properties of that object are also exposed directly via the component instance: + +```js +const app = Vue.createApp({ + data() { + return { count: 4 } + } +}) + +const vm = app.mount('#app') + +console.log(vm.$data.count) // => 4 +console.log(vm.count) // => 4 + +// Assigning a value to vm.count will also update $data.count +vm.count = 5 +console.log(vm.$data.count) // => 5 + +// ... and vice-versa +vm.$data.count = 6 +console.log(vm.count) // => 6 +``` + +These instance properties are only added when the instance is first created, so you need to ensure they are all present in the object returned by the `data` function. Where necessary, use `null`, `undefined` or some other placeholder value for properties where the desired value isn't yet available. + +It is possible to add a new property directly to the component instance without including it in `data`. However, because this property isn't backed by the reactive `$data` object, it won't automatically be tracked by [Vue's reactivity system](reactivity.html). + +Vue uses a `$` prefix when exposing its own built-in APIs via the component instance. It also reserves the prefix `_` for internal properties. You should avoid using names for top-level `data` properties that start with either of these characters. + +## Methods + +To add methods to a component instance we use the `methods` option. This should be an object containing the desired methods: + +```js +const app = Vue.createApp({ + data() { + return { count: 4 } + }, + methods: { + increment() { + // `this` will refer 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 binds the `this` value for `methods` so that it always refers to the component instance. This ensures that a method retains the correct `this` value if it's used as an event listener or callback. You should avoid using arrow functions when defining `methods`, as that prevents Vue from binding the appropriate `this` value. + +Just like all other properties of the component instance, the `methods` are accessible from within the component's template. Inside a template they are most commonly used as event listeners: + +```html + +``` + +In the example above, the method `increment` will be called when the ` + ` +}) +``` diff --git a/src/guide/instance.md b/src/guide/instance.md index fcdf03da31..dfdda01423 100644 --- a/src/guide/instance.md +++ b/src/guide/instance.md @@ -1,139 +1,100 @@ -# The Application Instance +# Application & Component Instances -## Creating an Instance +## Creating an Application Instance Every Vue application starts by creating a new **application instance** with the `createApp` function: ```js -Vue.createApp(/* options */) +const app = Vue.createApp({ /* options */ }) ``` -After the instance is created, we can _mount_ it, passing a container to `mount` method. For example, if we want to mount a Vue application on `
`, we should pass `#app`: +The application instance is used to register 'globals' that can then be used by components within that application. We'll discuss that in detail later in the guide but as a quick example: ```js -Vue.createApp(/* options */).mount('#app') +const app = Vue.createApp({}) +app.component('SearchInput', SearchInputComponent) +app.directive('focus', FocusDirective) +app.use(LocalePlugin) ``` -Although not strictly associated with the [MVVM pattern](https://en.wikipedia.org/wiki/Model_View_ViewModel), Vue's design was partly inspired by it. As a convention, we often use the variable `vm` (short for ViewModel) to refer to our instance. - -When you create an instance, you pass in an **options object**. The majority of this guide describes how you can use these options to create your desired behavior. For reference, you can also browse the full list of options in the [API reference](../api/options-data.html). - -A Vue application consists of a **root instance** created with `createApp`, optionally organized into a tree of nested, reusable components. For example, a `todo` app's component tree might look like this: - -``` -Root Instance -└─ TodoList - ├─ TodoItem - │ ├─ DeleteTodoButton - │ └─ EditTodoButton - └─ TodoListFooter - ├─ ClearTodosButton - └─ TodoListStatistics -``` - -We'll talk about [the component system](component-basics.html) in detail later. For now, just know that all Vue components are also instances, and so accept the same options object. - -## Data and Methods - -When an instance is created, it adds all the properties found in its `data` to [Vue's **reactivity system**](reactivity.html). When the values of those properties change, the view will "react", updating to match the new values. +Most of the methods exposed by the application instance return that same instance, allowing for chaining: ```js -// Our data object -const data = { a: 1 } +Vue.createApp({}) + .component('SearchInput', SearchInputComponent) + .directive('focus', FocusDirective) + .use(LocalePlugin) +``` -// The object is added to the root instance -const vm = Vue.createApp({ - data() { - return data - } -}).mount('#app') +You can browse the full application API in the [API reference](../api/application-api.html). -// Getting the property on the instance -// returns the one from the original data -vm.a === data.a // => true +## The Root Component -// Setting the property on the instance -// also affects the original data -vm.a = 2 -data.a // => 2 -``` +The options passed to `createApp` are used to configure the **root component**. That component is used as the starting point for rendering when we **mount** the application. -When this data changes, the view will re-render. It should be noted that properties in `data` are only **reactive** if they existed when the instance was created. That means if you add a new property, like: +An application needs to be mounted into a DOM element. For example, if we want to mount a Vue application into `
`, we should pass `#app`: ```js -vm.b = 'hi' +const RootComponent = { /* options */ } +const app = Vue.createApp(RootComponent) +const vm = app.mount('#app') ``` -Then changes to `b` will not trigger any view updates. If you know you'll need a property later, but it starts out empty or non-existent, you'll need to set some initial value. For example: +Unlike most of the application methods, `mount` does not return the application. Instead it returns the root component instance. -```js -data() { - return { - newTodoText: '', - visitCount: 0, - hideCompletedTodos: false, - todos: [], - error: null - } -} -``` +Although not strictly associated with the [MVVM pattern](https://en.wikipedia.org/wiki/Model_View_ViewModel), Vue's design was partly inspired by it. As a convention, we often use the variable `vm` (short for ViewModel) to refer to a component instance. -The only exception to this being the use of `Object.freeze()`, which prevents existing properties from being changed, which also means the reactivity system can't _track_ changes. +While all the examples on this page only need a single component, most real applications are organized into a tree of nested, reusable components. For example, a Todo application's component tree might look like this: -```js -const obj = { - foo: 'bar' -} +``` +Root Component +└─ TodoList + ├─ TodoItem + │ ├─ DeleteTodoButton + │ └─ EditTodoButton + └─ TodoListFooter + ├─ ClearTodosButton + └─ TodoListStatistics +``` -Object.freeze(obj) +Each component will have its own component instance, `vm`. For some components, such as `TodoItem`, there will likely be multiple instances rendered at any one time. All of the component instances in this application will share the same application instance. -const vm = Vue.createApp({ - data() { - return obj - } -}).mount('#app') -``` +We'll talk about [the component system](component-basics.html) in detail later. For now, just be aware that the root component isn't really any different from any other component. The configuration options are the same, as is the behavior of the corresponding component instance. -```html -
-

{{ foo }}

- - -
-``` +## Component Instance Properties -In addition to data properties, instances expose a number of useful instance properties and methods. These are prefixed with `$` to differentiate them from user-defined properties. For example: +Earlier in the guide we met `data` properties. Properties defined in `data` are exposed via the component instance: ```js -const vm = Vue.createApp({ +const app = Vue.createApp({ data() { - return { - a: 1 - } + return { count: 4 } } -}).mount('#example') +}) -vm.$data.a // => 1 +const vm = app.mount('#app') + +console.log(vm.count) // => 4 ``` -In the future, you can consult the [API reference](../api/instance-properties.html) for a full list of instance properties and methods. +There are various other component options that add user-defined properties to the component instance, such as `methods`, `props`, `computed`, `inject` and `setup`. We'll discuss each of these in depth later in the guide. All of the properties of the component instance, no matter how they are defined, will be accessible in the component's template. + +Vue also exposes some built-in properties via the component instance, such as `$attrs` and `$emit`. These properties all have a `$` prefix to avoid conflicting with user-defined property names. -## Instance Lifecycle Hooks +## Lifecycle Hooks -Each instance goes through a series of initialization steps when it's created - for example, it needs to set up data observation, compile the template, mount the instance to the DOM, and update the DOM when data changes. Along the way, it also runs functions called **lifecycle hooks**, giving users the opportunity to add their own code at specific stages. +Each component instance goes through a series of initialization steps when it's created - for example, it needs to set up data observation, compile the template, mount the instance to the DOM, and update the DOM when data changes. Along the way, it also runs functions called **lifecycle hooks**, giving users the opportunity to add their own code at specific stages. For example, the [created](../api/options-lifecycle-hooks.html#created) hook can be used to run code after an instance is created: ```js Vue.createApp({ data() { - return { - a: 1 - } + return { count: 1 } }, created() { // `this` points to the vm instance - console.log('a is: ' + this.a) // => "a is: 1" + console.log('count is: ' + this.count) // => "count is: 1" } }) ``` diff --git a/src/guide/template-syntax.md b/src/guide/template-syntax.md index 33473734e3..2c76a526b7 100644 --- a/src/guide/template-syntax.md +++ b/src/guide/template-syntax.md @@ -1,6 +1,6 @@ # Template Syntax -Vue.js uses an HTML-based template syntax that allows you to declaratively bind the rendered DOM to the underlying application instance's data. All Vue.js templates are valid HTML that can be parsed by spec-compliant browsers and HTML parsers. +Vue.js uses an HTML-based template syntax that allows you to declaratively bind the rendered DOM to the underlying component instance's data. All Vue.js templates are valid HTML that can be parsed by spec-compliant browsers and HTML parsers. Under the hood, Vue compiles the templates into Virtual DOM render functions. Combined with the reactivity system, Vue is able to intelligently figure out the minimal number of components to re-render and apply the minimal amount of DOM manipulations when the app state changes. @@ -16,7 +16,7 @@ The most basic form of data binding is text interpolation using the "Mustache" s Message: {{ msg }} ``` -The mustache tag will be replaced with the value of the `msg` property on the corresponding data object. It will also be updated whenever the data object's `msg` property changes. +The mustache tag will be replaced with the value of the `msg` property from the corresponding component instance. It will also be updated whenever the `msg` property changes. You can also perform one-time interpolations that do not update on data change by using the [v-once directive](../api/directives.html#v-once), but keep in mind this will also affect any other bindings on the same node: @@ -123,7 +123,7 @@ in the "Dynamic Argument Expression Constraints" section below. ... ``` -Here `attributeName` will be dynamically evaluated as a JavaScript expression, and its evaluated value will be used as the final value for the argument. For example, if your application instance has a data property, `attributeName`, whose value is `"href"`, then this binding will be equivalent to `v-bind:href`. +Here `attributeName` will be dynamically evaluated as a JavaScript expression, and its evaluated value will be used as the final value for the argument. For example, if your component instance has a data property, `attributeName`, whose value is `"href"`, then this binding will be equivalent to `v-bind:href`. Similarly, you can use dynamic arguments to bind a handler to a dynamic event name: