Асинхронное обновление элементов массива - часы не срабатывают

Я создал компонент, который отображает превью статей в блоге. Этот компонент имеет разбиение на страницы, и при выборе новой страницы я обновляю массив превью статей. Список статей берется из JSON api с server1. Ответ содержит информацию для выборки каждой статьи с сервера 2. Затем я запускаю x асинхронных выборок на сервер 2, столько же, сколько элементов в первом ответе. В этих ответах я обновляю элементы в массиве.

Я новичок в vue, но после некоторой борьбы я заставил это работать. Теперь я пытаюсь добавить счетчик в превью статей, пока загружаются отдельные статьи. Моя идея заключалась в том, чтобы следить за обновлением статьи в компоненте предварительного просмотра и показывать счетчик в зависимости от этого. К сожалению, это не работает, и теперь я начинаю сомневаться в своей реализации. Я заметил, что часы в предварительном просмотре не вызываются для каждого компонента предварительного просмотра, но все же каждый предварительный просмотр обновляется и отображается правильно. Я предполагаю, что это из-за системы обмена сообщениями, но мне не удается это исправить.

У меня двоякий вопрос:

  • Является ли моя реализация правильным способом решения этой проблемы? Чтобы это заработало, мне нужно «стереть» массив, потому что в противном случае новые статьи «перезаписывали» старые, и это было видно.
  • Как я могу обращаться с блеснами. Почему не срабатывают часы и как это исправить? В приведенном ниже коде есть несколько консольных записей. Я вижу 10 раз «асинхронно» и каждый раз разное количество «часов», никогда не 10.

Полный код находится на github здесь: Дом и СтатьяПредварительный просмотр. Это самые важные части:

Дом:

<template>
    <div class = "container article">
        <div class = "row" v-for = "(article, index) in articles" :key = "index">
            <ArticlePreview v-bind:blogEntry = "article"></ArticlePreview>
        </div>
        <b-pagination-nav :use-router = "true" :link-gen = "generateLink" align = "center" :number-of-pages = "nofPages" v-model = "pageIndex" />
    </div>
</template>

data: function ()
{
    return {
        articles: <BlogEntry[]> [],
        nofPages: 1
    }
},

loadContent()
{
    fetch("./api/v1/articles.php?page = " + this.pageIndex)
    .then(response => response.json())
    .then((data) =>
    {
        this.nofPages = Math.ceil(data.nofItems/10);
        this.articles.splice(0);
        this.articles.splice(data.data.length);
        let index :number;
        for(index = 0; index < data.data.length; index++)
        {
            createArticleAsync(data.data[index].name, data.data[index].permlink).then(function(this: any, index: number, article: BlogEntry)
            {
                console.info('async');
                    Vue.set(this.articles, index, article);
            }.bind(this, index));
        }
    })
},

СтатьяПредварительный просмотр:

<template>
    <div class = "container-fluid">
        <div class = "row" v-if = "blogEntry">
            <template v-if = "blogEntry">
                <div class = "imageframe col-md-3">
                    <div class = "blog-image">
                        <img :src = "blogEntry.previewImage" style = "border-radius: 5px;">
                    </div>
                </div>
                <div class = "col-md-9">
                    <h5 class = "font-weight-bold" style = "margin-top:5px;"><router-link :to = "{ name: 'Article', params: {author: blogEntry.author, permlink: blogEntry.permlink } }">{{blogEntry.title}}</router-link></h5>
                    <div class = "multiline-ellipsis">
                        <p>{{blogEntry.previewBody}}</p>
                    </div>
                    <span class = "metadata"><i>by <a :href = "AuthorBlogLink">{{blogEntry.author}}</a> on {{blogEntry.created | formatDate}}</i></span>
                </div>
            </template>
            <template v-else>
                <p>Loading</p>
            </template>
        </div>
    </div>
</template>

<script lang = "ts">
    import Vue from "vue";
    import VueRouter from 'vue-router';

    import {formatDate} from "../utils/utils";

    export default Vue.extend({
        props: [
            'blogEntry'
        ],
        data: function ()
        {
            return {
                loading: true
            }
        },
        watch:
        {
            blogEntry(newValue)
            {
                console.info('watch');
                if (newValue)
                    this.loading = false;
                else
                    this.loading = true;
            }
        }
    });
</script>
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
0
45
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я думаю, что метод получения подробных данных статьи должен быть инкапсулирован внутри компонента, а состояние загрузки также поддерживается внутри. Точно так же, как приведенный ниже код: (Он не работает должным образом, потому что Mockjs не может правильно выполняться во фрагменте)

Mock.setup({timeout: 2000})
const URL_ARTICLE_LIST = '/api/v1/articles.php'
const URL_ARTICLE_DETAIL = '/api/v1/article_detail.php'

Mock.mock(//api/v1/articles\.php.*/,function(options){
  return {
    nofItems: 33,
    data: Mock.mock({
      'list|10': [{
        'title': '@title',
        'url': URL_ARTICLE_DETAIL
      }]
    }).list
  }
})
Mock.mock(URL_ARTICLE_DETAIL,function(options){
  return Mock.mock({
  	content: '@paragraph'
  })
})

Vue.component('article-card',{
  template:  `
    <div>
      <template v-if = "!loading">
        <div class = "article-title">{{articleTitle}}</div>
        <div class = "article-content">{{article.content}}</div>
      </template>
      <template v-else>
        <div>loading...</div>
      </template>
    </div>`,
  data () {
    return {
      loading: false,
      article: {}
    }
  },
  props: {
    articleTitle: {
      required: true,
      type: String
    },
    articleUrl: {
      required: true,
      type: String
    }
  },
  watch: {
    articleUrl (url,oldUrl) {
      if (url && url!=oldUrl){
      	this.loadContent()
      }
    }
  },
  methods: {
  	loadContent () {
  		this.loading = true;
      //or your own async functions
      axios.get(this.articleUrl).then(res=>{
        this.article = res.data
        this.loading = false;
      })
  	}
  },
  created () {
  	this.loadContent()
  }
});

var app = new Vue({
  el: '#app',
  data () {
  	return {
	    articles: [],
	    nofPages: 1,
	    page: 1 //you should get page param from vue-router just like this.$route.query.page  		
  	}
  },
  created () {
    //you can also use fetch here
    axios.get(URL_ARTICLE_LIST+'?page='+this.page).then(res=>{
    	console.info(res.data)
      this.nofPages = Math.ceil(res.data.nofItems/10);
      this.articles = res.data.data
    })
  }  
})
	ul,li{
		list-style: none;
	}
	.article_list{
		display: flex;
		flex-wrap: wrap;
	}
	.article_list>li{
		width: 300px;
		background: skyblue;
		color: white;
		margin: 10px;
	}
	.article-content{
		text-indent: 2em;
	}
	.pagination-wrapper>li{
		display:inline-block;
		padding: 5px;
		border: 1px solid skyblue;
		margin: 3px;
	}
	.pagination-wrapper>li.active{
		background: skyblue;
		color: #fff;
	}
<script src = "https://cdn.bootcss.com/Mock.js/1.0.1-beta3/mock-min.js"></script>
<script src = "https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<script src = "https://unpkg.com/axios/dist/axios.min.js"></script>
<div id = "app">
  <ul class = "article_list">
    <li v-for = "article of articles">
      <article-card :article-title = "article.title" :article-url = "article.url"></article-card>
    </li>
  </ul>
  <ul class = "pagination-wrapper">
  	<li v-for = "x in nofPages" :class = "{active: page==x}">{{x}}</li>
  </ul>
</div>

Другие вопросы по теме