vuejs / vue

This is the repo for Vue 2. For Vue 3, go to https://github.com/vuejs/core
http://v2.vuejs.org
MIT License
207.21k stars 33.64k forks source link

2.0 Changes #2873

Closed yyx990803 closed 7 years ago

yyx990803 commented 8 years ago

This is a live document. Last update: 08/17/2016 as of 2.0.0-rc.2

General Notes

  • A checked item means it has been implemented in the 2.0 development branch.
  • Features subject to change during development.
  • The breaking change list is not guaranteed to be complete during development.
  • There are some upgrade tips at the end.

    High Level Changes

  • The template parser no longer relies on the DOM (unless you are using the real DOM as your template), so as long as you are using string templates (<script type="text/x-template">, inline JavaScript strings, or compiled via single-file components), you are no longer subject to any of the template parsing limitations in 1.x. However, if you are relying on mounting to an element with existing content as template (using the el option), you will still be subject to those limitations.
  • The compiler (the part which converts a template string to a render function) and the runtime can now be separated. There will be two different builds:
  • Standalone build: includes both the compiler and the runtime. This functions basically exactly the same Vue 1.x does.
  • Runtime only build: since it doesn't include the compiler, you need to either pre-compiled templates in a compile step, or manually written render functions. The npm package will export this build by default, since when consuming Vue from npm, you will likely be using a compilation step (with Browserify or Webpack), during which vueify or vue-loader will perform the template pre-compilation.

    Global config

  • [x] Vue.config.silent
  • [x] Vue.config.optionMergeStrategies
  • [x] Vue.config.devtools
  • [x] Vue.config.errorHandler new - global hook for handling uncaught errors during component render and watchers (default behavior is logging the error stack throwing in place)
  • [x] Vue.config.keyCodes new - configure custom key aliases for v-on.
  • Vue.config.debug deprecated, no longer useful since warnings come with stack traces by default now
  • Vue.config.async deprecated, async is required for rendering performance
  • Vue.config.delimiters reworked as a component-level option
  • Vue.config.unsafeDelimiters deprecated, use v-html

    Global API

  • [x] Vue.extend
  • [x] Vue.nextTick
  • [x] Vue.set
  • [x] Vue.delete
  • [x] Vue.directive
  • [x] Vue.component
  • [x] Vue.use
  • [x] Vue.mixin
  • [x] Vue.compile new (only in standalone build)
  • [x] Vue.transition
  • stagger deprecated, set and access data-index on el instead
  • [x] Vue.filter
  • Vue.elementDirective deprecated, just use components
  • Vue.partial deprecated, use functional components

    Options

    data
  • [x] data
  • [x] props
  • [x] prop validation
  • [x] default value
  • coerce deprecated. If you want to convert a prop, setup a local computed value based on it.
  • prop binding modes deprecated (v-model can work on components)
  • [x] propsData new, instantiation only
  • [x] computed
  • [x] methods
  • [x] watch
    DOM
  • [x] el
  • [x] template
  • [x] render new
  • replace deprecated, components now must have exactly one root element.
    Lifecycle Hooks
  • [x] init beforeCreate
  • [x] created
  • [x] beforeDestroy
  • [x] destroyed
  • [x] beforeMount new
  • [x] mounted new
  • [x] beforeUpdate new
  • [x] updated new
  • [x] activated new (for keep-alive)
  • [x] deactivated new (for keep-alive)
  • [x] ready deprecated, use mounted (there's no longer the guarantee to be in-document)
  • activate deprecated, moved into vue-router
  • beforeCompile deprecated, use created
  • compiled deprecated, use mounted
  • attached deprecated, use custom in-dom check in other hooks
  • detached deprecated, same as above
    Assets
  • [x] directives
  • [x] components
  • [x] transitions
  • [x] filters
  • partials deprecated
  • elementDirectives deprecated
    Misc
  • [x] parent
  • [x] mixins
  • [x] name
  • [x] extends
  • [x] delimiters new, replacing the original global config option. Only available in standalone build.
  • [x] functional new, makes the component stateless and instance-less (just a render function that returns virtual nodes)
  • events deprecated, since no more event propagation

    Instance Properties

  • [x] vm.$data
  • [x] vm.$el
  • [x] vm.$options
  • [x] vm.$parent
  • [x] vm.$root
  • [x] vm.$children
  • [x] vm.$refs
  • vm.$els deprecated, merged with $refs

    Instance Methods

    data
  • [x] vm.$watch
  • vm.$get deprecated, just retrieve values directly
  • vm.$set deprecated, use Vue.set
  • vm.$delete deprecated, use Vue.delete
  • vm.$eval deprecated, no real use
  • vm.$interpolate deprecated, no real use
  • vm.$log deprecated, use devtools
    events
  • [x] vm.$on
  • [x] vm.$once
  • [x] vm.$off
  • [x] vm.$emit
  • vm.$dispatch deprecated, use global event bus or Vuex. (see below)
  • vm.$broadcast deprecated, same as above
    DOM
  • [x] vm.$nextTick
  • vm.$appendTo deprecated, just use native DOM API on vm.$el.
  • vm.$before deprecated
  • vm.$after deprecated
  • vm.$remove deprecated
    Lifecycle
  • [x] vm.$mount
  • [x] vm.$destroy

    Directives

  • [x] v-text
  • [x] v-html but {{{ }}} shorthand has been deprecated
  • [x] v-if
  • [x] v-show
  • [x] v-else
  • [x] v-for
  • [x] key (replacing track-by)
  • [x] Object v-for
  • [x] range v-for
  • [x] argument order updates: (value, index) in arr, (value, key, index) in obj
  • $index and $key deprecated
  • [x] v-on
  • [x] modifiers
  • [x] on child component
  • [x] custom keyCodes (now avaiable via Vue.config.keyCodes instead of Vue.directive('on').keyCodes)
  • [x] v-bind
  • [x] as prop
  • [x] xlink
  • [x] bind object
  • [x] v-bind:style
  • [x] prefix sniffing
  • [x] v-bind:class
  • [x] v-model
  • [x] lazy (as modifier)
  • [x] number (as modifier)
  • [x] ignoring composition events
  • debounce deprecated, use v-on:input + 3rd party debounce function
  • [x] v-cloak
  • [x] v-pre
  • [x] v-once new
  • v-ref now just a special attribute as ref
  • v-el deprecated (merged with ref)

    Special Components

  • [x] <component>
  • [x] :is
  • [x] async components
  • [x] inline-template
  • [x] <transition>
  • [x] <transition-group>
  • [x] <keep-alive>
  • [x] <slot>
  • partial deprecated

    Special Attributes

  • [x] key
  • [x] ref
  • [x] slot

    Server-side Rendering

  • [x] renderToString
  • [x] renderToStream
  • [x] client-side hydration

    Other Breaking Changes

    v-for iteration syntax change

  • Deprecating $index and $key

Both of these are being deprecated in favor of more explicit named indices and keys. This syntax is a bit magical and has limitations in nested loops. As a bonus, there will be two fewer points of syntax for newcomers to learn.

In general, in 2.0 directives have a greatly reduced scope of responsibility: they are now only used for applying low-level direct DOM manipulations. In most cases, you should prefer using Components as the main code-reuse abstraction.

Directives no longer have instances - this means there's no more this inside directive hooks and bind, update and unbind now receives everything as arguments.

Note the binding object is immutable, setting binding.value will have no effect, and properties added to it will not be persisted. You can persist directive state on el if you absolutely need to:

<div v-example:arg.modifier="a.b"></div>
// example directive
export default {
  bind (el, binding, vnode) {
    // the binding object exposes value, oldValue, expression, arg and modifiers.
    binding.expression // "a.b"
    binding.arg // "arg"
    binding.modifiers // { modifier: true }
    // the context Vue instance can be accessed as vnode.context.
  },

  // update has a few changes, see below
  update (el, binding, vnode, oldVnode) { ... },

  // componentUpdated is a new hook that is called AFTER the entire component
  // has completed the current update cycle. This means all the DOM would
  // be in updated state when this hook is called. Also, this hook is always
  // called regardless of whether this directive's value has changed or not.
  componentUpdated (el, binding, vnode, oldVNode) { ... },

  unbind (el, binding, vnode) { ... }
}

You can use destructuring if you only care about the value:

export default {
  bind (el, { value }) {
    // ...
  }
}

In addition, the update hook has a few changes:

  1. It no longer gets called automatically after bind.
  2. It now always gets calls when the component is re-rendered, regardless of whether the value it's bound to has changed or not. You can compare binding.value === binding.oldValue to skip unnecessary updates, but there are also cases where you'd want to always apply updates, e.g. when the directive is bound to an Object that might have been mutated instead of replaced.

elementDirective, directive params and directive options such as acceptStatement, deep etc. are all deprecated.

Filter Usage and Syntax Change

In Vue 2.0, there are several changes to the filter system:

  1. Filters can now only be used inside text interpolations ({{}} tags). In the past we've found using filters with directives such as v-model, v-on etc. led to more complexity than convenience, and for list filtering on v-for it is more appropriate to move that logic into JavaScript as computed properties.
  2. Vue 2.0 will not ship with any built-in filters. It is recommended to use standalone libraries dedicated for solving problems in a specific domain, e.g. moment.js for formatting dates and accounting.js for formatting financial currencies. You are also welcome to create your own filter pack and share it with the community!
  3. The filter syntax has changed to be more inline with JavaScript function invocation, instead of taking space-delimited arguments:

    {{ date | formatDate('YY-MM-DD') }}

    Transition System

Transition CSS class changes:

The always-on v-transition class is no longer added and Vue now uses the same classes Angular and React CSSTransitionGroup does:

keep-alive is no longer a special attribute: it is now a wrapper component, similar to <transition>:

  <keep-alive>
    <component :is="view"></component>
  </keep-alive>

This makes it possible to use keep-alive on multiple conditional children (note the children should eventually evaluate to a single child - any child other than the first one will be ignored):

  <keep-alive>
    <comp-a v-if="a > 1"></comp-a>
    <comp-b v-else></comp-b>
  </keep-alive>

When used together with <transition>, make sure to nest it inside:

  <transition>
    <keep-alive>
      <component :is="view"></component>
    </keep-alive>
  </transition>

Slots

The reason that we are deprecating $dispatch and $broadcast is that event flows that depend on the components tree structure can be hard to reason about when the components tree becomes large (simply put: it doesn't scale well in large apps and we don't want to set you up for pain later). $dispatch and $broadcast also do not solve the communication between sibling components. Instead, you can use a pattern similar to the EventEmitter in Node.js: a centralized event hub that allows components to communicate, no matter where they are in the components tree. Because Vue instances implement the event emitter interface, you can actually use an empty Vue instance for that purpose:

var bus = new Vue()
// in component A's method
bus.$emit('id-selected', 1)
// in component B's created hook
bus.$on('id-selected', this.someMethod)

And don't forget to use $off to unbind the event.

// in component B's destroyed hook
bus.$off('id-selected', this.someMethod)

This pattern can serve as a replacement for $dispatch and $broadcast in simple scenarios. But for more complex cases, it is recommended to introduce a dedicated state management layer using Vuex.

How to Deal with the Deprecation of Array Filters?

For list filtering with v-for - one of the more common usage of filters - it is now recommended to use computed properties that return a processed copy of the original Array (see updated data grid example). The benefits is that you are no longer limited by the arbitrary filter syntax/API - it's just plain JavaScript now, and you naturally have access to the filtered result because it is a computed property.

Also see this discussion thread.

How to Deal with the Deprecation of debounce for v-model?

Debouncing is used to limit how often we execute Ajax requests and other expensive operations. Vue's debounce attribute parameter for v-model makes this easy, but it also debounces state updates rather than the expensive operations themselves, which comes with limitations.

These limitations become apparent when designing a search indicator. Take a look at that example. Using the debounce attribute, there'd be no way to detect a dirty input before the search begins, because we'd lose access to the input's real-time state. By decoupling the debounce function from Vue, we're able to debounce only the operation we want to limit.

There will be other times when debouncing isn't quite the right wrapper function. In the very common example of hitting an API for search suggestions, waiting to offer suggestions until after the user has stopped typing isn't an ideal experience. What you probably want instead is a throttling function. Now since you're already using a utility library like lodash for debounce, refactoring to use throttle instead takes only a few seconds!

franciscolourenco commented 7 years ago

What about providing an interface to create custom v-model modifiers as a way to replace 2 way filters? It seems they are already being used to parse user input (for example v-model.trim). If the parsing/ formatting is simple and independent from a specific data property, using a modifier would allow the parsing/formatting to be reused with much less boilerplate than by setting a computed property for each individual data property, or creating a new component for each input type where we want the parsing/formatting to be applied.

kemar commented 7 years ago

Hi, I'm currently working on a plugin to support gettext in Vue.js 1.0 and I have a directive that is using vm.$interpolate.

I'm wondering how to migrate my code to 2.0 since:

Or is there a better approach than a directive?

import languages from 'src/plugins/translate/languages'
import translateUtils from 'src/plugins/translate/utils'

const translateDirective = {
  terminal: true,
  params: ['translateN', 'translatePlural'],
  paramWatchers: {
    translateN: function () {
      this.translate()
    },
  },
  isPlural: function () {
    return 'translateN' in this.params && 'translatePlural' in this.params
  },
  bind: function () {
    this.boundTranslate = this.translate.bind(this)
    this.msgid = this.el.innerHTML.trim()
    this.translate()
    languages.eventEmitter.on(languages.languageChangedEventName, this.boundTranslate)
  },
  unbind: function () {
    languages.eventEmitter.removeListener(languages.languageChangedEventName, this.boundTranslate)
  },
  translate: function () {
    let n = this.isPlural() ? parseInt(this.params.translateN) : 1
    let translation = translateUtils.getTranslation(this.msgid, n)
    this.el.innerHTML = this.vm.$interpolate(translation)
  },
}

export default translateDirective
jeremenichelli commented 7 years ago

Just throwing some short words since I'm new at Vue, just to say that I'm happy to see the reduction of the API in general or the under-the-hood helpers. JavaScript is really powerful already, and with computed properties plus other reactive features of the framework almost everything can be achieved.

Kudos for this next release! 🎆

LinusBorg commented 7 years ago

@kemar I'm not that familiar with gettext, but I would simply extend Vue.prototype with a $translate method, and then do

{{ $translate('some.Key.path') }}
fergaldoyle commented 7 years ago

Has the ability to register assets with array syntax been removed from 2.0? Not working on alpha, just wondering if it's intentional or not. i.e:

components: [compA, compB, compC]

I know ES6 has shorthand which looks similar, but there are some scenarios where the array syntax was useful.

roblav96 commented 7 years ago

I see you mention rendering to native interfaces on mobile with weex and I was wondering how easy it would be to make vue and Nativescript talk.

smolinari commented 7 years ago

Something more along the lines of Nativescript for Vue would be either Weex, which you mentioned, or Quasar.

Scott

judocode commented 7 years ago

If there is no longer dispatch or broadcast how will a generic child component inform its parent of an event/change? This doesn't seem to fit the pattern of a global bus or vuex. Use case we use now is a range slider for search filters. The range slider component is generic and is a child of several different search filters. We currently use dispatch when a range slider has finished sliding, then the parent knows to trigger a search based on the change.

yyx990803 commented 7 years ago

@jrenton inline listeners <child @some-event="parentHandler">

marceloadsj commented 7 years ago

Great job guys.

In my point of view, all the changes say that the best approach is to create your component tree based on only a "one way flow", that is so much more simple and easy to debug and maintain.

Without this, your data truthness would be inverse proportional off how far you are from the top most component.

blocka commented 7 years ago

Just want to say that:

render (h) {
    return (
    <div>
      {this.things.map(thing => <Thing thing={thing}></Thing>)}
   </div>
 );

Makes me happy

zephraph commented 7 years ago

Is it expected that more will be added to this list before the release of 2.0? Just curious being as the issue is still open.

chrisvfritz commented 7 years ago

@zephraph Yes, we are continuously updating the list as we make updates to the API. 😃 Nothing huge so far, but occasional breaking changes from previous alphas.

gwildu commented 7 years ago

I have a case, I used event dispatching in the past and where I'm stuck with vuex: The parent component has a list of child components and the child was dispatching an event when it's value changed so the parent was able to do something as a reaction of that change. Now I tried to have an array of the child values in the vuex store. The thing is, how does the child component know in the getter, and in the action, what element of that array it needs to update. As far as I see, vuex does not provide functionality to dynamically get or trigger a mutuation of a value, or am I wrong about that? What would be the best way to handle this case without event dispatching?

fergaldoyle commented 7 years ago

With $broadcast being removed, how would you tell a direct child to do something when a particular thing happens? This would be a scenario where no data has actually changed, so reactive props don't seem to fit.

I could use a prop and pass down a timestamp or some random data and watch that prop in the child but that seems strange. A global event bus would require generation of unique IDs so the the child is only reacting to events from it's parent and not any other instance of the parent component.

There's $emit in a child which a parent can listen to using an inline listener, is there anything for the other way round?

I could pass down an instance of an emitter via a prop, then emmiter.on in the child, does that sound terrible?

simplesmiler commented 7 years ago

@gwildu actions can take arguments, so you can pass item id along with the action. And instead of making the item component fetch the corresponding item from the store, fetch the list in the parent, and pass item data to the item component with a prop.

// Vuex store
state: {
  items: [],
},
mutations: {
  ITEM_REMOVED: function(state, id) {
    var io = state.items.findIndex(item => item.id === id);
    state.items.splice(io, 1);
  },
},
// within the parent component
vuex: {
  getters: {
    items: state => state.items,
  },
  actions: {
    removeItem(store, id) {
      store.dispatch('ITEM_REMOVED', id);
    },
  },
},
<!-- within the parent template -->
<item v-for="item in item"
  :item-data="item.data"
  @removed="removeItem(item.id)"
>
</item>
<!-- within the child template -->
<button @click="$emit('removed')">Remove</button>

If your items do not have a locally unique ids, you can generate one when the item is created or received from the API. Most of the time cuid is good enough for that.

simplesmiler commented 7 years ago

@fergaldoyle due to the parent always knowing it's children, you can put v-ref:some-child on the child to get the reference to the child's vm, and then either $emit on it, or just call a method directly with this.$refs.someChild.<methodName>(...).

However I would advise rethinking the architecture in that case, because events flowing down make the component really hard to reason about.

dubcanada commented 7 years ago

I was playing around with vuejs 2 and I noticed for Snabbdom if you pass

h('div', {style: {color: '#000'}}, [
  h('h1', 'Headline'),
  h('p', 'A paragraph'),
]);

To the render function you get

<div style="color:#000;"><h1>Headline</h1><p>A paragraph</p></div>

But in vuejs you get

<div style="color:#000;"><h1></h1><p></p></div>

Is there a way to modify the text content (inside <h1>)?

blocka commented 7 years ago

@dubcanada why not just pass those as children?

dubcanada commented 7 years ago

Right that would make sense. Thanks

sqal commented 7 years ago

Hi. I have some question about transition system in Vue 2.0 or rather a proposal because I don't see it being in the plans for Vue 2.0. In Vue 1.0 i often encountered the need to detect when some transition/animation i have set up would end. Now I do this by using setTimeout, but this is very hacky and ugly way, we can all agree. So my question is, will be in Vue 2.0 some way to detect the end of CSS transition when we use transition combined with v-show/v-if, possibly via event?

<my-comp v-show="isVisible" @transition-end="onTransitionEnd" transition></my-comp>

i would be very happy to see something like this in next Vue release :) thanks for hearing me out

simplesmiler commented 7 years ago

@sqal you can do that with transition hooks: https://jsfiddle.net/simplesmiler/Lrk9sxjf/97/

yyx990803 commented 7 years ago

@dubcanada it will be supported in the next release (omitting data when creating element)

gwildu commented 7 years ago

Thanks @fergaldoyle and @simplesmiler for your hint to emit.

I was not aware, the parent is able to listen to events that were emitted by the child. Of course it makes more sense to listen to that non-bubbling event then.

remcohuijser commented 7 years ago

Hi all. A bit of background: we are working with webgl and I would like to do some interfaces on a 3D surface. This means that we need to render an interface to for example a canvas and then convert the content of the canvas to a texture.

I have been working with Angular, React and Vue and to me Vue just makes the most sense! While reading about React I came across the react-canvas project. The interesting thing is that instead of transforming the virtual DOM into real DOM nodes, they draw it to a canvas.

Because Vue 2.0 is also using a virtual DOM I was wondering if something like this can be done as well?

Towerful commented 7 years ago

Hello,

Just some clarification of the removing of .sync and what a generic workflow for handling props on a generic component might look like.

so, going from <component :value.sync="some.value"></component> to <component :value="some.value" @update="updateSomeValue"></component>

What is the recommended way of tracking the prop value? In the most basic case, it seems to be

props: ['value'],
computed: {
    _value: {
        get(){
            return this.value;
        },
        set(newVal) {
            this.$emit('update', newVal);
            return newVal;
        }
    }
}

But, surely this relies on the parent component returning that value to the prop, so when the component gets it again, it reflects the most recent change...

Does that mean we now need to do something like this:

props: ['value'],
data() {
    return {
        _val: this.value
    }
},
watch: {
    value(newVal) {
        this._val = newVal;
    }
},
computed: {
    _value: {
        get(){
            return this._val;
        },
        set(newVal) {
            this._val = newVal
            this.$emit('update', newVal);
        }
    }
}

This seems like a lot of boilerplate to handle the passing in (and changing) of a value, notifying the parent that the value has changed, and tracking the change internally, in case the change isn't propagated back by the parent.

Or am I missing a bit of vue magic reactivity here?

Also, there is a chance that if there are a lot of props to handle, this could get quite complicated. I could almost see myself working out a wrapper-component, where children access this.$parent.value in order to mutate directly, and the wrapper-component just handling the props/computed/watches

simplesmiler commented 7 years ago

@Towerful what exactly do you mean by "tracking the value"? And why do you want setter style (this._value = newValue) instead of explicit this.$emit('value-updated', newValue)?

The power of one-way flow is that the parent can decide to not apply the change requested by the child, or can mark the child as "on hold" and apply the change later (e.g. after checking back with the server).

Towerful commented 7 years ago

@simplesmiler using a computed property allows you to bind it in the template, no? so you can use v-model. And having the setter & getter contained in 1 place makes it easy to go and see the functionality when the value gets updated, as opposed to having different ways to access the value and mutate the value within the component, and scattered throughout the code. If using the explicit way within a model, and not using setters, it seems like the methods object is going to be cluttered up with updateValue type methods for the template, as opposed to actual methods.

I guess it applies where the user selects an option in a component, and the component relies on that value to show what is selected.
You are relying on the parent component passing that back into the component for it to be able to do that.
Unless, when the user selects an option, you trigger the component display update manually. Which seems to be moving away from Vue's reactivity.
So having an internal value track what it 'should be', have the template react to that. Use setters/getters to wrap the property to track internal changes & raise external events, and a watch on the property to update the internal value when it is changed externally.

Perhaps I am just struggling to get my head around the new way of doing it.

smolinari commented 7 years ago

@Towerful - You aren't the only one....

Scott

LinusBorg commented 7 years ago

@Towerful:

To me it seems that what you describe are essentally components that act like inputs with a v-model: the user changes some value in the UI, and you want that change to be reflected in the bound data immediatly.

For these types of components, you can use v-model on comonents in 2.0:

<my-input v-model="myValue">

// in my-input.vue
<input :value="value" @change="$emit('input', $event.target.value)">

export default {
  props: ['value']  //special prop received from v-model
}

This makes the interface to real <input> elements and to custom input components essentially identical, and a two-way binding.


For more complex components that receive multiple props (and are not simple custom inputs, but more abstract), we discourage using .sync because it becomes hard to reason about in most situations.

The parent should decide what to do with a value it receives from the child, it'S data should not be implicitly changed like .sync does.

Can you provide an example that is not solvabel with the v-model approach above and still beneftis from using .sync? That may be a better foundation for discussion than abstract theory.

Towerful commented 7 years ago

Oh, how did I miss that?! Its definitely there in the OP, and there is even a discussion about this some comments ago! Now I feel a bit stupid.
Could the original post be updated to make it a little more clear that v-model can be used on a component?
@LinusBorg Off the top of my head, I cannot think of a case where v-model on a component would not work. I missed that part in the original post. Even for complicated object components, it would just be a matter of nesting components. And this re-enforces single responsibility components. It makes a lot more sense :)

simplesmiler commented 7 years ago

@Towerful

Re: using v-model. The thing is, v-model is synchronous (in a way), while the cross-component data flow is inherently asynchronous because of the watcher queue (demo). I've seen this confuse a lot of people. One-way flow just makes it more explicit that props are not synchronous and forces you to not rely on them being synchronous (this is what you are trying to trick your way around).

Re: cluttered methods. For simple cases you can always do @value-updated="value = $arguments[0]". For complicated cases it's a good thing to have a method, where you can adjust the state to keep it consistent (e.g. trigger updates manually). Segway to the next point.

Re: moving away from reactivity. I don't agree with this statement. For simple cases you don't need magic to make the child pick up the value, updated by the value-updated="value = $arguments[0]".

For complicated cases, with .sync props you would have to use watch, but explicit watch is not really a part of reactivity. It's an escape hatch, where you trigger your manual updates that can not be expressed as computed. And it's not a good one, because it can not react to changes synchronously, like computed can. This is why when using watch heavily, you may find your data updates taking a few "ticks" to propagate. If you ever stumbled upon directly nested nextTick, you know what I'm talking about.

Now, -updated handler provides a better escape hatch, letting the complicated model changes be applied synchronously (or simultaneously asynchronously) after child expresses the intent, making sure that child will receive updated values in the next tick (or will not receive inconsistent state).

kharysharpe commented 7 years ago

@yyx990803 Could we implement a way to listen for $emits, similar to how we had events for $dispatch and $broadcast in vuejs1?

Feels more vuejs-esque, something along the lines of this (an 'on' or 'listen'):

Vue.component('cart', {
  template: "#cart-template",
  data () {
    return {quantity : 0 }
  },
  watch: {
    'quantity': function (quantity, oldQuantity) {
      console.log('quantity changed from %s to %s', oldQuantity, quantity)

      bus.$emit('cart.quantity-changed', quantity)
    }
  }
});

new Vue({
  el: '.container',
  data : function () {
    return {
      quantity: 0
    };
  },
  on: {
    'cart.quantity-changed': function (newQuantity) {
      console.log('quantity change emitted');

      Vue.set(self, 'quantity', newQuantity);
    }
  },
  computed:{
    gold: function(){
      return this.quantity * 100
    }
  }
})

This basically would automatically attach itself to the global bus.

LinusBorg commented 7 years ago

Event Busses are not a pattern that we want to encourage - it is only useful some edge cases. Generally, a store pattern, like vuex, is preferred.

Implementing an API that makes using a bus easier and feels "officially supported" would be the wrong signal.

Looking at your example, if you stored the quantity in a store accessed by both components, no events would be nessessary. The computed property in the container component would update automatically.

Simple example code without using a real store solution like vuex:

var store = {
  cart: {
    quantity: 0
  }
}
Vue.component('cart', {
  template: "#cart-template",
  data () {
    return store.cart
  },
});

new Vue({
  el: '.container',
  data : function () {
    return store.cart;
  },
  computed:{
    gold: function(){
      return this.quantity * 100
    }
  }
})
blocka commented 7 years ago

I would say the general idea of vue2 is to make it harder to shoot yourself in the foot.

On Sun, Jul 3, 2016 at 11:24 AM, Thorsten Lünborg notifications@github.com wrote:

Event Busses are not a pattern that we want to encourage - it is only useful some edge cases. Generally, a store pattern, like vuex, is preferred.

Implementing an API that makes using a bus easier and feels "officially supported" would be the wrong signal.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/vuejs/vue/issues/2873#issuecomment-230158828, or mute the thread https://github.com/notifications/unsubscribe/AACoukCpCgYlDbVej_w_h4NEhQ-imYHBks5qR9QwgaJpZM4IedHC .

simplesmiler commented 7 years ago

@kharysharpe $emits are intended to be listened with v-on on the child instance. This also has an added benefit of being able to tap into the original context of where the instance is used:

<list-item v-for="(item, index) in items"
  :title="item.title"
  @remove="items.splice(index, 1)"
>
</list-item>
iamajoe commented 7 years ago

Is there a date for the 2.0 release? I'm pretty excited with the changes. Congrats! I'm thinking on using Vue 2.0 + Redux.

chrisvfritz commented 7 years ago

@Sendoushi No date yet on the final release, but beta may be within a week. 😄 Vuex 2.0 is also being developed alongside and it will not only feature a much simpler API than current vuex, but also integrates into Vue ecosystem much more nicely than redux.

taoeffect commented 7 years ago

Vuex 2.0 is also being developed alongside and it will not only feature a much simpler API than current vuex, but also integrates into Vue ecosystem much more nicely than redux.

@chrisvfritz That's fantastic to hear! I always felt the current API is a bit overly and unnecessarily complicated. Ended up having to do things like this to compensate:

const mutations = {
  LOGIN (state) { state.loggedIn = true },
  LOGOUT (state) { state.loggedIn = false }
}

export const types = Object.keys(mutations)

// For now we dynamically generate all the actions like this.
// It's rare when anything more complicated is needed, but there
// is an example here:
// http://vuex.vuejs.org/en/actions.html
export const actions = types.reduce((o, el) => {
  var action = S(el.toLowerCase()).camelize().s
  o[action] = ({dispatch}, ...args) => dispatch(el, ...args)
  return o
}, {})
gwildu commented 7 years ago

What about the roadmap of vue 2 and vuex 2. Is it planned to release them together or one before the other and what about the compatibilities of different versions?

Uninen commented 7 years ago

Relating to question above, what is the status with vue-router -- is it going to get Vue 2 support soon or will Vue 2 testing need to be done without the router?

chrisvfritz commented 7 years ago

@gwildu They'll likely be released somewhat together and Vuex 2.0 will only support Vue 2.0. Pre 2.0 Vuex will still receive support until Vue 1.x is no longer supported.

@Uninen Vue Router will be receiving some love next, before the release of Vue 2.0.

Uninen commented 7 years ago

Thanks for the nfo @chrisvfritz :)

yyx990803 commented 7 years ago

@chrisvfritz @Uninen correction: Vuex 2.0 also works for Vue 1.x.

Next major version of vue-router will only support Vue 2.x.

sebastiandedeyne commented 7 years ago

Runtime only build: since it doesn't include the compiler, you need to either pre-compiled templates in a compile step, or manually written render functions.

Is there / will there be a way to precompile templates without using vueify/vue-loader and .vue files? If not, would it be a good idea to have a babel plugin to transform template: properties to render functions in components?

vebdhuz commented 7 years ago

升级2.0后,deprecated的特性还能用不 可以先升级2.0,然后再慢慢把deprecated的特性改掉不

PaulKiddle commented 7 years ago

Will it be possible to create a terminal component, now that elementDirective is gone?

IanSun commented 7 years ago

As mentioned:

v-model no longer cares about initial inline value. It will always treat the Vue instance data as the source of truth.

Consider that

<child-component>
  <input type="checkbox" :id="_uid" v-model="childModel" :value="value" />
  <label :for="_uid"><slot></slot></label>
</child-component>

How can I deal with checkbox with arrays between custom components?

Updated 1: Solved. Transfer prop type="checkbox" to the child component in the parent component.

<parent-component>
  <child-component type="checkbox" v-model="parentModel" value="apple"  />
  <child-component type="checkbox" v-model="parentModel" value="orange" />
  <child-component type="checkbox" v-model="parentModel" value="banana" />
</parent-component>

Then you can get inline value via {props: [ 'value' ]}. Emit a change event to the parent component to tell the value has changed.

<child-component>
  <input type="checkbox" :id="_uid" v-model="childModel" :value="value"
    @change="$emit('change', $event)"
  />
  <label :for="_uid"><slot></slot></label>
</child-component>

This is because the compiler compiles the v-model directive according to its type. And the compiler will generate the checked prop and bind a change event to it.

Updated 2: However, the updated life cycle hook doesn't trigger due to v-model directly changes the checked attribute (That means you can't get a change event of a native html checkbox component by modifying the value of v-model). So, @yyx990803, can you trigger a change event after v-model changes?

johnleider commented 7 years ago

@YunSun-CN The only way that I was able to get around your issue was to add a property specific for the value, ala val, and use that to set the actual value, and then just emit changes to the v-model 'input' event.

IanSun commented 7 years ago

@johnleider I wrote a custom directive to simulate what v-model does. By the way, you should generate models in a strict way not only checking type prop but checking element's tagName. Otherwise, another custom component with type prop may overwrite its default model behaviour.