Vue Sync Mixin

Create two-way bindings as easily as props.

HTML

<div id="vue">
  <user :firstname.sync="user.firstname" :lastname.sync="user.lastname"></user>
  <user v-bind.sync="user"></user>
  <wrapper :user.sync="user"></wrapper>
  {{ user }}<br>
  <toggler :state.sync="state"></toggler>{{ state }}
</div>

JavaScript

Vue.mixin({
	beforeCreate(){
  	const sync = this.$options.sync
  	if(sync){
    	if(!this.$options.computed){
      	this.$options.computed = {}
      }
      const attrs = Object.keys(this.$attrs)
      sync.forEach(key => {
      	if(!attrs.includes(key)){
        	Vue.util.warn(`Missing required sync-prop: "${key}"`, this)
        }
        this.$options.computed[key] = {
        	get(){
          	return this.$attrs[key]
          },
          set(val){
          	this.$emit('update:' + key, val)
          }
        }
      })
    }
  }
})
Vue.component('user',{
  sync:['firstname','lastname'], //this is the special option added by the mixin
  template:`
  <div>
    <input v-model="firstname">
    <input v-model="lastname">
  </div>`
})
Vue.component('wrapper',{
  sync:['user'],
  template:`<user v-bind.sync="user"></user>`
})
Vue.component('toggler',{
	sync:['state'],
  template:`<button @click="state = !state">{{state ? 'X' : 'O'}}</button>`
})
new Vue({
	el:'#vue',
  data:{
  	user:{
      firstname:'Simon',
      lastname:'Herteby'
    },
    state:true
  }
})