はじめに
基本的には以前書いた記事を Vue3
化したものですが、以下の2点手を入れています。
-
placeholder
に対応 - 更新時に余計な空白を削除
TL;DR;
出来上がりのコードはこちら。
<template lang="pug">
.text-input(
ref = "input"
:contenteditable = "true"
@input = "update"
@focus = "focus"
@blur = "blur"
)
</template>
<script lang="ts">
import { defineComponent, onMounted, ref, watch } from "@vue/runtime-core";
export default defineComponent({
name: "MultilineInput",
props: {
modelValue: String,
},
emits: {
"update:modelValue": null,
},
setup(props, ctx) {
const input = ref<HTMLElement>();
const focusIn = ref<boolean>();
const updateValue = () => {
if (!focusIn.value) {
let t = "";
if (props.modelValue) {
const elem: string[] = props.modelValue.split("\n");
for (const e of elem) {
t += "<div>" + (e !== "" ? e : "<br>") + "</div>";
}
}
if (input.value) input.value.innerHTML = t;
}
};
watch(() => props.modelValue, updateValue);
const update = (e: Event) => {
const target: HTMLElement = e.target as HTMLElement;
const breakdown = target.innerHTML
.replaceAll("<div><br></div>", "\n")
.replaceAll("<div>", "\n")
.replaceAll("</div>", "")
.replaceAll("<br>", "\n").\
.replaceAll(/<("[^"]*"|'[^']*'|[^'">])*>/g, "");
ctx.emit("update:modelValue", breakdown);
};
const focus = () => {
focusIn.value = true;
};
const blur = () => {
focusIn.value = false;
};
onMounted(() => {
updateValue();
});
return {
input,
update,
focus,
blur,
};
},
});
</script>
<style lang="stylus">
[contenteditable=true]:empty:before
content: attr(placeholder);
pointer-events: none;
display: block; /* For Firefox */
color rgba(255, 255, 255, 0.5)
</style>
改良点
placeholderに対応
こちらの記事で一発対応できました。
以前は無かった style
タグの中に該当するコードを書いています。
更新時に余計な空白を削除
久々に使って悩んだのですが、contenteditable
内で Enter
を入れると、
<div><br></div>
といった要素が挿入されます。(shift + Enter
なら <br>
のみ)
以前の記事では innerText
で取ってきた値をそのまま使用していたのですが、この状態では余分な改行コードが入った string
が取得されます。
ここを、innerHTML
で取得した値から 力業で 正しい値を抜き出すように変更しました。
入り込んだHTMLコードを削除(追記 2021/10/19)
運用中、なぜか <span style="font-size:12pt">やっほー</span>
みたいな文字列が入ってきてしまった事があったので、これも 力業で ねじ伏せます。
.replaceAll(/<("[^"]*"|'[^']*'|[^'">])*>/g, "");
おわりに
正しい値を取得するところでかなり無理やりな事をしており、きれいな実装とは言えませんが、この記事が同じ事でお困りの方の一助になれれば幸いです。