- New Features
- Dist Files Adjustments
- [email protected]
- JSX Improvements
- vue-server-renderer
- vue-template-compiler
- Fixed
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><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.
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>
`
})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">-
nextTicknow 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,.shiftand.meta. (@KingMario via #4034) -
v-bindnow supports the.camelmodifier (previously available in 1.x). This modifier allows camelizing av-bindattribute name when using in-DOM templates, e.g. the SVGviewBoxattribute:<svg :view-box.camel="viewBox"></svg>
It is not needed if you are using string templates, or compiling with
vue-loader/vueify.
Starting in 2.1.0, the following changes are applied to files in dist directory:
-
The old
vue.common.jsis now renamed tovue.runtime.common.js. (So is themainfield inpackage.json) -
The new
vue.common.jsnow 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.
-
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 gets a breaking release with the following changes:
-
vue-template-compileris now a peer dependency instead of a direct dependency. This allows the user to pinvue-template-compilerto a specific version instead of relying on the implicit upgrades from a semver caret range. -
templateBubleoption is merged with thebubleoption. 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>-
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-jsxnow 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: previouslyonChangewill 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.
- No longer requires explicitly setting
process.env.VUE_ENV=server. Whenvue-server-rendereris used, this flag is now automatically enabled.
parseComponentnow also exposes custom language blocks in*.vuefiles in addition to<script>,<style>and<template>. See #4157 for more details.
- #4268 properly handle unicode newlines
/u2028and/u2029in templates - #4266 fix dropping scoped CSS after global mixin application when exporting constructors in single file components (@ktsn via #4274)
awesome