Home

Awesome

Vue sync-query mixin

vue-sync-query-mixin@1.x see branch v1

npm version npm download

Effortlessly keep local state and $route.query in sync for Vue 1.x | Vue 2.x
Intellectual property of Oneway.mobi

Requirement

Installation

npm i vue-sync-query-mixin -S

alternatively:<script src="dist/vue-sync-query-mixin.min.js"></script>
which exposes VueSyncQuery as a global variable

Example

Vue 1.x online example is here (source code is ./example-vue1.html)
Vue 2.x online example is here (source code is ./example-vue2.html)

Usage

// This is a Vue component
import syncQuery from 'vue-sync-query-mixin'

export default {
  mixins: [syncQuery],
  data: () => ({ limit: 10 }),
  ready () {
    // `limit` will keep in sync with `$route.query.limit`
    this.syncQuery('limit')
  }
  // Vue 1.x can use beforeCompile/compiled/ready
  // Vue 2.x can use created/beforeMount/mounted
}

syncQuery accepts 4 types of argument:

this.syncQuery('limit')
this.syncQuery(['limit'])
this.syncQuery({
  localField: 'limit',
  queryField: 'limit',
  local2query: {
    formatter: v => v,
    immediate: false,
    deep: false
  },
  query2local: {
    formatter: v => v,
    immediate: true,
    deep: false
  }
})
this.syncQuery([
  {
    localField: 'limit',
    queryField: 'limit',
    local2query: {
      formatter: v => v,
      immediate: false,
      deep: false
    },
    query2local: {
      formatter: v => v,
      immediate: true,
      deep: false
    }
  }
])

Magic

More detail in source code
Vue.js official vm.$watch( expOrFn, callback, [options] ) API documentation is here

_syncQuery ({ localField, queryField, local2query, query2local }) {
  (() => {
    // backup the default value
    const defaultVal = this[localField]
    
    // local ==(sync)==> query
    this.$watch(localField, function (v, oldV) {
      this.updateQuery({ [queryField]: local2query.formatter(v, oldV) })
    }, local2query)

    // local <==(sync)== query
    this.$watch(`$route.query.${queryField}`, function (v, oldV) {
      this[localField] = query2local.formatter(v, oldV) || defaultVal
    }, query2local)
  })()
}

Notice

/**
 * default descriptor generator for $watch
 * @param  {String} field
 * @return {Object}
 */
function defaultDescGen(field) {
  return {
    localField: field,
    queryField: field,
    local2query: {
      formatter: v => v,
      immediate: false,
      deep: false
    },
    query2local: {
      formatter: v => v,
      immediate: true,
      deep: false // P.S. watching deep of a string makes no sense
    }
  }
}

But they can be function type, and then we regard them as the formatter
What's more, all the options are merge not override, for example:

syncQuery({
  localField: 'limit',
  queryField: 'limit',
  local2query: { immediate: true },
  query2local: v => +v // string to number
})

// ↑ is same as ↓

syncQuery({
  localField: field,
  queryField: field,
  local2query: {
    formatter: v => v,
    immediate: true, // merge!
    deep: false
  },
  query2local: {
    formatter: v => +v, // merge!
    immediate: true,
    deep: false
  }
})

Build

npm run build