Skip to content

Commit

Permalink
support default scoped slot + function children as scoped slot
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Nov 20, 2016
1 parent 745f8a9 commit 303378f
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 24 deletions.
1 change: 1 addition & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"presets": ["es2015", "flow-vue"],
"plugins": ["transform-vue-jsx"],
"ignore": [
"dist/*.js",
"packages/**/*.js"
Expand Down
1 change: 1 addition & 0 deletions flow/vnode.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ declare interface VNodeData {
};
directives?: Array<VNodeDirective>;
keepAlive?: boolean;
scopedSlots?: { [key: string]: Function }
}

declare type VNodeDirective = {
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,11 @@
"devDependencies": {
"babel-core": "^6.9.0",
"babel-eslint": "^7.1.0",
"babel-helper-vue-jsx-merge-props": "^2.0.2",
"babel-loader": "^6.2.4",
"babel-plugin-coverage": "^1.0.0",
"babel-plugin-syntax-jsx": "^6.18.0",
"babel-plugin-transform-vue-jsx": "^3.2.0",
"babel-preset-es2015": "^6.9.0",
"babel-preset-flow-vue": "^1.0.0",
"buble": "^0.14.0",
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/parser/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ function processSlot (el) {
} else {
const slotTarget = getBindingAttr(el, 'slot')
if (slotTarget) {
el.slotTarget = slotTarget
el.slotTarget = slotTarget === '""' ? '"default"' : slotTarget
el.slotScope = getAndRemoveAttr(el, 'scope')
}
}
Expand Down
3 changes: 0 additions & 3 deletions src/core/instance/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,9 +191,6 @@ export function renderMixin (Vue: Class<Component>) {
fallback: ?Array<VNode>,
props: ?Object
): ?Array<VNode> {
if (process.env.NODE_ENV !== 'production' && name === 'default' && props) {
warn(`Scoped slots must be named`, this)
}
const scopedSlotFn = this.$scopedSlots && this.$scopedSlots[name]
if (scopedSlotFn) { // scoped slot
return scopedSlotFn(props || {}) || fallback
Expand Down
7 changes: 7 additions & 0 deletions src/core/vdom/create-element.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ export function _createElement (
// in case of component :is set to falsy value
return emptyVNode()
}
// support single function children as default scoped slot
if (Array.isArray(children) &&
typeof children[0] === 'function') {
data = data || {}
data.scopedSlots = { default: children[0] }
children.length = 0
}
if (typeof tag === 'string') {
let Ctor
const ns = config.getTagNamespace(tag)
Expand Down
86 changes: 66 additions & 20 deletions test/unit/features/component/component-scoped-slot.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
import Vue from 'vue'

describe('Component scoped slot', () => {
it('default slot', () => {
const vm = new Vue({
template: `<test><span slot scope="props">{{ props.msg }}</span></test>`,
components: {
test: {
data () {
return { msg: 'hello' }
},
template: `
<div>
<slot :msg="msg"></slot>
</div>
`
}
}
}).$mount()
expect(vm.$el.innerHTML).toBe('<span>hello</span>')
})

it('normal element slot', done => {
const vm = new Vue({
template: `
Expand Down Expand Up @@ -204,25 +223,6 @@ describe('Component scoped slot', () => {
expect(vm.$el.innerHTML).toBe('<span>meh</span>')
})

it('warn un-named scoped slot', () => {
new Vue({
template: `<test><span scope="lol"></span></test>`,
components: {
test: {
data () {
return { msg: 'hello' }
},
template: `
<div>
<slot :msg="msg"></slot>
</div>
`
}
}
}).$mount()
expect('Scoped slots must be named').toHaveBeenWarned()
})

it('warn key on slot', () => {
new Vue({
template: `
Expand Down Expand Up @@ -250,7 +250,7 @@ describe('Component scoped slot', () => {
expect(`\`key\` does not work on <slot>`).toHaveBeenWarned()
})

it('render function usage', done => {
it('render function usage (named, via data)', done => {
const vm = new Vue({
render (h) {
return h('test', {
Expand Down Expand Up @@ -282,4 +282,50 @@ describe('Component scoped slot', () => {
expect(vm.$el.innerHTML).toBe('<span>world</span>')
}).then(done)
})

it('render function usage (default, as children)', () => {
const vm = new Vue({
render (h) {
return h('test', [
props => h('span', [props.msg])
])
},
components: {
test: {
data () {
return { msg: 'hello' }
},
render (h) {
return h('div', [
this.$scopedSlots.default({ msg: this.msg })
])
}
}
}
}).$mount()
expect(vm.$el.innerHTML).toBe('<span>hello</span>')
})

it('render function usage (JSX)', () => {
const vm = new Vue({
render (h) {
return <test>{
props => <span>{props.msg}</span>
}</test>
},
components: {
test: {
data () {
return { msg: 'hello' }
},
render (h) {
return <div>
{this.$scopedSlots.default({ msg: this.msg })}
</div>
}
}
}
}).$mount()
expect(vm.$el.innerHTML).toBe('<span>hello</span>')
})
})

0 comments on commit 303378f

Please sign in to comment.