タグ入力欄だけVue化

This commit is contained in:
shibafu
2019-06-01 00:40:35 +09:00
parent 7a95e0979e
commit 0670cb8736
8 changed files with 113 additions and 72 deletions

View File

@@ -1,59 +1,9 @@
function updateTags() {
$('input[name=tags]').val(
$('#tags')
.find('li')
.map(function () {
return $(this).data('value');
})
.get()
.join(' ')
);
}
import Vue from 'vue';
import TagInput from "./components/TagInput.vue";
function insertTag(value: string) {
$('<li class="list-inline-item badge badge-primary" style="cursor: pointer;"><span class="oi oi-tag"></span> <span></span> | x</li>')
.data('value', value)
.children(':last-child')
.text(value)
.end()
.appendTo('#tags');
}
const initTags = $('input[name=tags]').val() as string;
if (initTags.trim() !== '') {
initTags.split(' ').forEach(function (value) {
insertTag(value);
});
}
$('#tagInput').on('keydown', function (ev: JQuery.KeyDownEvent) {
const $this = $(this);
let value = $this.val() as string;
if (value.trim() !== '') {
switch (ev.key) {
case 'Tab':
case 'Enter':
case ' ':
if ((ev.originalEvent as any).isComposing !== true) {
insertTag(value.trim());
$this.val('');
updateTags();
}
ev.preventDefault();
break;
}
} else if (ev.key === 'Enter') {
// 誤爆防止
ev.preventDefault();
new Vue({
el: '#app',
components: {
TagInput
}
});
$('#tags')
.on('click', 'li', function (ev) {
$(this).remove();
updateTags();
})
.parent()
.on('click', function (ev) {
$('#tagInput').focus();
});

View File

@@ -0,0 +1,77 @@
<template>
<div class="form-control h-auto" @click="$refs.input.focus()">
<ul class="list-inline d-inline">
<li v-for="(tag, i) in tags"
class="list-inline-item badge badge-primary"
style="cursor: pointer;"
@click="removeTag(i)"><span class="oi oi-tag"></span> {{ tag }} | x</li>
</ul>
<input :id="id"
ref="input"
type="text"
style="border: 0; outline: 0;"
v-model="buffer"
@keydown="onKeyDown">
</div>
</template>
<script lang="ts">
import {Vue, Component, Prop} from "vue-property-decorator";
function getElementByName(elementName: string): HTMLElement | null {
const elements = document.getElementsByName(elementName);
if (elements.length) {
return elements[0];
}
return null;
}
@Component
export default class TagInput extends Vue {
@Prop(String) readonly id!: string;
@Prop(String) readonly input!: string;
@Prop(Boolean) readonly isInvalid!: boolean;
tags: string[] = [];
buffer: string = "";
mounted() {
const tags = getElementByName(this.input);
if (tags instanceof HTMLInputElement && tags.value.trim() !== "") {
this.tags = tags.value.split(" ")
}
}
onKeyDown(event: KeyboardEvent) {
if (this.buffer.trim() !== "") {
switch (event.key) {
case 'Tab':
case 'Enter':
case ' ':
if ((event as any).isComposing !== true) {
this.tags.push(this.buffer);
this.buffer = "";
this.sync();
}
event.preventDefault();
break;
}
} else if (event.key === "Enter") {
// 誤爆防止
event.preventDefault();
}
}
removeTag(index: number) {
this.tags.splice(index, 1);
this.sync();
}
sync() {
const tags = getElementByName(this.input);
if (tags instanceof HTMLInputElement) {
tags.value = this.tags.join(" ");
}
}
}
</script>

4
resources/assets/js/vue-shims.d.ts vendored Normal file
View File

@@ -0,0 +1,4 @@
declare module "*.vue" {
import Vue from "vue";
export default Vue;
}