Vue BindRoute Mixin
Use v-model on route query params as easily as on data properties
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-router/3.0.1/vue-router.min.js"></script>
<div id="vue">
<input v-model="search" placeholder="search">
<div>
<input type="checkbox" v-model="caseSensitive" id="caseSensitive">
<label for="caseSensitive">Case sensitive</label>
</div>
<div>
<label for="maxPrice">Max price:</label>
<input type="range" v-model="maxPrice" min="0" max="40">{{maxPrice}}
<button v-if="maxPrice !== null" @click="maxPrice = null">No max price</button>
</div>
<h3>Route path:</h3>
{{$route.fullPath}}
<button @click="add()">
CLick
</button>
<h3>Items matching query:</h3>
<ul v-if="results.length">
<li v-for="item in results"><b>{{item.name}}</b> {{item.price}}:-</li>
</ul>
<div v-else>No matches</div>
<h3>$route:</h3>
<pre>{{$route}}</pre>
</div>
JavaScript
//This is a mixin factory! It lets us pass arguments to the mixin.
function bindRoute(params) {
const mixin = {
computed: {}
}
for (let key in params) {
let def = params[key]
mixin.computed[key] = {
get() {
if (this.$route.query.hasOwnProperty(key)) {
return this.$route.query[key]
} else {
return def
}
},
set(val) {
if (val === def) { //if value is same as the default, remove it from the query to keep the URL neat
const query = { ...this.$route.query}
delete query[key]
this.$router.replace({query})
} else {
this.$router.replace({query: {...this.$route.query, ...{[key]: val}}})
}
}
}
}
return mixin
}
//Setup up VueRouter and the Vue app
const router = new VueRouter()
Vue.use(VueRouter)
new Vue({
el: '#vue',
router,
mixins: [ //Here's how you use the mixin
bindRoute({
search: '', //these values are the default values
caseSensitive: false,
maxPrice:null
})
],
data() {
return {
items: [
{name:'Cupcake', price:35},
{name:'Biscuit', price:15},
{name:'Cinnabun', price:25},
{name:'Coffee', price:29},
{name:'Tea', price:29},
{name:'Frappuccino', price:39}
]
}
},
computed: {
results() {
const matcher = new RegExp(this.search, this.caseSensitive ? '' : 'i')
let items = this.items.filter(item => matcher.test(item.name))
if(this.maxPrice !== null){
items = items.filter(item => item.price <= this.maxPrice)
}
return items
}
},
methods:{
add(){
this.items.push(Name)
}
}
})