【Nuxt.js】form実践編:contenteditableでイライラ解消!


前置き

formで使うinput, textarea
中でも何かと使い勝手の悪いtextareaさん😕
HTMLのグローバル属性
contenteditableを使って
textareaをもっと見やすくしてみましょう!

textarea

contenteditable

contenteditableって?

簡単にいうと編集モードにしてくれます。
分かりやすくbuttonタグにつけました。
編集できる+文字数に応じて幅が変化してくれます!

index.vue
<template>
 <button
   contenteditable="true"
 >
   編集できるよ
 </button>
</template>

使いやすさ比較

・textareaの場合
・div contenteditable="true"の場合

textareaにcontenteditable="true"は
使えないため擬似的にtextareaを作成🌟

◾️textarea
・基本的に高さが固定されるので全体が見えない
 リサイズボタンで拡大縮小できるけど
・横幅も動いて見にくい
・リサイズボタンがデザインできない
 resize: none;で消してしまうと拡大縮小できない
・色々使い勝手が悪い

◾️div contenteditable="true"
・横幅だけ固定してしまえば
・縦幅が文字数に応じて伸縮し
 とっても見やすい!!✨👀

コード

◾️div contenteditable="true"の場合
textareaをdiv contenteditable="true"に変更!
今回は複数行になるためrole="textbox"も追加💡

cssはtextareaとほとんど変わりません。
ただし当然ですがinput, textareaの
placeholder属性は使えません😣

Contenteditable.vue
<template>
 <label
  class="contenteditable"
 >
  <span class="label">
    {{ label }}
  </span>
  <div
    class="contenteditable"
    contenteditable="true"
    role="textbox"
    @input="$emit('input', $event.target.textContent)"
  />
 </label>
</template>

<script>
export default {
props: {
  label: {
    type: String,
    default: 'label',
  },
}
</script>

<style lang="scss" scoped>
.contenteditable {
  display: flex;
  align-items: flex-start;

  > .label {
    color: red;
    font-weight: bold;
    width: 64px;
    min-width: 64px;
    padding-top: 4px;
  }

  > .textarea {
    width: calc(100% - 64px);
    min-height: 70px;
    padding: 8px 12px;
    border: 2px solid red;
  }
}
</style>
```vue

```vue:index.vue
<template>
 <div class="page">
   <Contenteditable
     label="LABEL"
     @input="text = $event"
   />
 </div>
</template>

<script>
import Contenteditable from '~/components/Contenteditable.vue'

export default {
 components: {
   Contenteditable,
 },
 data () {
  return {
   text: "",
  }
 },
}
</script>

◾️textareaの場合

chromeだとフォントサイズが
小さく見えることがあります。
なのでtextareaの場合のみ
font-size: 100%; を追記します✍️

デフォルトのフォントサイズ16pxを指定すると
font-familyも変わる場合があるようです。

font-size: 100%;

または

font-size: 16px;
font-family: 'フォント名'

Textarea.vue
<template>
 <label
  class="textarea"
 >
  <span class="label">
    {{ label }}
  </span>
  <textarea
    :placeholder="placeholder"
    class="textarea"
    @input="$emit('input', $event.target.textContent)"
  />
 </label>
</template>

<script>
export default {
props: {
  label: {
    type: String,
    default: 'label',
  },
  placeholder: String,
}
</script>

<style lang="scss" scoped>
.textarea {
  display: flex;
  align-items: flex-start;

  > .label {
    color: red;
    font-weight: bold;
    width: 64px;
    min-width: 64px;
    padding-top: 4px;
  }

  > .textarea {
    font-size: 100%;
    width: calc(100% - 64px);
    min-height: 70px;
    padding: 8px 12px;
    border: 2px solid red;
  }
}
</style>
index.vue
<template>
 <div class="page">
   <Textarea
     label="LABEL"
     placeholder="ここに入力してください"
     @input="text = $event"
   />
 </div>
</template>

<script>
import Textarea from '~/components/Textarea.vue'

export default {
 components: {
   Textarea,
 },
 data () {
  return {
   text: "",
  }
 },
}
</script>

記事が公開したときにわかる様に、
note・Twitterフォローをお願いします😀

https://twitter.com/aLizlab