Skip to content

Instantly share code, notes, and snippets.

@yyx990803
Created November 22, 2016 16:16
Show Gist options
  • Save yyx990803/faebe22e8763f5b17572b35ed96f52fe to your computer and use it in GitHub Desktop.
Save yyx990803/faebe22e8763f5b17572b35ed96f52fe to your computer and use it in GitHub Desktop.

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 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)
@danshao
Copy link

danshao commented Nov 23, 2016

gz

@codedart2018
Copy link

牛逼,少年~!

@arnorhs
Copy link

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
Copy link

suweya commented Nov 23, 2016

cool

@liuxiaojiu
Copy link

cool , 版本迭代蛮快的 - -

@lincenying
Copy link

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

@kagawagao
Copy link

cool

@myst729
Copy link

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
Copy link

cool

@dukegod
Copy link

dukegod commented Nov 23, 2016

awesome

@pciapcib
Copy link

awesome

@icarusion
Copy link

cool

@SUpermin6u
Copy link

666

@rajibahmed
Copy link

:) 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
Copy link

mark

@chenxiaohuan
Copy link

cool

@jsm1003
Copy link

jsm1003 commented Dec 7, 2016

刚好用到了keep alive的新特性

@ayunami2000
Copy link

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