Skip to content

Commit c7d0e17

Browse files
committed
component scope update
1 parent 2fa36c0 commit c7d0e17

File tree

1 file changed

+133
-84
lines changed

1 file changed

+133
-84
lines changed

source/guide/components.md

Lines changed: 133 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -62,89 +62,15 @@ It is important to understand the difference between `Vue.extend()` and `Vue.com
6262

6363
Vue.js supports two different API paradigms: the class-based, imperative, Backbone style API, and the markup-based, declarative, Web Components style API. If you are confused, think about how you can create an image element with `new Image()`, or with an `<img>` tag. Each is useful in its own right and Vue.js provides both for maximum flexibility.
6464

65-
## Dynamic Components
66-
67-
You can dynamically switch between components by using Mustache tags inside the `v-component` direcitve, which can be used together with routers to achieve "page switching":
68-
69-
``` js
70-
new Vue({
71-
el: 'body',
72-
data: {
73-
currentView: 'home'
74-
},
75-
components: {
76-
home: { /* ... */ },
77-
posts: { /* ... */ },
78-
archive: { /* ... */ }
79-
}
80-
})
81-
```
82-
83-
``` html
84-
<div v-component="{&#123;currentView&#125;}">
85-
<!-- content changes when vm.currentview changes! -->
86-
</div>
87-
```
88-
89-
If you want to keep the switched-out components alive so that you can preserve its state or avoid re-rendering, you can add a `keep-alive` directive param:
90-
91-
``` html
92-
<div v-component="{&#123;currentView&#125;}" keep-alive>
93-
<!-- inactive components will be cached! -->
94-
</div>
95-
```
96-
97-
## Component Lifecycle
98-
99-
Every component, or Vue instance, has its own lifecycle: it will be created, compiled, inserted or detached, and finally destroyed. At each of these key moments the instance will emit corresponding events, and when creating an instance or defining a component, we can pass in lifecycle hook functions to react to these events. For example:
100-
101-
``` js
102-
var MyComponent = Vue.extend({
103-
created: function () {
104-
console.log('An instance of MyComponent has been created!')
105-
}
106-
})
107-
```
108-
109-
Check out the API reference for a [full list of lifecycle hooks](/api/options.html#Lifecycle) that are availble.
110-
11165
## Data Inheritance
11266

113-
### Scope Inheritance
114-
115-
By default, components have **isolated scope**. This means you cannot reference parent data in a child component's template. If you want though, you can use the `inherit: true` option for your child component to make it prototypally inherit parent properties:
116-
117-
``` js
118-
var parent = new Vue({
119-
data: {
120-
a: 1
121-
}
122-
})
123-
// $addChild() is an instance method that allows you to
124-
// programatically create a child instance.
125-
var child = parent.$addChild({
126-
inherit: true,
127-
data: {
128-
b: 2
129-
}
130-
})
131-
console.log(child.a) // -> 1
132-
console.log(child.b) // -> 2
133-
parent.a = 3
134-
console.log(child.a) // -> 3
135-
```
136-
137-
Note this comes with a caveat: because data properties on Vue instances are getter/setters, setting `child.a = 2` will change `parent.a` instead of creating a new property on the child shadowing the parent one:
67+
### Explicit Data Passing
13868

139-
``` js
140-
child.a = 4
141-
console.log(parent.a) // -> 4
142-
console.log(child.hasOwnProperty('a')) // -> false
143-
```
69+
By default, components have **isolated scope**. This means you cannot reference parent data in a child component's template. To explicitly pass data to child components with isolated scope, we can use the `v-with` directive.
14470

145-
### Explicit Data Passing
71+
#### Passing Down Child `$data`
14672

147-
To explicitly pass data to child components with isolated scope, we can use the `v-with` directive. When given a single keypath without an argument, the corresponding value on the parent will be passed down to the child as its `$data`. This means the passed-down value must be an object, and it will overwrite the default `$data` object the child component might have.
73+
When given a single keypath without an argument, the corresponding value on the parent will be passed down to the child as its `$data`. This means the passed-down value must be an object, and it will overwrite the default `$data` object the child component might have.
14874

14975
**Example:**
15076

@@ -190,12 +116,14 @@ var parent = new Vue({
190116
})
191117
</script>
192118

119+
#### Passing Down Individual Properties
120+
193121
`v-with` can also be used with an argument in the form of `v-with="childProp: parentProp"`. This means passing down `parent[parentProp]` to the child as `child[childProp]`. Note this data inheritance is one-way: when `parentProp` changes, `childProp` will be updated accordingly, however not the other way around.
194122

195123
**Example:**
196124

197125
``` html
198-
<div id="parent">
126+
<div id="demo-2">
199127
<input v-model="parentMsg">
200128
<p v-component="child" v-with="childMsg : parentMsg">
201129
<!-- essentially means "bind `parentMsg` on me as `childMsg`" -->
@@ -205,24 +133,24 @@ var parent = new Vue({
205133

206134
``` js
207135
new Vue({
208-
el: '#parent',
136+
el: '#demo-2',
209137
data: {
210138
parentMsg: 'Inherited message'
211139
},
212140
components: {
213141
child: {
214-
template: '<span v-text="childMsg"></span>'
142+
template: '<span>{&#123;childMsg&#125;}</span>'
215143
}
216144
}
217145
})
218146
```
219147

220148
**Result:**
221149

222-
<div id="parent" class="demo"><input v-model="parentMsg"><p v-component="child" v-with="childMsg:parentMsg"></p></div>
150+
<div id="demo-2" class="demo"><input v-model="parentMsg"><p v-component="child" v-with="childMsg:parentMsg"></p></div>
223151
<script>
224152
new Vue({
225-
el: '#parent',
153+
el: '#demo-2',
226154
data: {
227155
parentMsg: 'Inherited message'
228156
},
@@ -234,7 +162,126 @@ new Vue({
234162
})
235163
</script>
236164

237-
## Components and `v-repeat`
165+
#### Using `paramAttributes`
166+
167+
It is also possible to use the [`paramAttributes`](/api/options.html#paramAttributes) option, which compiles into `v-with`, to expose an interface that looks more like custom elements:
168+
169+
``` html
170+
<div id="demo-3">
171+
<input v-model="parentMsg">
172+
<child-component child-msg="parentMsg"></p>
173+
</div>
174+
```
175+
176+
``` js
177+
new Vue({
178+
el: '#demo-3',
179+
data: {
180+
parentMsg: 'Inherited message'
181+
},
182+
components: {
183+
'child-component': {
184+
paramAttributes: ['child-msg'],
185+
// dashed attributes are camelized,
186+
// so 'child-msg' becomes 'this.childMsg'
187+
template: '<span>{&#123;childMsg&#125;}</span>'
188+
}
189+
}
190+
})
191+
```
192+
193+
### Scope Inheritance
194+
195+
If you want, you can also use the `inherit: true` option for your child component to make it prototypally inherit all parent properties:
196+
197+
``` js
198+
var parent = new Vue({
199+
data: {
200+
a: 1
201+
}
202+
})
203+
// $addChild() is an instance method that allows you to
204+
// programatically create a child instance.
205+
var child = parent.$addChild({
206+
inherit: true,
207+
data: {
208+
b: 2
209+
}
210+
})
211+
console.log(child.a) // -> 1
212+
console.log(child.b) // -> 2
213+
parent.a = 3
214+
console.log(child.a) // -> 3
215+
```
216+
217+
Note this comes with a caveat: because data properties on Vue instances are getter/setters, setting `child.a = 2` will change `parent.a` instead of creating a new property on the child shadowing the parent one:
218+
219+
``` js
220+
child.a = 4
221+
console.log(parent.a) // -> 4
222+
console.log(child.hasOwnProperty('a')) // -> false
223+
```
224+
225+
### A Note on Scope
226+
227+
When a component is used in a parent template, e.g.:
228+
229+
``` html
230+
<!-- parent template -->
231+
<div v-component v-show="active" v-on="click:onClick"></div>
232+
```
233+
234+
The directives here (`v-show` and `v-on`) will be compiled in the parent's scope, so the value of `active` and `onClick` will be resolved against the parent. Any directives/interpolations inside the child's template will be compiled in the child's scope. This ensures a cleaner separation between parent and child components.
235+
236+
This rule also applies to [content insertion](#Content_Insertion), as explained later in this guide.
237+
238+
## Component Lifecycle
239+
240+
Every component, or Vue instance, has its own lifecycle: it will be created, compiled, inserted or detached, and finally destroyed. At each of these key moments the instance will emit corresponding events, and when creating an instance or defining a component, we can pass in lifecycle hook functions to react to these events. For example:
241+
242+
``` js
243+
var MyComponent = Vue.extend({
244+
created: function () {
245+
console.log('An instance of MyComponent has been created!')
246+
}
247+
})
248+
```
249+
250+
Check out the API reference for a [full list of lifecycle hooks](/api/options.html#Lifecycle) that are availble.
251+
252+
## Dynamic Components
253+
254+
You can dynamically switch between components by using Mustache tags inside the `v-component` direcitve, which can be used together with routers to achieve "page switching":
255+
256+
``` js
257+
new Vue({
258+
el: 'body',
259+
data: {
260+
currentView: 'home'
261+
},
262+
components: {
263+
home: { /* ... */ },
264+
posts: { /* ... */ },
265+
archive: { /* ... */ }
266+
}
267+
})
268+
```
269+
270+
``` html
271+
<div v-component="{&#123;currentView&#125;}">
272+
<!-- content changes when vm.currentview changes! -->
273+
</div>
274+
```
275+
276+
If you want to keep the switched-out components alive so that you can preserve its state or avoid re-rendering, you can add a `keep-alive` directive param:
277+
278+
``` html
279+
<div v-component="{&#123;currentView&#125;}" keep-alive>
280+
<!-- inactive components will be cached! -->
281+
</div>
282+
```
283+
284+
## List and Components
238285

239286
For an Array of Objects, you can combine `v-component` with `v-repeat`. In this case, for each Object in the Array, a child ViewModel will be created using that Object as data, and the specified component as the constructor.
240287

@@ -391,6 +438,8 @@ MyComponent
391438

392439
When creating reusable components, we often need to access and reuse the original content in the hosting element, which are not part of the component (similar to the Angular concept of "transclusion".) Vue.js implements a content insertion mechanism that is compatible with the current Web Components spec draft, using the special `<content>` element to serve as insertion points for the original content.
393440

441+
<p class="tip">Note: "transcluded" contents are compiled in the parent component's scope.</p>
442+
394443
### Single Insertion Point
395444

396445
When there is only one `<content>` tag with no attributes, the entire original content will be inserted at its position in the DOM and replaces it. Anything originally inside the `<content>` tags is considered **fallback content**. Fallback content will only be displayed if the hosting element is empty and has no content to be inserted. For example:

0 commit comments

Comments
 (0)