Vue.jsの勉強がてら作ってみた成果物

荒削りｗｗｗｗ
ま、でも機能として動作するレベルまで作れたのでよかったｗ

```haml
.editTopicSummary
  .inputName#js-inputName
    .form-group.text
      %textarea.inputName__field{placeholder: '記事のタイトル（34文字以内）', v:{'model.trim': 'name', 'bind:class': 'errorClass'}, id: 'topic_name'} 編集時の入力済みテキスト
    .inputName__textCount
      {{name.length}}/{{maxLength}}文字
  .uploadImage#js-uploadImage
    .uploadImage__display{v:{'on:click': 'clickFileButton'}}
      %input#js-imagePath{type: 'hidden', value: defaultImage}
      %img{v:{'bind:src': 'imagePath', 'show': 'imagePath'}}
      %span 看板画像を選ぶ
    .uploadImage__submit
      .form-group.file
        %input{id: 'topic_image', type: 'file', v:{'on:change': 'onFileChange'}}
  .inputDescription#js-inputDescription
    .form-group.text
      %textarea.inputDescription__field{placeholder: '記事の概要（200文字以内）', v:{'model.trim': 'description', 'bind:class': 'errorClass'}, id: 'topic_description'} 編集時の入力済みテキスト
    .inputDescription__textCount
      {{description.length}}/{{maxLength}}文字
```
```scss
.editTopicSummary{
  width: 720px;
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  color: #333;
}
.textareaDefaultSetting{
  width: 100%;
  max-width: 100%;
  min-width: 100%;
  box-sizing: border-box;
  border: 1px solid #DDD;
  border-radius: 6px;
  padding: 10px;
  margin-bottom: 5px;
  outline: none;
  &.error{
    background-color: #F9BABA;
  }
}
.textCount{
  font-size: 12px;
  text-align: right;
}
.inputName{
  width: 100%;
  margin-bottom: 15px;
  &__field{
    min-height: 50px;
    font-size: 20px;
    @extend .textareaDefaultSetting;
  }
  &__textCount{
    @extend .textCount;
  }
}
.uploadImage{
  width: 150px;
  &__display{
    width: 100%;
    height: 150px;
    background-color: #EEE;
    position: relative;
    cursor: pointer;
    img{
      display: block;
      width: 100%;
      height: 100%;
      object-fit: cover;
      position: absolute;
      top: 0;
    }
    span{
      display: block;
      width: 100%;
      font-size: 14px;
      color: #FFF;
      text-align: center;
      background-color: rgba(0, 0, 0, 0.4);
      padding: 10px 0;
      position: absolute;
      bottom: 0;
    }
  }
  &__submit{
    display: none;
  }
}
.inputDescription{
  width: 555px;
  &__field{
    height: 150px;
    min-height: 150px;
    @extend .textareaDefaultSetting;
  }
  &__textCount{
    @extend .textCount;
  }
}
```
```javascript
var inputTitle = new Vue({
  el: '#js-inputName',
  data: {
    errorClass: '',
    maxLength: 34,
    name: document.getElementById('topic_name').value
  },
  watch: {
    name(val){
      this.errorClass = (val.length > this.maxLength) ? 'error' : '';
    }
  }
});
var inputDescription = new Vue({
  el: '#js-inputDescription',
  data: {
    errorClass: '',
    maxLength: 200,
    description: document.getElementById('topic_description').value
  },
  watch: {
    description(val){
      this.errorClass = (val.length > this.maxLength) ? 'error' : '';
    }
  }
});
var uploadImage = new Vue({
  el: '#js-uploadImage',
  data: {
    imagePath: document.getElementById('js-imagePath').value,
  },
  methods: {
    clickFileButton(){
      document.getElementById('topic_image').click();
    },
    onFileChange(e){
      var files = e.target.files;
      this.createImage(files[0]);
    },
    createImage(file){
      var reader = new FileReader();
      reader.onload = (e) => {
        this.imagePath = e.target.result;
      };
      reader.readAsDataURL(file);
    }
  }
});
```