开发者问题收集

document.getElementById 在 Vue2 组件中未定义...因为误用了监视?

2019-07-14
2249

我正在制作一个基本的聊天组件,将来自 firebase 的消息加载到 div 中。

  • 目标是当 relevantMessages 更改时自动滚动到 div 的底部,如果当前滚动位置已经接近底部。

我尝试通过向 relevantMessages 添加一个调用“scrollToBottom”方法的观察器来实现这一点。

问题是:观察器“relevantMessages”的回调错误:

"TypeError: Cannot read property 'scrollTop' of undefined"

HTML:

<template>
  <div class="all">
    <div class="chat-header">
      ...
    </div>
    <div class="messages-area" id="messages-area-id" ref="messagesAreaRef">
      <div
        v-for="(thing, index) in relevantMessages"
        :key="index"
        class="message-row"
      >
        <div class="message">
          <span>{{thing.content}}</span>
          <span>{{thing.timeStamp}}</span>
        </div>
      </div>
    </div>
    <div class="input-area">
      ...
  </div>
</template>

JS:

<script>
import firebase from "firebase";
export default {
  data() {
    return {
      relevantMessages: Object,
      partnerObj: null
    };
  },
  computed: {
    ...
  },
  props: {
    ...
  },
  mounted: function() {
    this.getMessages();
    this.getPartner();
  },
  watch: {
    relevantMessages: function() {
      this.scrollToBottom();
    }
  },
  methods: {
    getMessages: function() {
      var that = this;
      firebase
        .database()
        .ref("/messages/" + that.conversationUID)
        .on("value", function(messages) {
          var result = messages.val();
          that.relevantMessages = result;
        });

      console.log("getting posts");
    },
    sendMessage: function() {
      ...
    },
    scrollToBottom: function() {
      var messagesArea = this.$refs.messagesAreaRef;
      // var messagesArea = document.getElementById("messages-area-id");

      var currentScrollPos = messagesArea.scrollTop;
      // console.log(currentScrollPos);
      var totalDivHeight = messagesArea.scrollHeight;
      if (currentScrollPos <= totalDivHeight - 100) {
        messagesArea.scrollTop(totalDivHeight);
      }
    }
  }
};

错误本身:

  • vue.runtime.esm.js?2b0e:619 [Vue warn]: Error in callback for watcher "relevantMessages": "TypeError: Cannot read property 'scrollTop' of undefined"

  • TypeError: Cannot read property 'scrollTop' of undefined

2个回答

此时组件本身可能尚未安装。因此所有 $refs 都是 未定义 。尝试在 mounted() 中使用 watch 的替代语法( 文档 )。希望有帮助!

Lueton
2019-07-14

您的实现存在一些问题:

  • relevantMessages: Object,
    

    Object 似乎不是 relevantMessages 的有效初始值。您应该将其设置为空对象 ( { ) 或空数组 ( [] )。

  • messagesArea.scrollTop(totalDivHeight);
    

    scrollTop 不是函数,应像 messagesArea.scrollTop = totalDivHeight 那样使用。

  • 您用于滚动到底部的实现不正确;如果 currentScrollPos 靠近 顶部 ,它将始终小于其容器的高度。要检查它是否靠近底部,您应该有 currentScrollPos >= totalDivHeight - messagesArea.clientHeight - 100

现在,即使进行了上述更改,观察程序似乎也会在 Vue 有机会实际重新渲染和更新 DOM 之前运行并执行(因此,滚动将始终落后一个节点),因此您必须在 “next tick” 之后调用 scrollToBottom

watch: {
  relevantMessages() {
    this.$nextTick(this.scrollToBottom);
  }
},

我在 CodeSandbox 中创建了一个工作示例: https://codesandbox.io/embed/vue-template-tqo4k

chipit24
2019-07-14