Skip to content

Commit

Permalink
Component Change
Browse files Browse the repository at this point in the history
- `v-component` now takes only a string value (the component id)
- `Vue.component()` now also registers the component id as a custom element
- add new directive: `v-with`, which can be used in combination with `v-component` or standalone
  • Loading branch information
yyx990803 committed Jan 12, 2014
1 parent bd835ac commit 04249e3
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 39 deletions.
2 changes: 1 addition & 1 deletion component.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"src/directives/repeat.js",
"src/directives/on.js",
"src/directives/model.js",
"src/directives/component.js"
"src/directives/with.js"
],
"dependencies": {
"component/emitter": "*"
Expand Down
21 changes: 9 additions & 12 deletions src/compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,9 +226,11 @@ CompilerProto.compile = function (node, root) {

// special attributes to check
var repeatExp,
componentExp,
withKey,
partialId,
directive
directive,
componentId = utils.attr(node, 'component') || tagName.toLowerCase(),
componentCtor = compiler.getOption('components', componentId)

// It is important that we access these attributes
// procedurally because the order matters.
Expand All @@ -244,21 +246,16 @@ CompilerProto.compile = function (node, root) {
// repeat block cannot have v-id at the same time.
directive = Directive.parse('repeat', repeatExp, compiler, node)
if (directive) {
directive.Ctor = componentCtor
compiler.bindDirective(directive)
}

// v-component has 2nd highest priority
} else if (!root && (componentExp = utils.attr(node, 'component'))) {
// v-with has 2nd highest priority
} else if (!root && ((withKey = utils.attr(node, 'with')) || componentCtor)) {

directive = Directive.parse('component', componentExp, compiler, node)
directive = Directive.parse('with', withKey || '', compiler, node)
if (directive) {
// component directive is a bit different from the others.
// when it has no argument, it should be treated as a
// simple directive with its key as the argument.
if (componentExp.indexOf(':') === -1) {
directive.isSimple = true
directive.arg = directive.key
}
directive.Ctor = componentCtor
compiler.bindDirective(directive)
}

Expand Down
1 change: 1 addition & 0 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ var prefix = 'v',
'text',
'repeat',
'partial',
'with',
'component',
'component-id',
'transition'
Expand Down
2 changes: 1 addition & 1 deletion src/directives/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ module.exports = {
repeat : require('./repeat'),
model : require('./model'),
'if' : require('./if'),
component : require('./component'),
'with' : require('./with'),

attr: function (value) {
this.el.setAttribute(this.arg, value)
Expand Down
7 changes: 3 additions & 4 deletions src/directives/repeat.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,8 @@ module.exports = {
ctn = self.container = el.parentNode

// extract child VM information, if any
ViewModel = ViewModel || require('../viewmodel')
var componentId = utils.attr(el, 'component')
self.ChildVM = self.compiler.getOption('components', componentId) || ViewModel
ViewModel = ViewModel || require('../viewmodel')
self.Ctor = self.Ctor || ViewModel

// extract transition information
self.hasTrans = el.hasAttribute(config.attrs.transition)
Expand Down Expand Up @@ -169,7 +168,7 @@ module.exports = {
}, this.compiler)
}

item = new this.ChildVM({
item = new this.Ctor({
el: node,
data: data,
compilerOptions: {
Expand Down
11 changes: 5 additions & 6 deletions src/directives/component.js → src/directives/with.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
var utils = require('../utils')
var ViewModel

module.exports = {

Expand All @@ -17,16 +17,15 @@ module.exports = {
},

build: function (value) {
var Ctor = this.compiler.getOption('components', this.arg)
if (!Ctor) utils.warn('unknown component: ' + this.arg)
var options = {
ViewModel = ViewModel || require('../viewmodel')
var Ctor = this.Ctor || ViewModel
this.component = new Ctor({
el: this.el,
data: value,
compilerOptions: {
parentCompiler: this.compiler
}
}
this.component = new Ctor(options)
})
},

unbind: function () {
Expand Down
51 changes: 51 additions & 0 deletions test/functional/fixtures/component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Component</title>
<meta charset="utf-8">
</head>
<body>
<div id="test">
<!-- v-component + v-with -->
<div id="component-and-with" v-component="avatar" v-with="user"></div>

<!-- custom element + v-with -->
<avatar id="element-and-with" v-with="user"></avatar>

<!-- v-with alone -->
<div id="with" v-with="user">{{hi}} {{name}}</div>

<!-- v-component alone -->
<div id="component" v-component="simple"></div>

<!-- custom element alone -->
<simple id="element"></simple>
</div>
<script src="../../../dist/vue.js"></script>
<script>

Vue.config({debug: true})

Vue.component('avatar', {
template: '{{hi}} {{name}}',
ready: function () {
console.log(JSON.stringify(this))
}
})

Vue.component('simple', {
template: '{{hi}} {{user.name}}'
})

var app = new Vue({
el: '#test',
data: {
hi: '123',
user: {
name: 'Jack'
}
}
})
</script>
</body>
</html>
2 changes: 1 addition & 1 deletion test/functional/fixtures/extend.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<div class="filter">{{filterMsg | nodigits}}</div>
<div class="partial" v-partial="partial-test"></div>
<div class="vm" v-component="vm-test">{{vmMsg}}</div>
<div class="vm-w-model" v-component="vm-w-model:vmData">{{selfMsg + msg}}</div>
<div class="vm-w-model" v-component="vm-w-model" v-with="vmData">{{selfMsg + msg}}</div>
</div>
<div id="child">
<div class="cvm" v-component="vm-test">{{vmMsg}}</div>
Expand Down
17 changes: 17 additions & 0 deletions test/functional/specs/component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
casper.test.begin('Components', 5, function (test) {

casper
.start('./fixtures/component.html')
.then(function () {
var expected = '123 Jack'
test.assertSelectorHasText('#component-and-with', expected)
test.assertSelectorHasText('#element-and-with', expected)
test.assertSelectorHasText('#component', expected)
test.assertSelectorHasText('#with', expected)
test.assertSelectorHasText('#element', expected)
})
.run(function () {
test.done()
})

})
25 changes: 11 additions & 14 deletions test/unit/specs/directives.js
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ describe('UNIT: Directives', function () {

describe('component', function () {

it('should work with no args', function () {
it('should create a child viewmodel with given constructor', function () {
var testId = 'component-test'
mock(testId, '<div v-component="' + testId + '"></div>')
var t = new Vue({
Expand All @@ -528,25 +528,22 @@ describe('UNIT: Directives', function () {
assert.strictEqual(t.$el.querySelector('span').textContent, '123')
})

it('should work with arg (passed-in model from parent)', function () {
var testId = 'component-test-2'
mock(testId, '<div v-component="' + testId + ':options.test"></div>')
})

describe('with', function () {

it('should create a child viewmodel with given data', function () {
var testId = 'with-test'
mock(testId, '<span v-with="test">{{msg}}</span>')
var t = new Vue({
el: '#' + testId,
data: {
options: {
test: {
msg: '123'
}
}
},
components: {
'component-test-2': {
template: '<span>{{msg}}</span>'
test: {
msg: testId
}
}
})
assert.strictEqual(t.$el.querySelector('span').textContent, '123')
assert.strictEqual(t.$el.querySelector('span').textContent, testId)
})

})
Expand Down

0 comments on commit 04249e3

Please sign in to comment.