【问题标题】:document.getElementById is undefined in Vue2 component...because misusing watch?document.getElementById 在 Vue2 组件中未定义...因为滥用手表?
【发布时间】:2019-07-14 12:43:27
【问题描述】:

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

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

我尝试通过向relevantMessages 添加一个调用'scrollToBottom' `方法的观察者来做到这一点。

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

“TypeError:无法读取未定义的属性'scrollTop'”

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 警告]:观察者“relevantMessages”的回调错误:“TypeError:无法读取未定义的属性 'scrollTop'”

  • TypeError: 无法读取未定义的属性“scrollTop”

【问题讨论】:

  • 它与document.getElementById("messages-area-id") 一起使用了吗?
  • 你试过检查 this.$refs 的值吗?
  • @Dadboz 不,它也不起作用。我可以通过引用 div 的 ID 毫无问题地更改 CSS,所以它肯定在那里找到它,所以我不明白为什么它不工作
  • @cppstudy 当我控制台记录 ref 和 getElementById 时,它们都正确地控制台记录

标签: html vue.js vuejs2


【解决方案1】:

也许此时组件本身尚未安装。所以所有$refs 都是undefined。在mounted() 中尝试使用 watch (Documentation) 的替代语法。希望对您有所帮助!

【讨论】:

  • 对不起,我不太明白你的建议。你能以对初学者友好的方式重新表述吗?当我查看该链接时,我不确定要从中获取什么
  • 避免在没有上下文的情况下链接到文档,并在您的答案中包含任何相关的 sn-ps。请参阅stackoverflow.com/help/how-to-answer 中的“为链接提供上下文”。
  • 另外,在@9142016 的情况下,ref 似乎是在调用观察者函数时定义的。
【解决方案2】:

您的实施存在一些问题:

  • relevantMessages: Object,
    

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

  • messagesArea.scrollTop(totalDivHeight);
    

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

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-09-08
    • 1970-01-01
    • 2021-09-13
    • 1970-01-01
    • 2018-07-03
    • 1970-01-01
    • 2015-02-07
    • 1970-01-01
    相关资源
    最近更新 更多