vue.js - 如何在 Vue 中绑定数据的 DIV 之间切换?
问题描述
所以我面临的问题是我有一个从实时 Firebase 数据库中获取数据的模板,同时用户可以通过一个input
元素导入更多数据。我正在使用 Vue.js,我需要将数据相互绑定。
这是我的模板:
<template>
<ul>
<li>
<input type="text" v-model="email" v-on:keyup.enter="addData()"/>
<img @click="addData()" src="@/assets/Plus.png" />
</li>
</ul>
<ul>
<li v-for="(item, key) in emails" :key="key">
<div>
<p>{{ item.data }}</p>
<img @click="deleteDataByKey(key)" src="@/assets/Delete.png" />
</div>
<div class="first">
<input type="text" v-model="comment[key]" v-on:keyup.enter="addComment(key, comment[key])"/>
<img @click="addComment(key, comment[key])" src="@/assets/Plus.png" />
</div>
<div class="second">
<p>{{ comment[key] }}</p>
<img @click="deleteCommentByKey(key)" src="@/assets/Delete.png" />
</div>
</li>
</ul>
</template>
现在发生的事情是,我想在<div class="first">
没有评论时显示,当有评论时,<div class="second">
应该在隐藏第一个评论时显示。
我尝试使用v-if="comment[key]"
,但它会立即切换 div。我也尝试了v-model.lazy
似乎正在工作的方法,但是没有调用更新数据库的方法。我尝试在方法中使用纯 JS 来更改 HTML,但似乎效果不佳。
这些是我的方法和数据:
data() {
return {
emailList: [],
email: "",
comment: []
};
},
addData() {
db.ref("emailItems").push({
data: data
});
this.email = "";
this.fetchData();
},
deleteDataByKey(key) {
db.ref("emailItems"+key).remove();
this.fetchData();
},
addComment(key, comment) {
db.ref(`emailItems/${key}/comment`).set(comment);
},
deleteCommentByKey(key){
db.ref("comment/"+key).remove();
this.fetchData();
},
fetchData() {
db.ref("emailItems")
.once("value")
.then(snapshot => {
this.emailList = snapshot.val().emailItems;
});
}
db结构看起来像这样
任何帮助将不胜感激...
解决方案
我认为你应该更多地基于Vue的(可以说)最大的特性,即:反应性和组件。
再进一步分解逻辑,直到你找到只做一件事的元素——这些元素可以是你的组件。然后从这些原子组件构建业务逻辑。
Vue.component('NewEmail', {
data() {
return {
email: null,
}
},
methods: {
handleKeyup() {
this.$emit("add-email", {
email: this.email,
comment: null
})
this.email = null
}
},
template: `
<div>
<label>
NEW EMAIL: <input
type="email"
placeholder="Type in an email"
v-model="email"
@keyup.enter="handleKeyup"
/>
</label>
</div>
`
})
Vue.component('SingleEmailRow', {
props: {
email: {
type: Object,
default: null,
}
},
methods: {
handleDeleteClick() {
this.$emit('remove-email', this.email)
},
},
template: `
<li
class="d-flex"
>
<div>
{{ email.email }}
</div>
<div>
<button
@click="handleDeleteClick"
>
X
</button>
</div>
<component
:is="email.comment ? 'HasEmailComment' : 'NoEmailComment'"
:email="email"
v-on="$listeners"
></component>
</li>
`
})
Vue.component('HasEmailComment', {
props: {
email: {
type: Object,
required: true
}
},
methods: {
handleUpdateComment() {
this.$emit('update:comment', { ...this.email,
comment: null
})
}
},
template: `
<div
class="d-flex"
>
<div>
{{ email.comment }}
</div>
<button
title="Remove comment"
@click="handleUpdateComment"
>
-
</button>
</div>
`
})
Vue.component('NoEmailComment', {
props: {
email: {
type: Object,
required: true
}
},
data() {
return {
comment: null,
}
},
methods: {
handleUpdateComment() {
this.$emit('update:comment', { ...this.email,
comment: this.comment
})
}
},
template: `
<div
class="d-flex"
>
<div>
<input
v-model="comment"
type="text"
placeholder="Write a comment"
/>
</div>
<button
title="Add comment"
@click="handleUpdateComment"
>
+
</button>
</div>
`
})
new Vue({
el: "#app",
data() {
return {
emailList: [],
}
},
methods: {
handleAddEmail(newEmail) {
if (!this.emailList.find(({
email
}) => email === newEmail.email)) {
this.emailList.push(newEmail)
}
},
handleRemoveEmail(toRemove) {
this.emailList = this.emailList.filter(({
email
}) => {
return email !== toRemove.email
})
},
handleUpdateComment(newEmail) {
this.emailList = this.emailList.map(email => {
if (email.email === newEmail.email) {
return newEmail
} else {
return email
}
})
}
}
})
.d-flex {
display: flex;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<new-email @add-email="handleAddEmail"></new-email>
<ul v-for="(email, i) in emailList" :key="i">
<single-email-row :email="email" @remove-email="handleRemoveEmail" @update:comment="handleUpdateComment"></single-email-row>
</ul>
</div>
好的,可以将comment
处理SingleEmailRow
放在其单独的组件中(基于我上面的想法)。
上面的片段中的要点是:
- 只有一个原始数据源(
emailList
在根组件中)根据需要向下传递props
,所有其他组件和函数只是通过操作该列表events
(反应性很棒!) - 因为所有组件都基于一个中央数据源,所以它们只需要使用它们作为
props
. (好吧,他们有一些内部状态,但是嘿 - 这只是一个片段!:)) - 这两个组件只有一个职责:
NewEmail
:将项目添加到中央emailList
SingleEmailRow
:管理一个电子邮件项目中的数据
我希望这可以帮助您找到解决问题的方法。
编辑:更新片段
我不得不更新片段,因为我对它不满意。
修改:
- 添加两个新组件
HasEmailComment
:NoEmailComment
- 更新
SingleEmailRow
了两个新组件
现在,所有组件只需要完成一项任务。
推荐阅读
- python - 在空的 Pandas DataFrame 中插入单元格
- cloudera - 为什么 drop table 在 impala-shell 中失败但在 Hue/Impala 中有效?
- r - 函数 mutate_if 和函数 auto.arima 的问题
- javascript - 为什么离开表单页面后没有显示一个隐藏视图更改
- python - 如何在 pyspark 中使用 pandas UDF 并在 StructType 中返回结果
- java - 为窗格创建和显示 JavaFX 应用程序的实用方法
- javascript - 进行图像直通,这样它就不会阻止交互
- javascript - 如何使用 Redux 过滤数据但保持旧状态?
- php - Laravel 服务提供者 - 使用多种配置
- java - 如何发布和使用依赖本地项目的 gradle 插件?