Skip to content

Commit 3712e66

Browse files
authored
Merge pull request #31 from vuejs/move-computed-watchers
Move computed+watchers and class+style
2 parents 1ea42cb + 081bd6a commit 3712e66

File tree

7 files changed

+566
-9
lines changed

7 files changed

+566
-9
lines changed

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,8 @@
55
"scripts": {
66
"serve": "vuepress dev src",
77
"build": "vuepress build src"
8+
},
9+
"dependencies": {
10+
"axios": "^0.19.1"
811
}
912
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<template>
2+
<div id="example" class="demo">
3+
<p>Original message: "{{ message }}"</p>
4+
<p>Computed reversed message: "{{ reversedMessage }}"</p>
5+
</div>
6+
</template>
7+
8+
<script>
9+
export default {
10+
data() {
11+
return {
12+
message: 'Hello'
13+
};
14+
},
15+
computed: {
16+
reversedMessage: function() {
17+
return this.message
18+
.split('')
19+
.reverse()
20+
.join('');
21+
}
22+
}
23+
};
24+
</script>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<template>
2+
<div class="demo">
3+
<p>
4+
Ask a yes/no question:
5+
<input v-model="question" />
6+
</p>
7+
<p>{{ answer }}</p>
8+
</div>
9+
</template>
10+
11+
<script>
12+
import { debounce, capitalize } from 'lodash'
13+
import axios from 'axios'
14+
export default {
15+
data() {
16+
return {
17+
question: '',
18+
answer: 'Questions usually contain a question mark. ;-)'
19+
}
20+
},
21+
watch: {
22+
// whenever question changes, this function will run
23+
question(newQuestion, oldQuestion) {
24+
if (newQuestion.indexOf('?') > -1) {
25+
this.getAnswer()
26+
}
27+
}
28+
},
29+
methods: {
30+
getAnswer() {
31+
this.answer = 'Thinking...'
32+
axios
33+
.get('https://yesno.wtf/api')
34+
.then(response => {
35+
this.answer = _.capitalize(response.data.answer)
36+
})
37+
.catch(error => {
38+
this.answer = 'Error! Could not reach the API. ' + error
39+
})
40+
}
41+
}
42+
}
43+
</script>

src/.vuepress/config.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,14 @@ module.exports = {
2525
],
2626
sidebarDepth: 2,
2727
sidebar: {
28-
'/guide/': ['installation', 'introduction', 'instance', 'template-syntax']
28+
'/guide/': [
29+
'installation',
30+
'introduction',
31+
'instance',
32+
'template-syntax',
33+
'computed',
34+
'class-and-style'
35+
]
2936
}
3037
},
3138
plugins: {
@@ -39,4 +46,4 @@ module.exports = {
3946
}
4047
}
4148
}
42-
};
49+
}

src/guide/class-and-style.md

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
# Class and Style Bindings
2+
3+
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.
4+
5+
## Binding HTML Classes
6+
7+
[Watch a free video lesson on Vue School](https://vueschool.io/lessons/vuejs-dynamic-classes?friend=vuejs)
8+
9+
### Object Syntax
10+
11+
We can pass an object to `v-bind:class` to dynamically toggle classes:
12+
13+
```html
14+
<div v-bind:class="{ active: isActive }"></div>
15+
```
16+
17+
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`.
18+
19+
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:
20+
21+
```html
22+
<div
23+
class="static"
24+
v-bind:class="{ active: isActive, 'text-danger': hasError }"
25+
></div>
26+
```
27+
28+
And the following data:
29+
30+
```js
31+
data: {
32+
isActive: true,
33+
hasError: false
34+
}
35+
```
36+
37+
It will render:
38+
39+
```html
40+
<div class="static active"></div>
41+
```
42+
43+
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"`.
44+
45+
The bound object doesn't have to be inline:
46+
47+
```html
48+
<div v-bind:class="classObject"></div>
49+
```
50+
51+
```js
52+
data: {
53+
classObject: {
54+
active: true,
55+
'text-danger': false
56+
}
57+
}
58+
```
59+
60+
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:
61+
62+
```html
63+
<div v-bind:class="classObject"></div>
64+
```
65+
66+
```js
67+
data: {
68+
isActive: true,
69+
error: null
70+
},
71+
computed: {
72+
classObject() {
73+
return {
74+
active: this.isActive && !this.error,
75+
'text-danger': this.error && this.error.type === 'fatal'
76+
}
77+
}
78+
}
79+
```
80+
81+
### Array Syntax
82+
83+
We can pass an array to `v-bind:class` to apply a list of classes:
84+
85+
```html
86+
<div v-bind:class="[activeClass, errorClass]"></div>
87+
```
88+
89+
```js
90+
data: {
91+
activeClass: 'active',
92+
errorClass: 'text-danger'
93+
}
94+
```
95+
96+
Which will render:
97+
98+
```html
99+
<div class="active text-danger"></div>
100+
```
101+
102+
If you would like to also toggle a class in the list conditionally, you can do it with a ternary expression:
103+
104+
```html
105+
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
106+
```
107+
108+
This will always apply `errorClass`, but will only apply `activeClass` when `isActive` is truthy.
109+
110+
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:
111+
112+
```html
113+
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
114+
```
115+
116+
### With Components
117+
118+
> This section assumes knowledge of [Vue Components](TODO:components.html). Feel free to skip it and come back later.
119+
120+
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.
121+
122+
For example, if you declare this component:
123+
124+
```js
125+
const MyComponent = {
126+
template: '<p class="foo bar">Hi!</p>'
127+
}
128+
```
129+
130+
Then add some classes when using it:
131+
132+
```html
133+
<div id="app">
134+
<my-component class="baz boo"></my-component>
135+
</div>
136+
```
137+
138+
```js
139+
Vue.createApp().mount(
140+
{
141+
components: {
142+
'my-component': MyComponent
143+
}
144+
},
145+
'#app'
146+
)
147+
```
148+
149+
The rendered HTML will be:
150+
151+
```html
152+
<p class="foo bar baz boo">Hi</p>
153+
```
154+
155+
> TODO: needs a check after https://github.com/vuejs/rfcs/blob/attr-fallthrough/active-rfcs/0000-attr-fallthrough.md is merged
156+
157+
The same is true for class bindings:
158+
159+
```html
160+
<my-component v-bind:class="{ active: isActive }"></my-component>
161+
```
162+
163+
When `isActive` is truthy, the rendered HTML will be:
164+
165+
```html
166+
<p class="foo bar active">Hi</p>
167+
```
168+
169+
## Binding Inline Styles
170+
171+
### Object Syntax
172+
173+
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:
174+
175+
```html
176+
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
177+
```
178+
179+
```js
180+
data: {
181+
activeColor: 'red',
182+
fontSize: 30
183+
}
184+
```
185+
186+
It is often a good idea to bind to a style object directly so that the template is cleaner:
187+
188+
```html
189+
<div v-bind:style="styleObject"></div>
190+
```
191+
192+
```js
193+
data: {
194+
styleObject: {
195+
color: 'red',
196+
fontSize: '13px'
197+
}
198+
}
199+
```
200+
201+
Again, the object syntax is often used in conjunction with computed properties that return objects.
202+
203+
### Array Syntax
204+
205+
The array syntax for `v-bind:style` allows you to apply multiple style objects to the same element:
206+
207+
```html
208+
<div v-bind:style="[baseStyles, overridingStyles]"></div>
209+
```
210+
211+
### Auto-prefixing
212+
213+
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.
214+
215+
### Multiple Values
216+
217+
You can provide an array of multiple (prefixed) values to a style property, for example:
218+
219+
```html
220+
<div v-bind:style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
221+
```
222+
223+
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.

0 commit comments

Comments
 (0)