VueJS Focusable Directive
Note: Feel free to not use a Polyfill for classList ;)
by Serhii Matrunchyk
HTML
<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/classlist/1.1.20150312/classList.min.js"></script>
<div id="app">
<input type="text" v-model="input" @blur="blur" id="input">
<input type="text" id="secondInput">
<ul>
<li v-for="contact in contacts" :id="`li_${contact.id}`" v-focusable @blur="blur">
{{ contact.name }}
</li>
</ul>
<div v-model="log" class="log">
<div v-for="l in log" v-text="l"></div>
</div>
</div>
CSS
.log {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: auto;
background: #fff;
color: #f00;
}
Babel + JSX
Vue.directive('focusable', {
inserted(el) {
el.addEventListener("keydown", (e) => {
e.preventDefault();
e.stopPropagation();
});
el.contentEditable = true;
el.classList.add("v-focusable");
// Setting styles
// TODO: Find more elegant Vue-way
if (!document.getElementById("vue-focusable-directive")) {
const style = `
<style id="vue-focusable-directive">
.v-focusable, .v-focusable:focus, .v-focusable:active {
border: none !important;
outline: none !important;
cursor: default !important;
color: transparent !important;
text-shadow: 0 0 0 #000 !important;
}
</style>`;
document.querySelector('body').insertAdjacentHTML('beforeend', style);
}
},
});
var vm = new Vue({
el: '#app',
data() {
return {
input: "",
log: ['Log started'],
contacts: [
{ id: 1, name: "John" },
{ id: 2, name: "Jane" },
{ id: 3, name: "Karl" },
{ id: 4, name: "Hank" },
],
};
},
methods: {
addToLog(str) {
this.log.push(str);
},
blur(e) {
if (e.relatedTarget) {
this.addToLog(`Blurred: ${e.target.id}; Focused: ${e.relatedTarget.id}`);
}
},
},
});