首页 > 解决方案 > 如何在 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.jsfirebase-realtime-database

解决方案


我认为你应该更多地基于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:管理一个电子邮件项目中的数据

我希望这可以帮助您找到解决问题的方法。

编辑:更新片段

我不得不更新片段,因为我对它不满意。

修改:

  • 添加两个新组件HasEmailCommentNoEmailComment
  • 更新SingleEmailRow了两个新组件

现在,所有组件只需要完成一项任务。


推荐阅读