Обновление объекта данных в Vue с помощью JavaScript не вызывает Vue реактивность - PullRequest
1 голос
/ 28 мая 2020

Я использую Vue 2.X с Quill JS в проекте.

Редактор Quill находится в модуле. Однако внутри я использую прослушиватель событий, чтобы размыть сам редактор. У Quill нет размытия, и эти решения не работают.

У меня также есть привязка класса Vue к содержащему его div.

Если я вкладываюсь или щелкаю, а затем выхожу из редактора, появляется красное поле с предупреждающей меткой в ​​соответствии с условие для привязки класса.

Размытие проверяет, ввел ли пользователь пробелы, а затем покинул редактор. Размытие очищает редактор, устанавливает для объекта данных Vue программу. Objective значение пустое, а также устанавливает для объекта данных ,nda.showErrorObjective, значение true. Он работает.

Однако класс не активируется в редакторе, даже если для его триггеров установлено значение true.

Я загрузил это в Code Pen здесь: https://codepen.io/ziggythecompace/pen/jOboRQE

Спасибо, Донна

Код также ниже.

Vue.component('editor', {
  template: '<div ref="editor"></div>',
  props: {
    value: {
      type: String,
      default: ''
    },
    placeholder: {
      type: String,
      default: "Please type here."
    }
  },
  data: function data() {
    return {
      editor: null
    };
  },
  mounted: function mounted() {
    var _this = this;
    this.editor = new Quill(this.$refs.editor, {
      modules: {
        keyboard: {
          bindings: {
            'tab': {
              key: 9,
              handler: function(range, context) {
                return true;
              }
            }
          }
        },
        toolbar: [
          ['bold', 'italic', 'underline', {
            'color': []
          }, {
            'background': []
          }, {
            'list': 'bullet'
          }, 'link', 'clean']
        ]
      },
      theme: 'snow',
      formats: ['bold', 'underline', 'italic', 'color', 'background', 'list', 'link', 'clean']
    });
    this.editor.root.innerHTML = this.value;
    this.editor.root.dataset.placeholder = this.placeholder;

    this.editor.on('text-change', function() {
      return _this.update();
    });

    // Prevent the event listeners from bubbling up.
    if (document.querySelector(".ql-toolbar")) {
      document.querySelector('.ql-toolbar').addEventListener('mousedown', function(e) {
        return e.preventDefault();
      });
    }

    //The below checks to see if the editors are loaded in the DOM.
    if (document.querySelector(".ql-editor")) {
      document.querySelector(".ql-editor").addEventListener('blur', function() {
        var lcEditor = document.querySelector(".ql-editor");
        var lcInput = lcEditor.innerHTML.replace(/<(.|\n)*?>/g, '').trim();
        if (lcInput.length === 0) {
          lcEditor.innerHTML = '';
          app.$data.agenda.objective = '';
          app.$data.showErrorObjective = true;
        } else {
          app.$data.showErrorObjective = false;
        }
        console.log("showErrorObjective: " + app.$data.showErrorObjective);
      });
    }
  },
  methods: {
    update: function update() {
      const limit = 1000;
      //console.log(this.editor.getText().length);
      if (this.editor.getLength() > limit) {
        this.editor.deleteText(limit, this.editor.getLength());
      }
      this.$emit('input', this.editor.getText() ? this.editor.root.innerHTML : '');
    }
  }
});

var app = new Vue({
  el: '#vueApp',
  data: {
    agenda: {
      objective: ""
    },
    showMeetingObjective: true,
    editMeetingObjective: false,
    showErrorObjective: false,
    showValidationErrors: false
  },
  methods: {
    checkTextArea: function(id) {
      if (id === "objectives") {
        if (this.agenda.objective.replace(/<(.|\n)*?>/g, '').trim().length === 0) {
          this.agenda.objective = "";
        }
      }
    }
  }
});
.form-group {
  margin-bottom: 0.25rem;
}

.agenda-label {
  color: #323130;
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  font-size: 14px;
  font-weight: 600;
  line-height: 17px;
  text-align: left;
}

.agendaAreaEdit {
  background-color: #FFFFFF;
  border: 1px solid #979797;
  border-radius: 2px;
  padding: 8px 8px 8px 8px;
}

.agendaAreaSmall {
  color: #605E5C !important;
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif !important;
  font-size: 12px !important;
  font-weight: 300 !important;
  line-height: 14px !important;
  text-align: left !important;
  overflow: hidden !important;
  /*height:28px;*/
  max-height: 28px !important;
  padding: 0px !important;
  width: 100% !important;
  border: none !important;
}

.agendaAreaEditor.error {
  border: 1px solid #CD0A0A !important;
}

.fa-pencil {
  font-size: 0.9em;
  color: #0078D4;
}

.fieldWarningLabel {
  background-color: #FDE7E9;
  border-radius: 2px;
  height: 16px;
  padding: 0px 8px;
  margin-bottom: 0px !important;
  float: right;
  color: #D13438;
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  font-size: 11px;
  font-weight: 400;
  line-height: 14.63px;
}
<link href="https://cdn.quilljs.com/1.3.4/quill.snow.css" rel="stylesheet">

<link rel="stylesheet" type="text/css" href="https://unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" type="text/css" href="https://unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.css" />
<link rel="stylesheet" type="text/css" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" />

<script src="https://cdn.quilljs.com/1.3.4/quill.js"></script>
<script type="text/javascript" src="https://unpkg.com/vue@latest/dist/vue.min.js"></script>
<script type="text/javascript" src="https://unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.js"></script>

<div id="vueApp" class="container">
  <form id="myForm">
    <div class="form-group" style="padding-top:16px;">
      <div v-bind:class="{agendaAreaEdit: editMeetingObjective}">
        <label class="agenda-label" for="purpose">Meeting Objective</label>
        <button v-if="!showMeetingObjective && !editMeetingObjective" v-on:click="showMeetingObjective=true, editMeetingObjective=true;" href="#" type="button" class="btn btn-sm btn-min-padding pull-right"><i class="fa fa-pencil" aria-hidden="true"></i></button>
        <div class="agendaAreaEditor" id="objectives" v-on:keypress="checkTextArea('objectives')" v-show="showMeetingObjective || editMeetingObjective" v-bind:class="{error: agenda.objective.trim().length===0 && (showValidationErrors || showErrorObjective)}">
          <editor v-model="agenda.objective"></editor>
        </div>
        <!--<div v-if="agenda.objective.trim().length===0 && (showValidationErrors || showErrorObjective)">-->
        <div v-if="agenda.objective.trim().length===0 && showErrorObjective">
          <label class="fieldWarningLabel">Please enter in Meeting Objectives/Purpose</label>
          <div style="clear:both;"></div>
        </div>
        <button v-if="showMeetingObjective && editMeetingObjective" v-on:click="showMeetingObjective=false, editMeetingObjective=false;" class="btn btn-sm btn-min-padding pull-right" style="margin: 8px 0px 0px 0px;" href="#" type="button"><i class="fa fa-check" aria-hidden="true"><span class="buttonText" v-html='$t("button.save")'></span></i></button>
        <div style="clear:both"></div>
        <div v-show="!showMeetingObjective" id="textarea" v-html="agenda.objective" class="agendaAreaSmall" style="height:24px;"></div>
      </div>
    </div>
  </form>
</div>
...