Während ich mit Vue.js experimentiere, lerne und vor allem spiele, baue ich verschiedene Arten von Apps, um Übung darin zu bekommen und meinen Umgang damit zu verbessern. Vor ein paar Wochen las ich vom Shutdown von Diggs RSS Reader und obwohl es tolle Alternativen gibt, dachte ich, es wäre lustig, meinen eigenen mit Vue zu bauen. In diesem Artikel werde ich erklären, wie ich ihn zusammengestellt habe und was daran falsch ist. Ich wusste, dass ich einige Kompromisse eingehen würde, daher ist der Plan, diese Version in einem Folgebeitrag mit einer besseren zu aktualisieren.
Artikelserie
- Einrichtung und erste Iteration (Dieser Beitrag)
- Verfeinerungen und Endversion
Beginnen wir mit der Betrachtung der App und der Erklärung der verschiedenen Komponenten.
Ein Blick auf die App
Beim Öffnen der Anwendung werden Sie mit einigen grundlegenden Anweisungen und der Aufforderung, einen neuen RSS-Feed hinzuzufügen, begrüßt.

Ein Klick auf den Button öffnet ein Modal, in dem Sie einen Feed eingeben können

Sobald Sie den Button hinzugefügt haben, werden die Blogeinträge dieses Feeds angezeigt

Beachten Sie die Farbe. Ich habe es so eingerichtet, dass jeder Feed eine eindeutige Farbe hat, was es einfacher macht, den Inhalt einer Seite von einem anderen zu unterscheiden. Hier ist zum Beispiel, wie es mit mehr hinzugefügten Feeds aussieht.

Das Panel auf der linken Seite ermöglicht das Filtern durch Klicken auf einen Feed. Leider kann man einen Feed noch nicht löschen, also müssen Sie, wenn Sie etwas entfernen müssen, Ihre DevTools öffnen und den gecachten Wert bearbeiten.
Lassen Sie uns den Tech-Stack durchgehen!
Die Komponenten
An erster Stelle steht die Vue-Bibliothek selbst. Ich verwende *nicht* webpack für diese Anwendung – nur einen einfachen Skript-Include ohne Build-Prozess.
Das UI besteht vollständig aus Vuetify, einem sehr schönen Material-Design-Framework, das einfach zu bedienen ist. Ich lerne es noch, daher können Sie sicher sein, dass mein Design besser sein könnte, obwohl ich wirklich zufrieden mit dem jetzigen Aussehen bin.
Die Persistenz wird über localStorage realisiert. Ich speichere die Metadaten des Feeds, die aus dem RSS-Feed abgerufen werden. Dazu gehören in der Regel Dinge wie der Name der Website, die Haupt-URL und eine Beschreibung. Ich speichere keine Feed-Elemente, was bedeutet, dass ich bei jedem Laden der Website die Elemente neu abrufe. Die nächste Version wird die Elemente lokal mit IndexedDB speichern.
Wie lade ich also Feed-Informationen? Ich könnte einfach eine Netzwerkanfrage an die URL stellen, aber die meisten RSS-Feeds nutzen CORS nicht, was bedeutet, dass der Browser das Laden blockieren würde. Um dies zu umgehen, habe ich eine schnelle serverlose Funktion mit Webtask geschrieben. Sie kümmert sich sowohl um die Erstellung eines CORS-freundlichen Endpunkts als auch um die Umwandlung des XML der Feeds in ein freundliches JSON.
Nachdem wir nun die verschiedenen Teile der Anwendung besprochen haben, schauen wir uns den Code an!
Das Layout
Beginnen wir mit dem Layout. Wie gesagt, ich verwende Vuetify für die Benutzeroberfläche. Ich habe mit dem Dark Sample Layout begonnen. Dies erzeugt den Header, den Footer und die linke Spalte, die für das Menü verwendet wird.

Ich habe die Kartenkomponente für einzelne Feed-Elemente verwendet. Mit dem Layout hier bin ich noch nicht ganz zufrieden. Zum Beispiel werden die Veröffentlichungsdaten noch nicht angezeigt, da ich Schwierigkeiten hatte, eine schöne Möglichkeit zur Anzeige zu finden. Ich habe beschlossen, dies einfach zu verschieben und bis zur nächsten Version zu warten, die wir **in Teil 2 dieser Serie sehen werden.**
Anstatt Ihnen den gesamten Quellcode auf einmal zu präsentieren, betrachten wir die einzelnen Teile. Zuerst hier der einleitende/hilfreiche Text, bevor Feeds hinzugefügt wurden
<div v-if="showIntro">
<p>
Welcome to the RSS Reader, a simple way to manage RSS feeds and read content. To begin using the RSS Reader, add your first feed by clicking the button below.
</p>
<p>
<v-btn color="primary" large @click="addFeed">
<v-icon>add</v-icon>
Add Feed
</v-btn>
</p>
</div>
Wenn Sie Feeds haben, werden Elemente als Liste von Karten angezeigt
<v-container fluid grid-list-lg>
<v-layout row wrap>
<v-flex xs12 v-for="item in items">
<v-card :color="item.feedColor">
<v-card-title primary-title>
<div class="headline">{{item.title}}</div>
</v-card-title>
<v-card-text>
{{item.content | maxText }}
</v-card-text>
<v-card-actions>
<v-btn flat target="_new" :href="item.link">Read on {{item.feedTitle}}</v-btn>
</v-card-actions>
</v-card>
</v-flex>
</v-layout>
</v-container>
Beachten Sie den Button zum Lesen eines Feed-Elements, der ein target verwendet, um es in einem neuen Tab zu öffnen.
Zur Anzeige von Feeds verwende ich eine Listenkomponente
<v-list dense>
<v-list-tile @click="allFeeds">
<v-list-tile-action>
<v-icon>dashboard</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>All Feeds</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
<v-list-tile @click="filterFeed(feed)" v-for="feed in feeds" :value="feed == selectedFeed">
<v-list-tile-action>
<v-icon :color="feed.color">bookmark</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>{{ feed.title }} </v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
<v-list-tile @click="addFeed">
<v-list-tile-action>
<v-icon>add</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>Add Feed</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</v-list>
Schließlich hier das Modal-Layout
<v-dialog v-model="addFeedDialog" max-width="500px">
<v-card>
<v-card-title>Add Feed</v-card-title>
<v-card-text>
Add the RSS URL for a feed below, or the URL for the site and I'll try to
auto-discover the RSS feed.
<v-text-field v-model="addURL" label="URL" :error="urlError"
:rules="urlRules"></v-text-field>
</v-card-text>
<v-card-actions>
<v-btn color="primary" @click.stop="addFeedAction">Add</v-btn>
<v-btn color="primary" flat @click.stop="addFeedDialog=false">Close</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
Die Logik
Nun zum spaßigen Teil – JavaScript! Wie zuvor werde ich Ihnen nicht die gesamte Datei übergeben. Stattdessen nehmen wir sie Stück für Stück in Angriff.
Beim Start lade ich alle vorhandenen Feeds, die möglicherweise definiert wurden, und zeige dann den Einführungstext an, falls erforderlich
created() {
this.restoreFeeds();
if (this.feeds.length === 0) this.showIntro = true;
},
Die Methode restoreFeeds kümmert sich um die Überprüfung von LocalStorage auf vorhandene Feeds.
restoreFeeds() {
let feeds = localStorage.getItem('feeds');
if (feeds) {
this.feeds = JSON.parse(feeds);
this.feeds.forEach((feed,idx) => {
feed.color = colors[idx % (colors.length-1)];
this.loadFeed(feed);
});
}
},
Beachten Sie, dass diese Methode das Zuweisen einer Farbe (die ein einfaches Array ist) und das Laden von Feed-Daten übernimmt.
Davon sprechend, wie gehe ich mit dem Laden von RSS-Informationen um? Derzeit geschieht dies zu zwei Zeitpunkten. Erstens, wenn Sie den Feed initial hinzufügen, und zweitens, wenn Sie die Anwendung neu laden und der Feed bereits definiert war. In beiden Fällen rufe ich eine URL auf – die serverlose Aufgabe, die mit Webtask definiert ist. Diese Aufgabe liefert alles – die Metadaten des Feeds und die Elemente selbst. Ich kümmere mich nur um die Metadaten beim *ersten* Aufruf und theoretisch hätte ich den Code etwas schneller machen können, indem ich die Metadaten auf der Serverseite entferne und aussonnere, aber es schien den Aufwand nicht wert zu sein.
Diese serverlose Funktion ist ziemlich einfach
'use strict';
const Parser = require('rss-parser');
const parser = new Parser();
module.exports = function(context, cb) {
let url = '';
if(context.body && context.body.url) url = context.body.url;
if(context.query && context.query.url) url = context.query.url;
if(url === '') cb(new Error('URL parameter not passed.'));
console.log('gonna parse '+url);
parser.parseURL(url)
.then(feed => {
console.log(feed);
cb(null, {feed:feed});
})
.catch(e => {
cb(e);
});
}
Ich wickle hier nur das npm-Paket rss-parser ein, und das kümmert sich um die gesamte Konvertierung für mich. Die if-Anweisungen, die Sie am Anfang sehen, kümmern sich um die Suche nach dem url-Parameter. Beim Aufruf meines Webtasks kann ich entweder eine Abfragezeichenfolgenvariable übergeben oder sie als Teil eines HTTP-Bodys senden. In beiden Fällen verwende ich einfach das rss-parser-Modul und gebe das Ergebnis zurück.
Der Endpunkt für diese Funktion ist
https://wt-c2bde7d7dfc8623f121b0eb5a7102930-0.sandbox.auth0-extend.com/getRss
Sie können ihn gerne selbst ausprobieren. Sie sehen dies in der Methode, die das Hinzufügen eines Feeds behandelt
addFeedAction() {
this.urlError = false;
this.urlRules = [];
//first, see if new
if(this.feeds.findIndex((feed) => {
return (feed.rsslink === this.addURL);
}) >= 0) {
this.urlError = true;
this.urlRules = ["URL already exists."];
return;
} else {
fetch(rssAPI+encodeURIComponent(this.addURL))
.then(res => res.json())
.then(res => {
// ok for now, assume no error, cuz awesome
this.addURL = '';
//assign a color first
res.feed.color = colors[this.feeds.length % (colors.length-1)];
// ok, add the items (but we append the url as a fk so we can filter later)
res.feed.items.forEach(item => {
item.feedPk = this.addURL;
item.feedColor = res.feed.color;
this.allItems.push(item);
});
// delete items
delete res.feed.items;
// add the original rss link
res.feed.rsslink = this.addURL;
this.feeds.push(res.feed);
this.addFeedDialog = false;
//always hide intro
this.showIntro = false;
//persist the feed, but not the items
this.storeFeeds();
});
}
},
Diese Methode prüft zuerst, ob ein Feed bereits existiert und, falls nicht, ruft sie den serverlosen Endpunkt auf, um die Details zu erhalten. Ich habe eine gewisse Datenredundanz beim Speichern von Elementen. Ich wollte die Elemente nicht „unter“ einem Feed-Objekt speichern, sondern einen globalen Vue-Datenwert, allItems, verwenden. Daher kopiere ich die Feed-ID und die Farbe in jedes Element. Die Idee war, die Anzeige und Filterung von Elementen später zu erleichtern. Das fühlt sich für mich „falsch“ an, aber auch hier, dies ist mein erster Entwurf. Ich verwende eine berechnete Eigenschaft für Elemente, und Sie können diese Logik hier sehen
items:function() {
if(this.allItems.length === 0) return [];
// filter
let items = [];
if(this.selectedFeed) {
console.log('filtered');
items = this.allItems.filter(item => {
return item.feedPk == this.selectedFeed.rsslink;
});
} else {
items = this.allItems;
}
items = items.sort((a, b) => {
return new Date(b.isoDate) - new Date(a.isoDate);
});
return items;
}
Wenn ich es mir jetzt ansehe, könnte ich meine Elemente aus jedem Feed sammeln, anstatt ein globales Array zu speichern, obwohl ich das später beheben könnte, wenn ich möchte. Ich liebe, dass Vue mir Optionen gibt, wie ich solche Dinge lösen kann.
Wo geht es weiter?
Als ich diesen Artikel begann, dachte ich ausdrücklich: *dies* *ist* ein erster Entwurf. Ich habe hier und da Dinge hervorgehoben, die mir gefallen und die mir nicht gefallen, aber was genau plane ich für die nächste Version?
- Ich möchte den gesamten Datenzugriff in Vuex verschieben. Vuex wird als „State-Management-Muster + Bibliothek“ für Vue beschrieben. Wenn das für Sie nicht viel Sinn ergibt, machen Sie sich keine Sorgen. Ich hatte anfangs auch keine Ahnung, was das bedeutet. Für mich bietet Vuex eine Möglichkeit, komplexere Daten auf gekapselte Weise zu verwalten. Dies wird noch wichtiger, wenn Sie mehr Komponenten erstellen, die Daten austauschen müssen.
- Wo wir gerade von Komponenten sprechen, ich sollte „Item“ als eine richtige Vue-Komponente in Betracht ziehen. Das ist ein einfacher Gewinn.
- Ich möchte Feed-Elemente in IndexedDB speichern, damit Sie Inhalte erhalten, sobald Sie die Anwendung öffnen. Dies macht die Anwendung wesentlich performanter und bietet grundlegende Offline-Unterstützung. Natürlich können Sie die vollständigen Einträge im Offline-Modus nicht lesen, aber zumindest *etwas* könnte bereitgestellt werden.
- …und alles, was Sie vorschlagen! Schauen Sie sich den Code an und machen Sie gerne Vorschläge und weisen Sie auf Fehler hin!
Bleiben Sie dran für den zweiten Beitrag!
Ich liebe den Artikel. Ich bin gerade dabei, meinen RSS-Reader zu überarbeiten, der mit Vuex und Vuejs erstellt wurde. https://github.com/mrgodhani/rss-reader/tree/newversion