Component Change

- `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
This commit is contained in:
Evan You 2014-01-12 15:37:50 -05:00
parent bd835ac276
commit 04249e320a
10 changed files with 100 additions and 39 deletions

View File

@ -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": "*"

View File

@ -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.
@ -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)
}

View File

@ -4,6 +4,7 @@ var prefix = 'v',
'text',
'repeat',
'partial',
'with',
'component',
'component-id',
'transition'

View File

@ -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)

View File

@ -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)
@ -169,7 +168,7 @@ module.exports = {
}, this.compiler)
}
item = new this.ChildVM({
item = new this.Ctor({
el: node,
data: data,
compilerOptions: {

View File

@ -1,4 +1,4 @@
var utils = require('../utils')
var ViewModel
module.exports = {
@ -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 () {

View File

@ -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>

View File

@ -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>

View File

@ -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()
})
})

View File

@ -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({
@ -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)
})
})