问题描述
我尝试使用Vue CLI 3创建聊天应用程序,并且已经完成了实时聊天室的制作。然后,我尝试为其提供引用功能,以便用户可以引用该消息并进行回复。因此,我设法通过道具将引用的消息传递给子组件。引用的消息默认为NULL
。用户单击某些按钮后,我希望“被引用的消息”的值将更改,并且新值将通过props(自动更新)传递给孩子。但是,实际上不是。
当我浏览互联网时,我确实发现了一些有关在props值更改时更新子组件的问题。因此,我尝试了watch:
,created()
,update()
,但是它们都不起作用。
我曾经尝试直接在子组件中添加元素<p>
并将{{cited_message}}
放入其中,以查看变量内部的内容。然后,Vue应用程序崩溃了,留下空白的空白页(但控制台未显示任何错误)。
为方便起见,我认为问题在于:
<CreateMessage:name="name":cited_message="this.cited_message"@interface="handleFcAfterDateBack"/>
OR
props: ["name","cited_message"],watch: { cited_message: function (newValue){ this.c_message = newValue; } },
父组件:
<template>
<div class="container chat">
<h2 class="text-primary text-center">Real-time chat</h2>
<h5 class="text-secondary text-center">{{ name }}</h5>
<div class="card" style="min-height: 0.8vh">
<div class="card-body">
<p class="text-secondary nomessages" v-if="messages.length == 0">
[no messages yet!]
</p>
<div class="messages" v-chat-scroll="{ always: false,smooth: false }">
<div v-for="message in messages" :key="message.id">
<div v-if="equal_name(message)">
<div class="d-flex flex-row">
<div class="text-info">
[ {{ message.name }} ] : {{ message.message }}
</div>
<div class="btn-group dropright">
<a
class="btn btn-secondary btn-sm dropdown-toggle"
href="#"
role="button"
id="dropdownMenuLink"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
>
</a>
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
<button
@click="get_cited_message(message)"
:key="message.id"
class="dropdown-item"
href="#"
>
Cite
</button>
</div>
</div>
<div class="text-secondary time">
<sub>{{ message.timestamp }}</sub>
</div>
</div>
<!--below is for cited message-->
<div v-if="message.cited_message" class="d-flex flex-row">
Cited : {{ message.cited_message }}
</div>
</div>
<div v-else>
<div class="d-flex flex-row-reverse">
<div class="text-info">
[ {{ message.name }} ] : {{ message.message }}
</div>
<div class="text-secondary time">
<sub>{{ message.timestamp }}</sub>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card-action">
<CreateMessage
:name="name"
:cited_message="this.cited_message"
@interface="handleFcAfterDateBack"
/>
</div>
</div>
</div>
</template>
<script>
import CreateMessage from "@/components/CreateMessage";
import fb from "@/firebase/init.js";
import moment from "moment";
export default {
name: "Chat",props: {
name: String,},components: {
CreateMessage,methods: {
equal_name(message) {
if (message.name == this.name) {
return true;
} else {
return false;
}
},get_cited_message(message) {
this.cited_message = message.message;
console.log(this.cited_message);
},handleFcAfterDateBack(event) {
console.log("data after child handle: ",event);
},data() {
return {
messages: [],cited_message: null,};
},created() {
let ref = fb.collection("messages").orderBy("timestamp");
ref.onSnapshot((snapshot) => {
snapshot.docChanges().forEach((change) => {
change.type = "added";
if (change.type == "added") {
let doc = change.doc;
this.messages.push({
id: doc.id,name: doc.data().name,message: doc.data().message,timestamp: moment(doc.data().timestamp).format(
"MMMM Do YYYY,h:mm:ss a"
),cited_message: doc.data().cited_message,});
}
});
});
},};
</script>
<style>
.chat h2 {
font-size: 2.6em;
margin-bottom: 0px;
}
.chat h5 {
margin-top: 0px;
margin-bottom: 40px;
}
.chat span {
font-size: 1.2em;
}
.chat .time {
display: block;
font-size: 0.7em;
}
.messages {
max-height: 300px;
overflow: auto;
text-align: unset;
}
.d-flex div {
margin-left: 10px;
}
</style>
子组件:
<template>
<div class="container" style="margin-bottom: 30px">
<form @submit.prevent="createMessage()">
<div class="form-group">
<input
type="text"
name="message"
class="form-control"
placeholder="Enter your message"
v-model="newMessage"
/>
<p v-if="c_message" class="bg-secondary text-light">Cited: {{c_message}}</p>
<p class="text-danger" v-if="errorText">{{ errorText }}</p>
</div>
<button class="btn btn-primary" type="submit" name="action">
Submit
</button>
</form>
</div>
</template>
<script>
import fb from "@/firebase/init.js";
import moment from "moment";
export default {
name: "CreateMessage",props: ["name",watch: {
cited_message: function (newValue){
this.c_message = newValue;
}
},data() {
return {
newMessage: "",errorText: null,c_message: null
};
},methods: {
createMessage() {
if (this.newMessage) {
fb.collection("messages")
.add({
message: this.newMessage,name: this.name,timestamp: moment().format(),cited_message: this.c_message
})
.then(function(docRef) {
console.log("Document written with ID: ",docRef.id);
})
.catch((err) => {
console.log(err);
});
this.newMessage = null;
this.errorText = null;
} else {
this.errorText = "Please enter a message!";
}
},beforeMount(){
this.c_message = this.cited_message;
}
};
</script>
旁注:在上级组件中,我仅对左侧的消息进行了下拉菜单。如果此线程解决了,我将在右侧完成操作。
解决方法
已解决。我认为问题在于,当父组件中的变量更新时,子组件没有重新渲染。仅父组件被重新渲染。因此,孩子中的道具价值仍然是初始价值。为了解决这个问题,用v-bind:key绑定元素可以让Vue应用程序跟踪变量的变化(就像某种提醒,提醒应用程序遵循对键所做的更改)。当变量(键)更改时,将注意到该应用程序,并将新值传递给子级。
例如 原始
<CreateMessage
:name="name"
:cited_message="this.cited_message"
@interface="handleFcAfterDateBack"
/>
已解决
<CreateMessage
:name="name"
:cited_message="this.cited_message"
@interface="handleFcAfterDateBack"
:key="this.cited_message"
/>
即使问题已解决,我也不知道我是否清楚地理解了问题。如果我有任何错误,请发表评论并告诉我。