使用AngularJS制作一个简单的RSS阅读器的教程

简介

几年前,我用C#写了一个RSS阅读器,但是我想如果把它做成一个SPA(单页应用)效果会更好。 Angular使一些事情变得简单,RSS阅读器就是其中之一。 我也用Twitter Bootstrap(做UI)实现了RSS阅读器,调试页面样式是最难的地方之一...可能是因为我不擅长css的原因。

背景

我有一些自己喜欢的网站( CodeProject, Dr.Dobb's Journal, ComputerWorld, Inc. Magazine)。 然而,我发现其中很多网站都有烦人的广告、风格不好的布局,我实在不愿意看到这些东西。当我说这话的时候,并不包括 CodeProject网站。

在这些网站之间来回切换浪费了很多时间。 因此我更喜欢浏览文章标题和简介,这样我可以决定是否进入文章内容页面。 这就是我决定写FreedReadR 单页应用的原因。

FreedReadR 响应是比较快的,因为它读取的数据量(RSS源)比较小。

下面是点击CodeProject选项的效果图:

下面是FreedReadR 加载某一个站点数据的效果图:

你现在可以试下效果:

http://newtonsaber.com/FreedReadR

差点忘了,我在创建自己的RSS 阅读器之前在Google上搜索了这个想法,发现jsfiddle中一段比较好的代码: angularJS Feed Reader alt.

我的代码和它的代码有相似的地方,但仍有不同,因为我想要实现更多的功能。 FreedReadR 允许你本地存储自己的RSS源数据,这样你就可以一直使用应用来创建自定义的RSS源。 另外,它的代码基于Twitter Bootstrap 2,FreedReadR 基于新版本Twitter Bootstrap 3。
使用代码

如果你熟悉Angular,开发时代码并不多。 大部分的难点是在Angular中使用Bootstrap。

其它问题可以在”Angular编程思想”中找到解决方法。$scope 的用法和控制器工作的方式有点不同。 首先你必须在html中设置应用程序的作用域。 类似下面的使用ng-app="FreedReadR"的代码,设置了html中$scope的作用域:所有div标签内的对象 –- 在下面的示例中作用域是整个页面。 我只需要一个控制器来处理整个应用程序逻辑,我对这一点比较满意。

<body ng-app="FreedReadR">

<div data-ng-controller="FeedCtrl">
  <h4>RSS Feed Reader using AngularJS</h4>

<form class="form-horizontal col-md-12" role="form">
 <div class = "row">
  <div class="col-md-6">

在上面的html代码中,你可以看到Angular 应用模板的名称是FreedReadR。 当我设置应用程序模板、添加控制器(FeedCtrl) 代码时,我在main.js文件中使用了相同的名字。让我们看一下main.js中设置参数的代码。

var app = angular.module('FreedReadR', []);

app.factory('FeedService',function($http){
 return {
  parseFeed : function(url){
   return $http.jsonp('//ajax.googleapis.com/ajax/services/feed/load?v=1.0&num=50&callback=JSON_CALLBACK&q=' + encodeURIComponent(url));
  }
 }
});

app.controller("FeedCtrl", ['$scope','FeedService', FeedCtrl]);

在上面的js代码中,第一行是创建AngularJS 应用模板。 注意,它的名称是FreedReadR,我们在html代码中使用相同的名称以引用这个模板。

接下来,我们创建一个Angular工厂类,后面会用它访问RSS源URL来获取真实的源数据。 认真地看下代码中使用的 $http.jsonp请求。URL格式如下:

//ajax.googleapis.com/ajax/services/feed/load?v=1.0&num=50&callback=JSON_CALLBACK&q=

URL里调用了Google API,以前我并不知道Google API。这就是我在文章开头提到的jsfiddle示例的主要代码。 如果你想更多地了解Google API,你可以在这里下载:https://developers.google.com/feed/v1/jsondevguide。

在上面的js代码中,你会发现我们调用了encodeURIComponent 函数,它是用来转换URL的。
配置Angular 控制器

控制器用来处理应用程序的逻辑,因此大部分js函数应该在控制器内部。这就是Angular 帮助你组织(混乱的)js代码的方式。 我刚有大声说出来吗?

好吧,JavaScript鼓励杂乱无章,不是吗?这是它不好的地方.提到JavaScript的全局变量的时候,你不用带着恐惧尖声叫喊着说吗?如果不用,那么我们可能要撤销你的开发者许可证.你有编写软件的许可,不是吗?(译者注:因为你有开发者许可证,所以你自然也是带着恐惧尖声叫喊着说JavaScript的"全局变量"的--这里有些夸张的说法,意在说明开发者对于JavaScript的"全局变量"的使用应该有所顾忌.)

现在,在我们深入了解应用程序具体做了些什么的时候,看看控制器提供的功能.看看在控制器中的每个函数,以便了解FreedReadR可以做些什么.
检查localStorage, 存在则加载

我想做的一件事是,希望你在浏览器的slocalStorage中保存你的源.我不希望因为设置数据库而弄得一团糟,但我希望你可以增加自定义的源,并且让他们在你的浏览器中一直可用.
 
localStorage的限制

当然,localStorage的限制是,它存在于一个特定浏览器的给定域名.

这意味着,如果你从NewtonSaber.com/FreedReadR运行应用程序并保存一些自定义的源,当你从浏览器打开最初打开的连接的时候,你将会再次只看到列表中的这些内容.每个浏览器的localStorage都是私有的.所以,如果你某天使用IE增加了一些源,在接下来的一天将无法使用Chrome来查看已经添加的源.

对我来说,这个版本的应用程序已经OK了.因为它是我所希望的,用非常快速和了解其限制的技术开始.修正限制可能是以后另一篇文章的事情了.

你会发现在控制器代码中,我首先调用了一个函数:retrieveFromLocalStorage()。

函数如下:

function retrieveFromLocalStorage()
 {
  $scope.allFeeds = [];
  console.log("retrieving localStorage...");
  try
  {
  $scope.allFeeds = JSON.parse(localStorage["feeds"]);
  console.log($scope.allFeeds.length);

  // console.log(JSON.stringify($scope.allFeeds));
  if ($scope.allFeeds === null)
  {
   console.log("couldn't retrieve feeds" );
   loadDefaultFeeds();
  }
  }
  catch (ex)
  {
  console.log("ex: " + ex);
  loadDefaultFeeds();
  saveToLocalStorage($scope.allFeeds);
  }
 }

这是一个非常简单的函数。 它在 $scope的作用域内定义了一个名为 allFeeds的数组变量。 然后,通过 JSON.parse方法从localStorage数组中读取一个 feeds对象,这个对象保存的是已存在的 RSS源。如果这个 feeds对象为 undefined(这是首次运行应用程序),程序会抛出一个异常。 当异常被抛出时,应用程序会加载一些默认的 RSS源(loadDefaultFeeds()),然后将这些源保存到localStorage中供下次使用。

先看看loadDefaultFeeds()函数,然后我们再看saveToLocalStorage()函数.

function loadDefaultFeeds()
{
 $scope.allFeeds = [{titleText:"Load (from textbox)",url:""},
 {titleText:"CodeProject C#",url:"http://www.codeproject.com/webservices/articlerss.aspx?cat=3"}, {titleText:"ComputerWorld - News",url:"http://www.computerworld.com/index.rss"},
 {titleText:"Dr. Dobb's",url:"http://www.drdobbs.com/rss/all"},
 {titleText:"InfoWorld Today's News",url:"http://www.infoworld.com/news/feed"},
 {titleText:"Inc. Magazine",url:"http://www.inc.com/rss/homepage.xml"},
 {titleText:"TechCrunch",url:"http://feeds.feedburner.com/TechCrunch"},
 {titleText:"CNN",url:"http://rss.cnn.com/rss/cnn_topstories.rss"}
     ];
}

就像你所看到的,我增加了一些我最喜欢的源,这样,你就可以很容易的试用这个应用程序.它仅仅只是一个对象数组,通过titleText和url来定义.

只要它们都加载到$scope类型的变量allFeeds之中,你就可以使用ng-repeat从HTML获取它们了,它看起来像下面这样:

<li ng-repeat="feed in allFeeds">
 <a href="#" ng-click="loadFeed($event,feed.url);">{{feed.titleText}}</a>
</li>

这创建了选项的列表,当你点击下拉框按钮的时候,它们将会显示在上面.如你所看到的,我们在ng-repeat语句中引用了allFeeds $scope变量,然后我们引用了feed.titleText来生成入口.

现在你的按钮已经加载了很好的标题了。

我说过会给你介绍saveToLocalStorage()方法,现在让我们看一看。

function saveToLocalStorage(feeds)
 {
  // Put the object into storage

  localStorage.setItem('feeds', angular.toJson(feeds));
  console.log(angular.toJson(feeds));
  console.log("wrote feeds to localStorage");
 }

这是一个非常简单的方法。方法允许你传入  feeds 对象(这应该是一个feed对象数组)。然后我们简单地调用  localStorage.setItem( ) 方法。正如方法的名字所说,我们可以用该方法来保存对象。要注意的是,当我们保存对象的时候,我们会调用对象的  angular.toJson()  方法。这是个方法会帮助我们去除一些angular特有的属性,而这些属性是我们不想保存的。所以调用这个方法非常重要,因为angular会在对象中保存一些特有属性,这些属性会让你感到迷惑。

现在,应用程序已经加载了一些默认的RSS源,如果你想获取某一个RSS源的数据,点击下拉框按钮,选择其中一个值,然后应用程序会运行下面的代码来获取相关的数据。 我们在$scope作用域内添加一个loadFeed函数,函数如下。 下面的函数会被调用,因为我们在html中给按钮绑定了事件ng-click="loadFeed($event,feed.url);"。

loadFeed=function(e,url){
  $scope.currentButtonText = angular.element(e.target).text();
  // 清空过滤文本框中的上次展示的信息,
  // 当我们选择一个新的RSS源时,如果不清空会让人疑惑
  $scope.filterText = "";
  console.log("loadFeed / click event fired");

  if ($scope.currentButtonText == $scope.allFeeds[0].titleText)
  {
   //console.log($scope.feedSrc);
   url = $scope.feedSrc;
  }

  $scope.feedSrc = url;
  if (url === undefined || url === "")
  {
   $scope.phMessage = "Please enter a valid Feed URL & try again.";
   return;
  }
  console.log("button text: " + angular.element(e.target).text());
  console.log("value of url: " );
  console.log(url);
  FeedService.parseFeed(url).then(function(res){
   $scope.loadButonText=angular.element(e.target).text();
   $scope.feeds=res.data.responseData.feed.entries;
  });
 }

通过点击事件调用上面的函数时,我们先判断用户选择的信息与下拉框第一个选项 "Load (from textbox)"是否相同。 这么做是为了判断用户是否想加载文本框中提供的 RSS源。 如果是这样,我们调用FeedService.parseFeed  方法时,直接传入文本框中 URL值。如果不是这样,我们从相关的源对象中获取 URL。

结果列表

当源信息返回的时候,HTML代码使用另一个ng-repeat来迭代遍历每个项,并用友好的格式显示它们.HTML代码看起来像下面这样:

<ul class="unstyled">
 <span class="badge badge-warning top-buffer" ng-show="feeds.length > 0">{{(feeds | filter:filterText).length}} Items</span>
 <li ng-repeat="feed in feeds | filter:filterText">
  <h5><a href="{{feed.link}}" target="_blank"><span class="titleText" >{{feed.title}}</span></a><span class="small"> {{feed.publishedDate}}</span></h5>
  <p class="text-left">{{feed.contentSnippet}}</p>     

 </li>
</ul>

HTML也创建了一个好友的标记,用来显示获取到的文本链接数.
搜索结果里的内容

它也显示了一个搜索文本框,可以用来输入文字,根据文本链接的内容来过滤下拉列表.
点击链接: 在新的页面加载

最后,如果你点击一个链接,它会在浏览器的新页面或窗口加载.这让这个工具很容易使用.

保存新的源

这个部分我做的很简单,因为我完成这个应用程序只是为了我自己使用.

如果你在文本框中输入一个URL,然后点击保存按钮(向下的箭头图标),你将看到一个JavaScript提示框,它看起来像下面展示的图片这样:

你可以简单的输入标题(它将显示在下拉列表中)用来标识新的源,然后点击OK按钮.

只要你这么做了,这个项就会增加到下拉列表.这个过程通过增加这个项到allFeeds对象来实现,同时,这个项也将立即保存到localStorage之中.

这就是所有的内容.

希望你和我一样喜欢这个工具,它节省了很多时间.

发布提示

请注意许多外部库的链接是CDN的,除了下载的Bootstrap文件,其他下载的文件在一个3rdPartyLibs(第三方库)的目录里。你可以下载代码,解压和运行它们。
为本地存储准备Web服务器是必需的

你必须运行一个web服务器使它正常工作。注意,在下载的文件中已经包含一个精致小巧的web服务器(mongoose web server)和配置文件,因此,如果你希望使用它,你可以双击mongoose.exe,它就开始运行了,之后,你可以简单地加载: http://localhost:999/FreedReadR/ 它就从你的电脑上运行了。
 
最后一个要注意的是:那个【X】按钮是什么?

保存按钮后面的那个[X]按钮是什么?那个按钮允许你释放所有来自你的localStorage的反馈。如果你点击它,它们会被移除。被命名为反馈的localstorage条目就这样简单地被销毁了,所以要小心处理。如果你在添加任何反馈之前使用这个按钮,没有任何问题,否则你将会失去你已经添加的反馈。

我很懒,我使用它仅仅是为了我的测试,你还是应该把它去掉的。懒惰还真是一个伟大开发者的标志啊。

(0)

相关推荐

  • 基于AngularJS实现页面滚动到底自动加载数据的功能

    要实现这个功能,可以通过 https://github.com/sroze/ngInfiniteScroll 这个第三方控件来实现.步骤如下: 1. 下载ng-infinite-scroll.js程序 http://sroze.github.io/ngInfiniteScroll/ 目前版本是1.0.0 2. 如果你是用的jQuery2.0以上版本,还需要修改ng-infinite-scroll.js程序,将所有的将所有的$window.xxx改为$(window).xxx, elem.xxx改

  • AngularJS入门教程之Cookies读写操作示例

    本文实例讲述了AngularJS的Cookies读写操作.分享给大家供大家参考,具体如下: 虽然使用JavaScript创建和获取Cookie很简单,AngularJS还是把它作为一个单独的模块进行了封装,模块名为ngCookies,和前面的教程中做法一样,先引入angular-cookies.js: <script type="text/javascript" src="angular-1.3.0.14/angular-cookies.js"><

  • Angularjs根据json文件动态生成路由状态的实现方法

    项目上有一个新需求,就是需要根据json文件动态生成路由状态,查阅了一下资料,现在总结一下发出来: 首先项目用到的是angular的UI-路由,所以必须引入angular.js和angular-ui-router.js两个js文件,如下例子: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Example</title> <script

  • Angularjs实现多个页面共享数据的方式

    废话不多说了,直接看干货吧. 使用service来共享数据 定义一个共享服务的service //家电维修共享数据的服务 angular.module("sqhApp").factory("repairDeviceDataShareServer",function($http,$state,$ionicPopup){ return { //缓存当前需要维修的设备名称.数量.唯一标识 deviceRepairObj : [], //小区位置 xiquLocation:

  • AngularJS中的JSONP实例解析

    概念 首先呢,Json和JSONP是不一样的哦.Json呢,是众多数据存储的其中一种格式,是数据书写方式的其中一种.好比是大中华众多诗体的一种(比如说是七言诗吧).这种诗体规定了: 这种诗体要包含题目,每行诗句的字数(7个字) 等等的文本格式.而Json所规定的文本格式是这样子的 (Json格式示意图)   而JSONP呢,它是一种特殊的通讯方式,使用它能够轻松绕过浏览器的同源安全限制,达到加载来自不同源的资源(脚本, 图片, 其他)的效果.比如说,您是一个王国的王子,你意外地喜欢上了附近一个小

  • angularjs学习笔记之双向数据绑定

    这次我们来详细讲解angular的双向数据绑定. 一.简单的例子 这个例子我们在第一节已经展示过了,要看的移步这里 这里实现的效果就是,在输入框输入内容,下面也会相应的改变对应的内容.这就实现了数据双向绑定. 二.取值表达式与ng-bind的使用 我们再看一个例子,点击这里,文中出现的第一个例子中,{{greeting.text}}和{{text}}就是一个取值表达式了,但是如果你一直刷新页面,你会发现这样一个问题,那就是页面有时候会一瞬间的出现"{{greeting.text}} {{text

  • angularJS 如何读写缓冲的方法(推荐)

    写在前面 1.在客户端.服务端架构中,HTTP协议是主流通信技术: 2.HTTP协议的无状态特性,节省带宽,较少服务器的负载,缓冲技术具有重要的运用:这里主要讲解在客户端浏览器中angular如何读写缓存... 如何实现 1.angular提供了ngCookies模块来实现读写缓存的操作,基于angular的注入该服务就能很容易的操作缓存了,但是本人推荐你使用该方法实现(重构了angular-cookie) /** * Description : 缓冲服务 * Author :maikec *

  • AngularJS实现数据列表的增加、删除和上移下移等功能实例

    效果图 实例代码 <!DOCTYPE html> <html lang="en" ng-app="myapp" ng-controller="myCtrl"> <head> <meta charset="UTF-8"> <title>Title</title> <style> *{margin:0;padding:0; list-style:

  • AngularJS入门教程之 XMLHttpRequest实例讲解

    AngularJS XMLHttpRequest $http 是 AngularJS 中的一个核心服务,用于读取远程服务器的数据. 读取 JSON 文件 以下是存储在web服务器上的 JSON 文件: http://www.runoob.com/try/angularjs/data/Customers_JSON.php { "records": [ { "Name" : "Alfreds Futterkiste", "City"

  • AngularJS读取JSON及XML文件的方法示例

    本文实例讲述了AngularJS读取JSON及XML文件的方法.分享给大家供大家参考,具体如下: <!doctype html> <meta charset="UTF-8"> <html ng-app='routingDemoApp'> <head> <title>AJAX and promise</title> <link href="bootstrap.min.css" rel=&qu

  • 使用AngularJS 跨站请求如何解决jsonp请求问题

    今天写东西的时候遇到了 一种情况 ,因为用的不是自己公司人员写的接口 ,而我要写的东西是抓别的网页上的接口 所以出现了 一下这种情况 用 get请求出现拦截跨站请求资源  以下是解决办法, 这是我的请求: 我在浏览器模板赋值的时候发现赋值没有成功, 在浏览器控制台打印出来的如下: 大概的意思是没有请求头,然后在网上看了一些, 楼主英语不好 我也解释不清楚 ,所以读客有时候不要较真!!! 毕竟能解决问题就是可以的. 解决这个bug的办法  , url 后面要拼接要加上 callback=JSON_

  • 三种AngularJS中获取数据源的方式

    在AngularJS中,可以从$rootScope中获取数据源,也可以把获取数据的逻辑封装在service中,然后注入到app.run函数中,或者注入到controller中.本篇就来整理获取数据的几种方式. ■ 数据源放在$rootScope中 var app = angular.module("app",[]); app.run(function($rootScope){ $rootScope.todos = [ {item:"",done:true}, {it

随机推荐