Vue-chat-scroll не работает с загрузчиком - PullRequest
0 голосов
/ 21 мая 2018

У меня есть окно чата с директивой v-chat-scroll, которое работает хорошо.Каждый раз, когда добавляется новое сообщение, окно чата прокручивается вниз.

Моя проблема в том, что у меня есть загрузчик между всеми сообщениями, который не распознается v-chat-scroll, и я никогда не нажимаю на прокрутку вниз, когда он "появляется "

<div class="message" v-chat-scroll>
  <div>
    <div v-for="message in messages" class="msg-box">
      {{ message }}
    </div>
    <!-- Loader don't scroll to bottom -->
    <div v-show="loader" class="msg-box">
      >>super loader>>
    </div>
  </div>
</div>
  • Я пытался обернуть загрузчик сообщений + внутри одного элемента div (как во фрагменте)
  • Я пытался поместить div загрузчика в v-for (с условным отображением только после последнего сообщения)
  • Я попытался принудительно прокрутить нижнюю часть прокрутки (используя scrollTop и scrollHeight) с помощью ref на главном div и просмотром loaderсвойство (true / false)

Но ни одно из этих решений не работает ... Если у кого-то есть решение для этой проблемы, это было бы так здорово!

Я сделал минималистскую версиюмой чат здесь: https://jsfiddle.net/StpFlp_DDK/6s0kbtkr/

Ответы [ 3 ]

0 голосов
/ 07 ноября 2018

Я знаю, что на вопрос уже дан ответ.Но это может быть лучшим подходом, когда свойство сообщения обновляется, вы выбираете в качестве ссылки свой контейнер сообщений, в котором вы определили свойство overflow-y: auto; и обновляете его следующим образом:

var container = this.$refs.yourRef;
container.scrollTop = container.scrollHeight;
0 голосов
/ 23 января 2019

вместо добавления div

<div v-show="loader" class="msg-box">
      >>super loader>>
    </div>

внутри сообщения div, вы можете добавить загрузчик в качестве фонового изображения и удалить фоновое изображение после завершения загрузки данных.как мне решить проблему!

0 голосов
/ 22 мая 2018

Посмотрите исходные коды для v-chat-scroll , выделите строку # = 27, вы найдете if (pause || e[e.length - 1].addedNodes.length != 1) return;

Когда loader = true (v-if="loader"),вы увидите e.length=2 и e[e.length - 1].addedNodes.length = 0, что не соответствует ожиданиям.

Поэтому я использовал одно уменьшение, чтобы суммировать длину добавленных узлов для каждого MutationRecord , затем работает.

Vue.config.productionTip = false

// Below codes (scrollToBottom and vChatScroll) is copied from v-chat-scroll at github:
// https://github.com/theomessin/vue-chat-scroll/blob/master/src/directives/v-chat-scroll.js
const scrollToBottom = el => {
    el.scrollTop = el.scrollHeight;
};

const vChatScroll = {
    bind: (el, binding) => {
        let timeout;
        let scrolled = false;

        el.addEventListener('scroll', e => {
            if (timeout) window.clearTimeout(timeout);
            timeout = window.setTimeout(function() {
                scrolled = el.scrollTop + el.clientHeight + 1 < el.scrollHeight;
            }, 200);
        });

        (new MutationObserver(e => {
            let config = binding.value || {};
            let pause = config.always === false && scrolled;
            if (pause 
            || 
            e.reduce((pre, cur) => { // sum the length of each addedNodes
              return pre+cur.addedNodes.length
            }, 0) < 1 // if sum(addedNodes.length) === 0, do nothing.
            ) return;
            scrollToBottom(el);
        })).observe(el, {childList: true, subtree: true});
    },
    inserted: scrollToBottom
};

Vue.directive('chat-scroll', vChatScroll)

const str = [
	"Lorem ipsum dolor sit amet, consectetur adipisicing elit, similique sequi perspiciatis praesentium iure debitis explicabo animi reiciendis!",
	"Error ipsa eaque officia tempore optio laborum porro illo, veritatis atque pariatur, vero voluptatem quos",
  "At doloremque eveniet labore, eligendi dicta beatae earum aperiam et, recusandae perspiciatis perferendis corporis dolorum quidem dolores esse labore."
]

new Vue({
  el: "#app",
  data: {
    messages: [],
    loader: false
  },
  methods: {
    addMessage() {
      this.loader = true

      setTimeout(() => {
        this.loader = false
        let randMsg = str[Math.floor(Math.random()*str.length)]
        this.messages.push(randMsg)
      }, 2000)
    }
  }
})
body {
  background: #20262E;
  padding: 20px;
  font-family: Montserrat;
}

#app {
  background: #D3F3F1;
  position: relative;
  border-radius: 4px;
  height: 300px;
  width: 350px;
}
.messages-container {
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  position: absolute;
  top: 0;
  bottom: 0;
  width: 100%;
}

.message {
  display: flex;
  flex-direction: column;
  flex-grow: 1;
  flex-shrink: 1;
  box-sizing: border-box;
  overflow-x: hidden;
  position: relative;
  width: 100%;
}

.msg-box {
  margin: 20px;
  padding: 20px;
  background-color: #fff;
  border-radius: 8px;
}

.input-message {
  position: relative;
  bottom: 0;
  background-color: white;
  width: 100%;
  height: 50px;
  text-align: center;
  flex-shrink: 0;
}

button {
  margin-top: 10px;
  border-radius: 4px;
  background: #D3F3F1;
  padding: 8px 15px;
  border: none;
}
<script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script>
<div id="app">
  <div class="messages-container">
    <div class="message" v-chat-scroll>
      <div>
        <div v-for="message in messages" class="msg-box">
          {{ message }}
        </div>
        <!-- Loader don't scroll to bottom -->
        <div v-if="loader" :class="loader ? 'msg-box' : ''">
          >>super loader>>
        </div>
      </div>

    </div>

    <div class="input-message">
      <button @click="addMessage">Add message</button>
    </div>
  </div>
</div>
...