1

我有一个User-Select包装v-select的组件。该组件的工作是获取用户列表作为用户类型,并允许用户选择一个或多个用户。这是该组件的代码。

<template>
  <div>
    <v-select
      id="recipients"
      name="recipients"
      :options="options"
      label="name"
      multiple
      @search="onSearch"
      v-model="selectedVal"
    />
  </div>
</template>

<script>
import vSelect from 'vue-select'
import axios from 'axios'
import _ from 'lodash'
export default {
  name: 'UserSelect',
  components: {
    'v-select': vSelect
  },
  props: {
    value: {
      type: Array
    }
  },
  data() {
    return {
      options: []
    }
  },
  computed: {
    selectedVal: {
      get() {
        return this.value
      },
      set(val) {
        //this.value = val
        this.$emit('input', val)
      }
    }
  },
  methods: {
    onSearch(search, loading) {
      loading(true)
      this.search(loading, search, this)
    },
    setSelected: function(val) {
      this.$emit('input', val)
    },
    search: _.debounce((loading, search, vm) => {
      axios
        .post('searchPeople', { search }, { useCredentails: true })
        .then(res => {
          vm.options = res.data
          loading(false)
        })
    }, 350)
  }
}
</script>

<style lang="scss" scoped>
@import url('https://unpkg.com/vue-select@latest/dist/vue-select.css');
</style>

如您所见,我有一个链接到计算属性的 v-model ,它发出输入事件。我的财产名称也是value. 因此,我希望使用此 UserEvent 组件的父组件能够进行 v-model。

编辑弹性快速t3pti

在父组件中,我有一个计算属性,我已经对所选值进行了 v 建模。这是代码。

<template>
  <div>
    <b-modal id="editMessage" :title="title" :static="true">
      <form id="newMessageForm" class="row">
        <div class="col-md-12">
          <div class="form-group row">
            <label for="to" class="col-sm-3 col-form-label">To:</label>
            <user-select
              class="col-sm-7"
              style="padding-left: 0px; padding-right: 0px"
              v-model="editedMessage.recipients"
            />
          </div>
          <div class="form-group row">
            <label for="subject" class="col-sm-3 col-form-label"
              >Subject:</label
            >
            <input
              id="subject"
              name="subject"
              type="text"
              class="form-control col-sm-7"
              :value="editedMessage.messageSubject"
            />
          </div>
          <div class="form-group row">
            <label for="date" class="col-sm-3 col-form-label"
              >Schedule for later :
            </label>
            <input
              type="checkbox"
              class="form-control col-sm-7"
              v-model="scheduleForLater"
              id="scheduleCheckBox"
            />
          </div>
          <div class="form-group row" v-if="scheduleForLater">
            <label for="date" class="col-sm-3 col-form-label"
              >Scheduled Date:</label
            >
            <datetime
              v-model="editedMessage.sentDate"
              type="datetime"
              class="col-sm-17"
              input-class="form-control col-sm-15"
              input-id="date"
            />
          </div>
          <div class="form-group row">
            <label for="body" class="col-sm-3 col-form-label">Message:</label>
            <textarea
              id="body"
              name="body"
              type="text"
              rows="10"
              class="form-control col-sm-7"
              :value="editedMessage.messageBody"
            ></textarea>
          </div>
        </div>
      </form>

      <template v-slot:modal-footer="{ hide }">
        <!-- Emulate built in modal footer ok and cancel button actions -->

        <b-button size="sm" variant="light" @click="hide()">
          Cancel
        </b-button>
        <b-button
          size="sm"
          variant="secondary"
          @click="
            sendMessage(true)
            hide()
          "
        >
          Save Draft
        </b-button>
        <b-button
          size="sm"
          variant="primary"
          @click="
            sendMessage(false)
            hide()
          "
        >
          Send
        </b-button>
      </template>
    </b-modal>
  </div>
</template>

<script>
import { mapState } from 'vuex'
import UserSelect from '@/components/UserSelect.vue'
import axios from 'axios'
export default {
  name: 'NewMessage',
  components: {
    'user-select': UserSelect
  },
  data() {
    return {
      options: [],
      scheduleForLater: false
    }
  },
  mounted() {},
  computed: {
    ...mapState({
      openMessage: state => state.message.openMessage,
      messageAction: state => state.message.messageAction
    }),
    editedMessage: {
      get() {
        if (this.messageAction === 'new') {
          return this.newMessage()
        } else if (this.messageAction === 'reply') {
          let openMessageClone = Object.assign({}, this.openMessage)
          // make sender as the recipient.
          return Object.assign(openMessageClone, {
            messageSubject: 'RE: ' + this.openMessage.messageSubject,
            recipients: [
              {
                name: this.openMessage.sender.name,
                id: this.openMessage.sender.id
              }
            ]
          })
        } else {
          let openMessageClone = Object.assign({}, this.openMessage)
          return Object.assign(openMessageClone, {
            messageSubject: 'FW: ' + this.openMessage.messageSubject
          })
        }
      },
      set(val) {
        this.$emit('input', val)
      }
    },
    title() {
      if (this.messageAction === 'new') {
        return 'New'
      } else if (this.messageAction === 'reply') {
        return 'Reply'
      } else {
        return 'Forward'
      }
    }
  },
  methods: {
    newMessage() {
      return {
        messageBody: '',
        messageSubject: '',
        recipients: [],
        sender: {}
      }
    },
    sendMessage(saveOrUpdateDraft) {
      var url = ''
      var message = {
        recipients: this.editedMessage.recipients.map(x => x.id),
        subject: this.editedMessage.messageSubject,
        body: this.editedMessage.messageBody,
        sentDate: this.scheduleForLater ? this.editedMessage.sentDate : null,
        id: ['editDraft', 'viewScheduled'].includes(this.messageAction)
          ? this.editedMessage.messageId
          : null
      }
      // id indiciates message id of draft message if one was opened.
      if (saveOrUpdateDraft) {
        // if no changes have been made to an opened draft, or the draft is completely empty for a new or existing draft , just go back.
        if (message.id) {
          url = `updateDraft`
        } else {
          url = 'saveNewDraft'
        }
      } else {
        if (message.id) {
          url = `sendSavedMessage`
        } else {
          url = 'sendMessage'
        }
      }
      axios
        .post(`eventdirect/${url}`, message, {
          withCredentials: true
        })
        .then(response => {
          if (url.includes('Draft') && this.messageAction === 'viewScheduled') {
            this.$store.dispatch('sent/moveToDraft', response.data)
          } else if (url.includes('Draft')) {
            this.$store.dispatch('drafts/updateDraft', response.data)
          } else {
            // else part is sending a message or scheduling a draft.
            if (this.messageAction === 'editDraft') {
              this.$store.dispatch('drafts/deleteDraft', response.data)
            }
            // if we are sending an existing scheduled messsage , just update the sent vuex store , so that the message moves from scheduled to sent bucket.
            if (this.messageAction === 'viewScheduled') {
              this.$store.dispatch('sent/updateMessage', response.data)
            } else {
              this.$store.dispatch('sent/addSentItem', response.data)
            }
          }
        })
        .catch(() => {
          // TODO , add a qtip here to notify user , this message should be sent later.
          // messages in draft store with target , should be posted to the target
          this.$store.dispatch('drafts/updateDraft', {
            ...message,
            target: url
          })
        })
    }
  }
}
</script>

现在我可以在 vue 开发工具中看到这个NewMessage组件中的计算值发生了变化。然而,这个组件不会重新渲染,并且选定的值不会传递给UserSelect组件,直到我切换,安排以后的复选框,这会导致组件数据发生变化,这会触发 Vue 组件突然开始显示选定的值。

这里发生了什么。关于 Vue 的反应性,我在这里无法理解。

感谢期待。你可以在这里试试,或者点击上方的编辑沙箱按钮查看和编辑代码。

要尝试它,请单击 Vue 消息链接,然后单击回复,然后键入“测试”,然后从下拉列表中选择“测试用户”。在您单击复选框 - 稍后安排之前,所选用户不会显示。

PS:在组件中,UserSelect,在计算属性 selectedVal 的设置器中,如果我手动设置属性值的值(通过简单地取消注释第 39 行 - 现在已注释),一切正常。但是,我收到一个警告,即不应直接设置属性。由于我正在发出输入事件,父组件应该更改其 v-model 并重新渲染,从而导致子组件重新渲染。请纠正我,如果我的理解是错误的。问题再次是父组件的 v-model 更改,但它不会重新渲染。

在此处输入图像描述

4

0 回答 0