Warm tip: This article is reproduced from serverfault.com, please click

vue.js-如何在Vue中具有绑定数据的DIV之间切换?

(vue.js - How to toggle between DIVs with bound data in Vue?)

发布于 2020-11-27 23:16:13

因此,我面临的问题是我有一个模板,可从Realtime 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结构看起来像这样

在此处输入图片说明

任何帮助将不胜感激...

Questioner
Makis Milas
Viewed
11
muka.gergely 2020-11-28 20:04:36

我认为你应该更多地基于Vue的最大功能(即 React 性和组件)构建

进一步分解逻辑,直到找到只做一件事的元素-这些元素可以成为你的组件。然后从这些原子组件构建业务逻辑。

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根据需要向下传递,而所有其他组件和函数都只通过以下方式操纵THAT列表events( React 性非常好!)
  • 因为所有组件都基于一个中央数据源,所以它们只需要处理作为的项目props(好吧,他们有一些内部状态,但是嘿-这只是一个片段!:))
  • 这两个组成部分仅具有一项责任:
    • NewEmail:向中央添加一个项目 emailList
    • SingleEmailRow:管理一个电子邮件项目中的数据

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

编辑:更新片段

我不得不更新该代码段,因为我对此不满意。

修改内容:

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

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