Skip to content

v2.1.0 Hunter X Hunter

Compare
Choose a tag to compare
@yyx990803 yyx990803 released this 22 Nov 16:15
· 2241 commits to main since this release

"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 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)