美文网首页React Native高手进阶Hybrid开发github
【React Native实战教程】GitHub Trendin

【React Native实战教程】GitHub Trendin

作者: CrazyCodeBoy | 来源:发表于2016-10-26 20:05 被阅读8427次

    项目开源地址:GitHub PopularGitHubTrending

    React Native实战教程】GitHub Trending API数据的获取.png

    关于GitHub Trending API的困惑

    GitHub Popular中有个treding模块,该模块是GitHub的treding的手机版,在这个模块中你可以使用只有在PC上才能使用的功能。为了开发这个treding模块我们需要获取GitHub的treding的API数据。不过不幸的的是GitHub并没有开放有关trending的API,所以想调GitHub的treding的API已经是不现实的了。

    github.com_trending.pnggithub.com_trending.png

    拨开云雾见月明

    为了给GitHub Populartreding模块提供可靠的数据支持,我查遍了所有看似可行的方法,但都没能达到要求。本着只要思想不滑坡,方法总比问题多态度,我打开了https://github.com/trending的页面源码研究了起来。

    github.com_trending-github_populargithub.com_trending-github_popular

    在源码中我发现了能够满足GitHub Populartreding模块的所有数据,但存在如下两个问题:

    1. 冗余的数据太多,我们需要从这些冗余的数据中提取出treding模块真正需要的数据。
    2. 这些数据都是HTML格式的,而我们需要的是Json格式的数据。

    GitHubTrending项目的开发

    经过上述的分析,我们的需求与任务也逐渐明确了,我们需要一个能为我们提供可靠的https://github.com/trending数据的模块,暂且叫它GitHubTrending吧。这个模块需要满足如下需求:

    1. 接受一个url参数,如:https://github.com/trending/
    2. 能够根据url参数返回对应的json或object数据。

    为了实现这一需求,我们需要对请求url返回的数据进行解析,提取出我们所需要的数据,下面就跟大家分享GitHubTrending的具体实现:

    数据模型TrendingRepoModel

    我们需要让GitHubTrending返回一个包含TrendingRepoModel.js的集合,TrendingRepoModel.js的代码如下:

    /**
     * TrendingRepoModel
     * 项目地址:https://github.com/crazycodeboy/GitHubTrending
     * 博客地址:http://www.devio.org
     * @flow
     */
    
    export default class TrendingRepoModel {
      constructor(fullName,url,description,language,meta,contributors,contributorsUrl) {
        this.fullName = fullName;
        this.url = url;
        this.description = description;
        this.language = language;
        this.meta = meta;
        this.contributors = contributors;
        this.contributorsUrl = contributorsUrl;
      }
    }
    
    

    从上面代码中可以看出,TrendingRepoModel.js包含了https://github.com/trending/的所以数据的模型。

    将HTML解析成TrendingRepoModel

    我们通过TrendingUtil.js将HTML解析成包含TrendingRepoModel.js的集合。下面是TrendingUtil.js文件代码:

    /**
     * TrendingUtil
     * 工具类:用于将github trending html 转换成 TrendingRepoModel
     * 项目地址:https://github.com/crazycodeboy/GitHubTrending
     * 博客地址:http://www.devio.org
     * @flow
     */
    
    import TrendingRepoModel from './TrendingRepoModel';
    import StringUtil from './StringUtil';
    
    export default class TrendingUtil {
        static htmlToRepo(responseData) {
            responseData = responseData.substring(responseData.indexOf('<li class="repo-list-item'), responseData.indexOf('</ol>')).replace(/\n/, '');
            var repos = [];
            var splitWithH3 = responseData.split('<h3');
            splitWithH3.shift();
            for (var i = 0; i < splitWithH3.length; i++) {
                var repo = new TrendingRepoModel();
                var html = splitWithH3[i];
    
                this.parseRepoBaseInfo(repo, html);
    
                var metaNoteContent = this.parseContentOfNode(html, 'repo-list-meta');
                this.parseRepoMeta(repo, metaNoteContent);
                this.parseRepoContributors(repo, metaNoteContent);
                repos.push(repo);
            }
            return repos;
        }
    
        static parseContentOfNode(htmlStr, classFlag) {
            var noteEnd = htmlStr.indexOf(' class="' + classFlag);
            var noteStart = htmlStr.lastIndexOf('<', noteEnd) + 1;
            var note = htmlStr.substring(noteStart, noteEnd);
    
            var sliceStart = htmlStr.indexOf(classFlag) + classFlag.length + 2;
            var sliceEnd = htmlStr.indexOf('</' + note + '>', sliceStart);
            var content = htmlStr.substring(sliceStart, sliceEnd);
            return StringUtil.trim(content);
        }
    
        static parseRepoBaseInfo(repo, htmlBaseInfo) {
            var urlIndex = htmlBaseInfo.indexOf('<a href="') + '<a href="'.length;
            var url = htmlBaseInfo.slice(urlIndex, htmlBaseInfo.indexOf('">', urlIndex));
            repo.url = url;
            repo.fullName = url.slice(1, url.length);
    
            var description = this.parseContentOfNode(htmlBaseInfo, 'repo-list-description');
            var index = description.indexOf('</g-emoji>');
            if (index !== -1) {
                var indexEmoji = description.indexOf('</g-emoji>');
                var emoji = description.substring(description.indexOf('>') + 1, indexEmoji)
                description = emoji + description.substring(indexEmoji + '</g-emoji>'.length);
            }
            repo.description = description;
        }
    
        static parseRepoMeta(repo, htmlMeta) {
            var splitWit_n = htmlMeta.split('\n');
            if (splitWit_n[0].search('stars') === -1) {
                repo.language = splitWit_n[0];
            }
            for (var i = 0; i < splitWit_n.length; i++) {
                if (splitWit_n[i].search('stars') !== -1) {
                    repo.meta = StringUtil.trim(splitWit_n[i]);
                    break;
                }
            }
        }
    
        static parseRepoContributors(repo, htmlContributors) {
            var splitWitSemicolon = htmlContributors.split('"');
            repo.contributorsUrl = splitWitSemicolon[1];
            var contributors = [];
            for (var i = 0; i < splitWitSemicolon.length; i++) {
                var url = splitWitSemicolon[i];
                if (url.search('http') !== -1) {
                    contributors.push(url);
                }
            }
            repo.contributors = contributors;
        }
    }
    
    

    上面代码将HTML解析成一个包含TrendingRepoModel.js的集合,为了去除空行,上述代码中用到了StringUtil.js工具类:

    /**
     * 字符串工具类
     * 项目地址:https://github.com/crazycodeboy/GitHubTrending
     * 博客地址:http://www.devio.org
     * @flow
     */
    export default class StringUtil {
      /*
      * 去掉字符串左右空格、换行
      */
      static trim( text ){
        if (typeof(text) == "string")  {
          return text.replace(/^\s*|\s*$/g, "");
        }
        else{
          return text;
        }
      }
    }
    
    

    上述代码用于去除字符串中左右空格与换行。

    GitHubTrending封装

    经过上述步骤之后,我们的准备工作已经完成了,下面我们就可以通过GitHubTrending来提供数据了:

    /**
     * 从https://github.com/trending获取数据
     * 项目地址:https://github.com/crazycodeboy/GitHubTrending
     * 博客地址:http://www.devio.org
     * @flow
     */
    import TrendingUtil from './TrendingUtil';
    
    export default class GitHubTrending {
      GitHubTrending(){//Singleton pattern
        if (typeof GitHubTrending.instance==='object') {
          return GitHubTrending.instance;
        }
        GitHubTrending.instance=this;
      }
      fetchTrending(url){
        return new Promise((resolve,reject)=>{
          fetch(url)
          .then((response)=>response.text())
          .catch((error)=>{
            reject(error);
            console.log(error);
          }).then((responseData)=>{
            try {
              resolve(TrendingUtil.htmlToRepo(responseData));
            } catch (e) {
              reject(e);
            }
          }).done();
        });
      }
    }
    
    

    上述代码接受一个url,然后通过fetchAPI获取url返回的HTML数据,最后将HTML解析成包含TrendingRepoModel.js的集合。

    如何使用GitHubTrending

    为了方面大家使用,我已将GitHubTrending发布到npm,大家可以通过下列步骤来使用GitHubTrending

    安装

    打开在终端中运行如下命名进行安装:

    npm i GitHubTrending --save
    

    使用

    new GitHubTrending().fetchTrending(url)
        .then((data)=> {
            //
        }).catch((error)=> {
            //
    });
    

    更多用例可参考:GitHubPopular:DataRepository.js

    总结

    从探索使用官方API,到自己动手去实现它,虽然过程比较曲折,但最终还是完成目标。经过反复测试GitHubTrending
    现在已经满足了GitHub Popular项目的需求,而且稳定性还是不错的,感兴趣的小伙伴可以下载GitHub Popular
    体验一下。

    相关文章

      网友评论

        本文标题:【React Native实战教程】GitHub Trendin

        本文链接:https://www.haomeiwen.com/subject/ovcjuttx.html