Create a gist now

Instantly share code, notes, and snippets.

Embed

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 a v-bind attribute name when using in-DOM templates, e.g. the SVG viewBox 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 to vue.runtime.common.js. (So is the main field in package.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 pin vue-template-compiler to a specific version instead of relying on the implicit upgrades from a semver caret range.

  • templateBuble option is merged with the buble option. This means the template expressions will be using the same Buble configuration with buble-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: previously onChange 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. When vue-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.

Fixed

  • #4268 properly handle unicode newlines /u2028 and /u2029 in templates
  • #4266 fix dropping scoped CSS after global mixin application when exporting constructors in single file components (@ktsn via #4274)
@blackcater

This comment has been minimized.

Show comment
Hide comment

Sofa :)

@KentonYu

This comment has been minimized.

Show comment
Hide comment

cool

@surmon-china

This comment has been minimized.

Show comment
Hide comment

bench :)

@zhangking

This comment has been minimized.

Show comment
Hide comment

cool~

@danshao

This comment has been minimized.

Show comment
Hide comment

danshao commented Nov 23, 2016

gz

@myxingke

This comment has been minimized.

Show comment
Hide comment
@myxingke

myxingke Nov 23, 2016

牛逼,少年~!

牛逼,少年~!

@arnorhs

This comment has been minimized.

Show comment
Hide comment
@arnorhs

arnorhs Nov 23, 2016

shouldn't that example be (props.msg, intead of props.text):

const Parent = {
  components: { Child },
  template: `
    <div class="parent">
      <child>
        <template scope="props">
          <span>hello from parent</span>
          <span>{{ props.msg }}</span>
        </template>
      </child>
    </div>
  `
}

or i guess, judging from the other example snipets, maybe it's the .msg that's the wrong one.. or i don't understand the feature at all :)

arnorhs commented Nov 23, 2016

shouldn't that example be (props.msg, intead of props.text):

const Parent = {
  components: { Child },
  template: `
    <div class="parent">
      <child>
        <template scope="props">
          <span>hello from parent</span>
          <span>{{ props.msg }}</span>
        </template>
      </child>
    </div>
  `
}

or i guess, judging from the other example snipets, maybe it's the .msg that's the wrong one.. or i don't understand the feature at all :)

@suweya

This comment has been minimized.

Show comment
Hide comment

suweya commented Nov 23, 2016

cool

@liuxiaojiu

This comment has been minimized.

Show comment
Hide comment
@liuxiaojiu

liuxiaojiu Nov 23, 2016

cool , 版本迭代蛮快的 - -

cool , 版本迭代蛮快的 - -

@lincenying

This comment has been minimized.

Show comment
Hide comment
@lincenying

lincenying Nov 23, 2016

终于有else-if了...泪流满面...

终于有else-if了...泪流满面...

@kagawagao

This comment has been minimized.

Show comment
Hide comment

cool

@myst729

This comment has been minimized.

Show comment
Hide comment
@myst729

myst729 Nov 23, 2016

Filter for v-bind is great!

@arnorhs

msg is scoped within Child. It's bond to the <slot/> with the prop text, and this prop is exposed to the outside. So to access it from Parent, you should use props.text. Very nice feature, just applied in my scaffolding app.

myst729 commented Nov 23, 2016

Filter for v-bind is great!

@arnorhs

msg is scoped within Child. It's bond to the <slot/> with the prop text, and this prop is exposed to the outside. So to access it from Parent, you should use props.text. Very nice feature, just applied in my scaffolding app.

@jansesun

This comment has been minimized.

Show comment
Hide comment

cool

@dukegod

This comment has been minimized.

Show comment
Hide comment

dukegod commented Nov 23, 2016

awesome

@pciapcib

This comment has been minimized.

Show comment
Hide comment

awesome

@icarusion

This comment has been minimized.

Show comment
Hide comment

cool

@SUpermin6u

This comment has been minimized.

Show comment
Hide comment

666

@rajibahmed

This comment has been minimized.

Show comment
Hide comment
@rajibahmed

rajibahmed Nov 25, 2016

:) I love the middle ground taken by VueJS, oppose to overwhelming technological jargon opinions - to a actually simple
api that works, does not require plumbing.

You guys nailed it !! thank your for the amazing code and its corresponding documentation.

:) I love the middle ground taken by VueJS, oppose to overwhelming technological jargon opinions - to a actually simple
api that works, does not require plumbing.

You guys nailed it !! thank your for the amazing code and its corresponding documentation.

@HankLiang

This comment has been minimized.

Show comment
Hide comment

mark

@chenxiaohuan

This comment has been minimized.

Show comment
Hide comment

cool

@jsm1003

This comment has been minimized.

Show comment
Hide comment
@jsm1003

jsm1003 Dec 7, 2016

刚好用到了keep alive的新特性

jsm1003 commented Dec 7, 2016

刚好用到了keep alive的新特性

@ayunami2000

This comment has been minimized.

Show comment
Hide comment
@ayunami2000

ayunami2000 Dec 27, 2016

On your comment on jshipster_templates.js
Improved to:

var screen = 'Dat Boi';
var user = '@DatBoi';
var rank = 'MLG';
var txt = 'lel\n\n\nnubz';
var msg = '{rank} {screen} {user}: {msg}'.replace('{user}', '('+user+')').replace('{rank}', '['+rank+']').replace('{msg}', txt).replace('{screen}', screen);
alert(msg);

A very easy forum soon-to-be

On your comment on jshipster_templates.js
Improved to:

var screen = 'Dat Boi';
var user = '@DatBoi';
var rank = 'MLG';
var txt = 'lel\n\n\nnubz';
var msg = '{rank} {screen} {user}: {msg}'.replace('{user}', '('+user+')').replace('{rank}', '['+rank+']').replace('{msg}', txt).replace('{screen}', screen);
alert(msg);

A very easy forum soon-to-be

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment