-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Move computed+watchers and class+style #31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<template> | ||
<div id="example" class="demo"> | ||
<p>Original message: "{{ message }}"</p> | ||
<p>Computed reversed message: "{{ reversedMessage }}"</p> | ||
</div> | ||
</template> | ||
|
||
<script> | ||
export default { | ||
data() { | ||
return { | ||
message: 'Hello' | ||
}; | ||
}, | ||
computed: { | ||
reversedMessage: function() { | ||
return this.message | ||
.split('') | ||
.reverse() | ||
.join(''); | ||
} | ||
} | ||
}; | ||
</script> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
<template> | ||
<div class="demo"> | ||
<p> | ||
Ask a yes/no question: | ||
<input v-model="question" /> | ||
</p> | ||
<p>{{ answer }}</p> | ||
</div> | ||
</template> | ||
|
||
<script> | ||
import { debounce, capitalize } from 'lodash' | ||
import axios from 'axios' | ||
export default { | ||
data() { | ||
return { | ||
question: '', | ||
answer: 'Questions usually contain a question mark. ;-)' | ||
} | ||
}, | ||
watch: { | ||
// whenever question changes, this function will run | ||
question(newQuestion, oldQuestion) { | ||
if (newQuestion.indexOf('?') > -1) { | ||
this.getAnswer() | ||
} | ||
} | ||
}, | ||
methods: { | ||
getAnswer() { | ||
this.answer = 'Thinking...' | ||
axios | ||
.get('https://yesno.wtf/api') | ||
.then(response => { | ||
this.answer = _.capitalize(response.data.answer) | ||
}) | ||
.catch(error => { | ||
this.answer = 'Error! Could not reach the API. ' + error | ||
}) | ||
} | ||
} | ||
} | ||
</script> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,223 @@ | ||
# Class and Style Bindings | ||
|
||
A common need for data binding is manipulating an element's class list and its inline styles. Since they are both attributes, we can use `v-bind` to handle them: we only need to calculate a final string with our expressions. However, meddling with string concatenation is annoying and error-prone. For this reason, Vue provides special enhancements when `v-bind` is used with `class` and `style`. In addition to strings, the expressions can also evaluate to objects or arrays. | ||
|
||
## Binding HTML Classes | ||
|
||
[Watch a free video lesson on Vue School](https://vueschool.io/lessons/vuejs-dynamic-classes?friend=vuejs) | ||
|
||
### Object Syntax | ||
|
||
We can pass an object to `v-bind:class` to dynamically toggle classes: | ||
|
||
```html | ||
<div v-bind:class="{ active: isActive }"></div> | ||
``` | ||
|
||
The above syntax means the presence of the `active` class will be determined by the [truthiness](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) of the data property `isActive`. | ||
|
||
You can have multiple classes toggled by having more fields in the object. In addition, the `v-bind:class` directive can also co-exist with the plain `class` attribute. So given the following template: | ||
|
||
```html | ||
<div | ||
class="static" | ||
v-bind:class="{ active: isActive, 'text-danger': hasError }" | ||
></div> | ||
``` | ||
|
||
And the following data: | ||
|
||
```js | ||
data: { | ||
isActive: true, | ||
hasError: false | ||
} | ||
``` | ||
|
||
It will render: | ||
|
||
```html | ||
<div class="static active"></div> | ||
``` | ||
|
||
When `isActive` or `hasError` changes, the class list will be updated accordingly. For example, if `hasError` becomes `true`, the class list will become `"static active text-danger"`. | ||
|
||
The bound object doesn't have to be inline: | ||
|
||
```html | ||
<div v-bind:class="classObject"></div> | ||
``` | ||
|
||
```js | ||
data: { | ||
classObject: { | ||
active: true, | ||
'text-danger': false | ||
} | ||
} | ||
``` | ||
|
||
This will render the same result. We can also bind to a [computed property](computed.md) that returns an object. This is a common and powerful pattern: | ||
|
||
```html | ||
<div v-bind:class="classObject"></div> | ||
``` | ||
|
||
```js | ||
data: { | ||
isActive: true, | ||
error: null | ||
}, | ||
computed: { | ||
classObject() { | ||
return { | ||
active: this.isActive && !this.error, | ||
'text-danger': this.error && this.error.type === 'fatal' | ||
} | ||
} | ||
} | ||
``` | ||
|
||
### Array Syntax | ||
|
||
We can pass an array to `v-bind:class` to apply a list of classes: | ||
|
||
```html | ||
<div v-bind:class="[activeClass, errorClass]"></div> | ||
``` | ||
|
||
```js | ||
data: { | ||
activeClass: 'active', | ||
errorClass: 'text-danger' | ||
} | ||
``` | ||
|
||
Which will render: | ||
|
||
```html | ||
<div class="active text-danger"></div> | ||
``` | ||
|
||
If you would like to also toggle a class in the list conditionally, you can do it with a ternary expression: | ||
|
||
```html | ||
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div> | ||
``` | ||
|
||
This will always apply `errorClass`, but will only apply `activeClass` when `isActive` is truthy. | ||
|
||
However, this can be a bit verbose if you have multiple conditional classes. That's why it's also possible to use the object syntax inside array syntax: | ||
|
||
```html | ||
<div v-bind:class="[{ active: isActive }, errorClass]"></div> | ||
``` | ||
|
||
### With Components | ||
|
||
> This section assumes knowledge of [Vue Components](TODO:components.html). Feel free to skip it and come back later. | ||
|
||
When you use the `class` attribute on a custom component, those classes will be added to the component's root element. Existing classes on this element will not be overwritten. | ||
|
||
For example, if you declare this component: | ||
|
||
```js | ||
const MyComponent = { | ||
template: '<p class="foo bar">Hi!</p>' | ||
} | ||
``` | ||
|
||
Then add some classes when using it: | ||
|
||
```html | ||
<div id="app"> | ||
<my-component class="baz boo"></my-component> | ||
</div> | ||
``` | ||
|
||
```js | ||
Vue.createApp().mount( | ||
{ | ||
components: { | ||
'my-component': MyComponent | ||
} | ||
}, | ||
'#app' | ||
) | ||
``` | ||
|
||
The rendered HTML will be: | ||
|
||
```html | ||
<p class="foo bar baz boo">Hi</p> | ||
``` | ||
|
||
> TODO: needs a check after https://github.com/vuejs/rfcs/blob/attr-fallthrough/active-rfcs/0000-attr-fallthrough.md is merged | ||
|
||
The same is true for class bindings: | ||
|
||
```html | ||
<my-component v-bind:class="{ active: isActive }"></my-component> | ||
``` | ||
|
||
When `isActive` is truthy, the rendered HTML will be: | ||
|
||
```html | ||
<p class="foo bar active">Hi</p> | ||
``` | ||
|
||
## Binding Inline Styles | ||
|
||
### Object Syntax | ||
|
||
The object syntax for `v-bind:style` is pretty straightforward - it looks almost like CSS, except it's a JavaScript object. You can use either camelCase or kebab-case (use quotes with kebab-case) for the CSS property names: | ||
|
||
```html | ||
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div> | ||
``` | ||
|
||
```js | ||
data: { | ||
activeColor: 'red', | ||
fontSize: 30 | ||
} | ||
``` | ||
|
||
It is often a good idea to bind to a style object directly so that the template is cleaner: | ||
|
||
```html | ||
<div v-bind:style="styleObject"></div> | ||
``` | ||
|
||
```js | ||
data: { | ||
styleObject: { | ||
color: 'red', | ||
fontSize: '13px' | ||
} | ||
} | ||
``` | ||
|
||
Again, the object syntax is often used in conjunction with computed properties that return objects. | ||
|
||
### Array Syntax | ||
|
||
The array syntax for `v-bind:style` allows you to apply multiple style objects to the same element: | ||
|
||
```html | ||
<div v-bind:style="[baseStyles, overridingStyles]"></div> | ||
``` | ||
|
||
### Auto-prefixing | ||
|
||
When you use a CSS property that requires [vendor prefixes](https://developer.mozilla.org/en-US/docs/Glossary/Vendor_Prefix) in `v-bind:style`, for example `transform`, Vue will automatically detect and add appropriate prefixes to the applied styles. | ||
|
||
### Multiple Values | ||
|
||
You can provide an array of multiple (prefixed) values to a style property, for example: | ||
|
||
```html | ||
<div v-bind:style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div> | ||
``` | ||
|
||
This will only render the last value in the array which the browser supports. In this example, it will render `display: flex` for browsers that support the unprefixed version of flexbox. |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel this example is introducing to complex handling of strings which is out of the scope here. We can add a simpler example something like sum of two numbers as computed property.