繁体   English   中英

从 Vue.JS 中的两个循环 arrays 正确输出数据

[英]Correctly outputting data from two looped arrays in Vue.JS

我正在使用 Vue.JS 开发这个基本的聊天应用程序,它就像一个聊天机器人概念,用户的输入会触发书面响应。 它有效,但我只知道如何 output 输入和响应,如下所示。 这样做的问题是 {{ data.message }} 和 {{ data.response }} 在彼此下循环,没有给 convo 排序。

用户的输入存储在“消息”数组中。 消息被循环

<div class="userMessageC">
  <div class="userMessage" v-for="(data, index) in messages" :key='index'>
    {{ data.message }}
  </div>
</div>

而机器人的响应存储在响应数组中。

<div class="botMessageC" v-for="(data, index) in responses" :key='index'>
  <span class="botAvatar">
    <img src="@/assets/pimAvatar.png" width="50"/> 
  </span>           
  <div class="botMessage">
    {{ data.response }} 
  </div>
</div>

我想要的是 data.message 之后是 data.response,然后是 data.message,然后是 data.response 等等。 我将如何解决这个问题? 这是它的样子(乱序)

在此处输入图像描述 .

一个 jsfiddle 给你更好的主意

因为您的“机器人”几乎被嘲笑,所以您的问题大大简化:它具有相同的响应时间,并且结果以与发送时相同的顺序返回。 对于真实的服务器而言,这并不总是正确的。

您要做的是创建一个包含messageresponseutterancepair实体,从返回 promise 的方法调用服务器,并在完成时将响应添加到话语中。 在模板中,您需要做的就是遍历话语:

data: () => ({
  utterances: []
})
methods: {
  sendRequest(message) {
    const utterance = { message, response: '' };
    this.utterances.push(utterance);
    this.outputResponse(message).then(response => utterance.response = response);
  },
  outputResponse(message) {
    // do whatever you want to get response and return a resolved promise:
    return Promise.resolve(response);
  }
}

模板如下所示:

<div v-for="(u, key) in utterances" :key="key">
  <div v-text="u.message" />
  <div v-text="u.response" />
</div>

在现实生活场景中,对 bot 的调用实际上可能与您的组件分离,您可能希望为每个话语提供一个uuid ,并且 map 根据该唯一标识符返回对话语的响应。
此外,记录输入消息的时间戳为您在未来按发送顺序存储和重新呈现它们打开了大门。


上面的outputResponse方法有点过于简单了。 调用实际的服务器看起来像这样:

outputResponse(message) {
  return axios.get('https://your.bot', params: { message })
    .then(response => response.data)
}

...假设机器人以简单的字符串响应。


看到它工作。
为了让它更像一个现实生活中的服务器,我让“bot”响应花费了一个可变的时间,在 1 到 15 秒之间:

 Vue.config.devtools = false; Vue.config.productionTip = false; new Vue({ el: '#app', data: () => ({ utterances: [], message: '' }), methods: { send(message) { const utterance = { message, response: '' }; this.utterances.push(utterance); this.getResponse(message).then(response => utterance.response = response); this.message = ''; }, getResponse: message => new Promise((resolve, reject) => { setTimeout(() => { resolve(`<pre> => </pre>${message} back...`); }, (Math.floor(Math.random() * 15) + 1) * 1e3) }) } })
 pre { margin: 2px 0 0; display: inline-block; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script> <div id="app"> <div> <input v-model="message" @keyup.enter="send(message)"> <button @click="send(message)">Send</button> (or press enter) </div> <div v-for="(u, k) in utterances":key="k" style="display: flex"> <div v-text="u.message"></div> <div v-html="u.response"></div> </div> </div>

您可以参考下面的响应索引。 所以它会在顶部显示消息,然后在下面显示与该消息相关的响应。 您也可以使用三元组进行错误处理,以防出现消息但没有响应您的代码不会中断

 <div class="userMessageC"> <div class="userMessage" v-for="(data, index) in messages":key='index'> <p>{{ data.message }}</p> <p> {{responses[index].response? responses[index].response: ""}}}</p> </div> </div>

好吧,我认为您可以使用计算属性来更新您的消息,并为问题和答案设置正确的顺序。

如果是您想要实现的,我不太了解,但这是我能理解的。

现在,我建议用和 Id (messageId) 识别每条消息并将 id 附加到响应中,然后您可以过滤响应并在任何时候收到任何响应时将其放置到位。

我对你的 jsfiddle 做了一些更新,你可以在这里看到(我猜,我不太清楚它是如何工作的)

模板,如果你想有消息然后响应,消息然后响应,更好的方法是在同一个v-for语句中:

<div class="messagesC"  v-for="(data, index) in rightOrder" :key='index'>
  <p class="userMessage">
    {{ data.message }}
  </p>
  <p class="botMessage">
    {{ data.response }}
  </p>            
</div>

现在在您的方法中,您可以添加 Id

...
sendResponse() {
  const messageId = Math.random().toString(16).slice(2); // Generate uuid
  this.messages.push({
    message: this.message,
    messageId,
  }) // Push message with its id
  this.outputResponse(this.message, messageId);
},

outputResponse(input, messageId){ // receives message and messageId
  this.message = '';
  this.timer = setTimeout(() => {
    try {
        var output = input + "=" + eval(input);
    } catch (e) {
        var utterance = [
          ["hello"],
          ],intent = [
            ["hello back!"]
            ],fallback = ["this is a response to your input"];
        var text = (input.toLowerCase()).replace(/[^\w\s\d]/gi, "");    
        if (this.compare(utterance, intent, text)) {
            output = this.compare(utterance, intent, text);
        } else {
            output = fallback[Math.floor(Math.random() * fallback.length)];
        } 
    }
      this.responses.push({
       response: output,
       messageId
      }) // send back the response and the messageId
  }, 1000);
}
...

现在计算的属性

computed: {
  // computed property that searches for an answer
  // taking into account the message order
  rightOrder() {
    return this.messages.map(message => {
      const response = {
      // Search a response with the messageId
      ...this.responses.find(
        response => response.messageId === message.messageId
      )}
      // return the message, messageId and its response
      return {
        message: message.message,
        ...response
      }
    })
  }
},

最后是 CSS

#window {
  float: left;
  width: 100%;
}
.userMessage {
  flex: flex-shrink;
  margin-right: 10px;
}
.botMessage {
  flex: flex-shrink;
}
.messagesC {
  display: flex;
  flex-wrap: wrap;
}
.click {
  float: left;
  background: black;
  color: white;
  padding: 0.5%;
}

您可以在不等待响应的情况下发送消息,一旦responses有新响应,它将立即显示在消息之后

我可能创建了一个计算属性,它结合了消息和响应并对其进行迭代

computed: {
  messagesAndResponses() {
    return this.messages.map((m, i) =>
      ({message: m.message, response: this.responses[i]})
    );
  }

然后在模板中

<div 
    v-for="(m,i) in messagesAndResponses"
    :key="i"
>
  <div class="userMessageC">
    <div class="userMessage">
      {{ m.message }}
    </div>
  </div>
  <div class="botMessageC">
    <span class="botAvatar">
      <img src="@/assets/pimAvatar.png" width="50"/> 
    </span>           
    <div class="botMessage">
      {{ m.response }} 
    </div>
  </div>
</div>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM