v2.1.0 Hunter X Hunter
"You should enjoy the little detours to the fullest. Because that's where you'll find the things more important than what you want." - Ging Freecss
This is a pretty long releaes note - see a version with linkable TOC here
New Features
Scoped Slots
A scoped slot is a special type of slot that functions as a reusable template (that can be passed data to) instead of already-rendered-elements.
In a child component, simply pass data into a slot using normal prop syntax:
const Child = {
data () {
return { msg: 'hello from child' }
},
template: `
<div class="child">
<slot :text="msg"></slot>
</div>
`
}
In the parent, a <template>
element with a special attribute scope
indicates that it is a template for a scoped slot. The value of scope
is the name of a temporary variable that holds the props object passed from the child:
const Parent = {
components: { Child },
template: `
<div class="parent">
<child>
<template scope="props">
<span>hello from parent</span>
<span>{{ props.text }}</span>
</template>
</child>
</div>
`
}
If we render the above, the output will be:
<div class="parent">
<div class="child">
<span>hello from parent</span>
<span>hello from child</span>
</div>
</div>
The equivalent in raw render functions would be:
const Child = {
data () {
return { msg: 'hello from child' }
},
render (h) {
return h('div', { class: 'child' }, [
// <slot :text="msg"></slot>
this.$scopedSlots.default({ text: this.msg })
])
}
}
const Parent = {
render (h) {
return h('div', { class: 'parent' }, [
h(Child, {
// pass scopedSlots in the data object
// in the form of { name: props => VNode | Array<VNode> }
scopedSlots: {
default: props => [
h('span', 'hello from parent'),
h('span', props.text)
]
}
})
])
}
}
Notice how the scoped slot is simply a function under the hood.
A more typical use case for scoped slots would be a list component that allows the component consumer to customize how each item in the list should be rendered:
<my-awesome-list :items="items">
<!-- scoped slot can be named too -->
<template slot="item" scope="props">
<li class="my-fancy-item">{{ props.text }}</li>
</template>
</my-awesome-list>
And the template for the list component:
<ul>
<slot name="item"
v-for="item in items"
:text="item.text">
<!-- fallback content here -->
</slot>
</ul>
Conditional Keep Alive
<keep-alive>
can now be configured to conditionally cache components using the new include
and exclude
props. Both props can either be a comma-delimited string or a RegExp:
<!-- comma-delimited string -->
<keep-alive include="a,b">
<component :is="view"></component>
</keep-alive>
<!-- regex (use v-bind) -->
<keep-alive :include="/a|b/">
<component :is="view"></component>
</keep-alive>
The match is first checked on the component's own name
option, then its local registration name (the key in the parent's components
option) if the name
option is not available. Anonymous components cannot be matched against.
v-else-if
A new directive v-else-if
is introduced, and it works as you might have expected:
<div v-if="type === 'a'">A</div>
<div v-else-if="type === 'b'">B</div>
<div v-else>C</div>
Previously, if you write a template with multiple root-level elements with v-if
on each, you would receive a warning from the compiler. However, with v-else-if
it will be fine because now the compiler can safely infer that there will only be one root-level element:
Vue.component('example', {
// no more warnings!
template: `
<div v-if="type === 'a'">A</div>
<div v-else-if="type === 'b'">B</div>
<div v-else>C</div>
`
})
Relaxed Filter Usage
Filters are now also supported in v-bind
expressions (in addition to text interpolations):
<img v-bind:src="imgSrc | formatURL">
<!-- shorthand -->
<img :src="imgSrc | formatURL">
Misc
-
nextTick
now returns a Promise if no callback is provided and Promise is supported in the environment (@chrisvfritz via #3967). -
New mouse event modifiers for
v-on
:.ctrl
,.alt
,.shift
and.meta
. (@KingMario via #4034) -
v-bind
now supports the.camel
modifier (previously available in 1.x). This modifier allows camelizing av-bind
attribute name when using in-DOM templates, e.g. the SVGviewBox
attribute:<svg :view-box.camel="viewBox"></svg>
It is not needed if you are using string templates, or compiling with
vue-loader
/vueify
.
Dist Files Adjustments
Starting in 2.1.0, the following changes are applied to files in dist
directory:
- The old
vue.common.js
is now renamed tovue.runtime.common.js
. (So is themain
field inpackage.json
) - The new
vue.common.js
now contains a different build that targets CommonJS/bundler environments but includes the compiler.
The difference between dist/vue.js
and the new dist/vue.common.js
is that the former is hard-coded in development mode, while the latter can be in either mode depending on the environment variables injected by the build tools.
See a more detailed explanation here, or read below to see if you need to do anything.
What does this mean?
-
First, nothing will break because of these changes. You can upgrade first.
-
If you've been using the runtime-only build, no further action is needed.
-
If you've been using the standalone build by configuring the Webpack alias, it's recommended to make the following change to benefit from slightly better perf and smaller file size (only do this after upgrading to 2.1.0):
// before resolve: { alias: { vue$: 'vue/dist/vue.js' } } // after resolve: { alias: { vue$: 'vue/dist/vue.common.js' } }
vue-loader@10.0.0
vue-loader
gets a breaking release with the following changes:
vue-template-compiler
is now a peer dependency instead of a direct dependency. This allows the user to pinvue-template-compiler
to a specific version instead of relying on the implicit upgrades from a semver caret range.templateBuble
option is merged with thebuble
option. This means the template expressions will be using the same Buble configuration withbuble-loader
(if present).
In addition, all Buble base transforms are now enabled by default for template expression, including arrow functions and parameter destructuring (Note: the following examples all require Vue core ^2.1.0):
<!-- arrow functions in v-on handlers -->
<button @click="e => log(e)"></button>
<!-- destructuring in v-for -->
<li v-for="{ id, text } in items">
{{ id }} {{ text }}
</li>
<!-- destructuring in scoped slots -->
<my-component>
<template scope="{ id, text }">
<span>{{ id }} {{ text }}</span>
</template>
</my-component>
JSX Improvements
-
Using a function as children is now treated as the default scoped slot (note this requires Vue core 2.1.0):
// in parent render (h) { return ( <child> {props => <span>{props.text}</span>} </child> ) } // in child render (h) { return ( <div> {this.$scopedSlots.default({ text: 'hello' })} </div> ) }
-
babel-plugin-transform-vue-jsx
now also supports camelCase style props:// before return <button on-click={this.onClick}></button> // can now also be written as: return <button onClick={this.onClick}></button>
Note this change has a small implication if you have components that expects props like
onChange
: previouslyonChange
will be passed down as a prop, but now it will be treated as a listener (v-on:change
). All you need to do is instead of calling the prop function (this.onChange()
), emit an event instead (this.$emit('change')
). Your component's usage will remain the same to external consumers.
vue-server-renderer
- No longer requires explicitly setting
process.env.VUE_ENV=server
. Whenvue-server-renderer
is used, this flag is now automatically enabled.
vue-template-compiler
parseComponent
now also exposes custom language blocks in*.vue
files in addition to<script>
,<style>
and<template>
. See #4157 for more details.